mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
core: mouse pressure state and callbacks
This commit is contained in:
@ -535,6 +535,7 @@ void ghostty_surface_mouse_scroll(ghostty_surface_t,
|
|||||||
double,
|
double,
|
||||||
double,
|
double,
|
||||||
ghostty_input_scroll_mods_t);
|
ghostty_input_scroll_mods_t);
|
||||||
|
void ghostty_surface_mouse_pressure(ghostty_surface_t, uint32_t, double);
|
||||||
void ghostty_surface_ime_point(ghostty_surface_t, double*, double*);
|
void ghostty_surface_ime_point(ghostty_surface_t, double*, double*);
|
||||||
void ghostty_surface_request_close(ghostty_surface_t);
|
void ghostty_surface_request_close(ghostty_surface_t);
|
||||||
void ghostty_surface_split(ghostty_surface_t, ghostty_split_direction_e);
|
void ghostty_surface_split(ghostty_surface_t, ghostty_split_direction_e);
|
||||||
|
@ -578,6 +578,13 @@ extension Ghostty {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override func pressureChange(with event: NSEvent) {
|
override func pressureChange(with event: NSEvent) {
|
||||||
|
guard let surface = self.surface else { return }
|
||||||
|
|
||||||
|
// Notify Ghostty first. We do this because this will let Ghostty handle
|
||||||
|
// state setup that we'll need for later pressure handling (such as
|
||||||
|
// QuickLook)
|
||||||
|
ghostty_surface_mouse_pressure(surface, UInt32(event.stage), Double(event.pressure))
|
||||||
|
|
||||||
// Pressure stage 2 is force click. We only want to execute this on the
|
// Pressure stage 2 is force click. We only want to execute this on the
|
||||||
// initial transition to stage 2, and not for any repeated events.
|
// initial transition to stage 2, and not for any repeated events.
|
||||||
guard self.prevPressureStage < 2 else { return }
|
guard self.prevPressureStage < 2 else { return }
|
||||||
|
@ -173,6 +173,10 @@ const Mouse = struct {
|
|||||||
/// The last x/y sent for mouse reports.
|
/// The last x/y sent for mouse reports.
|
||||||
event_point: ?terminal.point.Coordinate = null,
|
event_point: ?terminal.point.Coordinate = null,
|
||||||
|
|
||||||
|
/// The pressure stage for the mouse. This should always be none if
|
||||||
|
/// the mouse is not pressed.
|
||||||
|
pressure_stage: input.MousePressureStage = .none,
|
||||||
|
|
||||||
/// Pending scroll amounts for high-precision scrolls
|
/// Pending scroll amounts for high-precision scrolls
|
||||||
pending_scroll_x: f64 = 0,
|
pending_scroll_x: f64 = 0,
|
||||||
pending_scroll_y: f64 = 0,
|
pending_scroll_y: f64 = 0,
|
||||||
@ -2492,6 +2496,41 @@ fn processLinks(self: *Surface, pos: apprt.CursorPos) !bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mousePressureCallback(
|
||||||
|
self: *Surface,
|
||||||
|
stage: input.MousePressureStage,
|
||||||
|
pressure: f64,
|
||||||
|
) !void {
|
||||||
|
// We don't currently use the pressure value for anything. In the
|
||||||
|
// future, we could report this to applications using new mouse
|
||||||
|
// events or utilize it for some custom UI.
|
||||||
|
_ = pressure;
|
||||||
|
|
||||||
|
// If the pressure stage is the same as what we already have do nothing
|
||||||
|
if (self.mouse.pressure_stage == stage) return;
|
||||||
|
|
||||||
|
// Update our pressure stage.
|
||||||
|
self.mouse.pressure_stage = stage;
|
||||||
|
|
||||||
|
// If our left mouse button is pressed and we're entering a deep
|
||||||
|
// click then we want to start a selection. We treat this as a
|
||||||
|
// word selection since that is typical macOS behavior.
|
||||||
|
const left_idx = @intFromEnum(input.MouseButton.left);
|
||||||
|
if (self.mouse.click_state[left_idx] == .press and
|
||||||
|
stage == .deep)
|
||||||
|
select: {
|
||||||
|
self.renderer_state.mutex.lock();
|
||||||
|
defer self.renderer_state.mutex.unlock();
|
||||||
|
|
||||||
|
// This should always be set in this state but we don't want
|
||||||
|
// to handle state inconsistency here.
|
||||||
|
const pin = self.mouse.left_click_pin orelse break :select;
|
||||||
|
const sel = self.io.terminal.screen.selectWord(pin.*) orelse break :select;
|
||||||
|
try self.setSelection(sel);
|
||||||
|
try self.queueRender();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn cursorPosCallback(
|
pub fn cursorPosCallback(
|
||||||
self: *Surface,
|
self: *Surface,
|
||||||
pos: apprt.CursorPos,
|
pos: apprt.CursorPos,
|
||||||
|
@ -716,6 +716,17 @@ pub const Surface = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mousePressureCallback(
|
||||||
|
self: *Surface,
|
||||||
|
stage: input.MousePressureStage,
|
||||||
|
pressure: f64,
|
||||||
|
) void {
|
||||||
|
self.core_surface.mousePressureCallback(stage, pressure) catch |err| {
|
||||||
|
log.err("error in mouse pressure callback err={}", .{err});
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn scrollCallback(
|
pub fn scrollCallback(
|
||||||
self: *Surface,
|
self: *Surface,
|
||||||
xoff: f64,
|
xoff: f64,
|
||||||
@ -1648,6 +1659,25 @@ pub const CAPI = struct {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export fn ghostty_surface_mouse_pressure(
|
||||||
|
surface: *Surface,
|
||||||
|
stage_raw: u32,
|
||||||
|
pressure: f64,
|
||||||
|
) void {
|
||||||
|
const stage = std.meta.intToEnum(
|
||||||
|
input.MousePressureStage,
|
||||||
|
stage_raw,
|
||||||
|
) catch {
|
||||||
|
log.warn(
|
||||||
|
"invalid mouse pressure stage value={}",
|
||||||
|
.{stage_raw},
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
surface.mousePressureCallback(stage, pressure);
|
||||||
|
}
|
||||||
|
|
||||||
export fn ghostty_surface_ime_point(surface: *Surface, x: *f64, y: *f64) void {
|
export fn ghostty_surface_ime_point(surface: *Surface, x: *f64, y: *f64) void {
|
||||||
const pos = surface.core_surface.imePoint();
|
const pos = surface.core_surface.imePoint();
|
||||||
x.* = pos.x;
|
x.* = pos.x;
|
||||||
|
@ -63,6 +63,22 @@ pub const MouseMomentum = enum(u3) {
|
|||||||
may_begin = 6,
|
may_begin = 6,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// The pressure stage of a pressure-sensitive input device.
|
||||||
|
///
|
||||||
|
/// This currently only supports the stages that macOS supports.
|
||||||
|
pub const MousePressureStage = enum(u2) {
|
||||||
|
/// The input device is unpressed.
|
||||||
|
none = 0,
|
||||||
|
|
||||||
|
/// The input device is pressed a normal amount. On macOS trackpads,
|
||||||
|
/// this is after a "click".
|
||||||
|
normal = 1,
|
||||||
|
|
||||||
|
/// The input device is pressed a deep amount. On macOS trackpads,
|
||||||
|
/// this is after a "force click".
|
||||||
|
deep = 2,
|
||||||
|
};
|
||||||
|
|
||||||
/// The bitmask for mods for scroll events.
|
/// The bitmask for mods for scroll events.
|
||||||
pub const ScrollMods = packed struct(u8) {
|
pub const ScrollMods = packed struct(u8) {
|
||||||
/// True if this is a high-precision scroll event. For example, Apple
|
/// True if this is a high-precision scroll event. For example, Apple
|
||||||
|
Reference in New Issue
Block a user