core: mouse pressure state and callbacks

This commit is contained in:
Mitchell Hashimoto
2024-06-12 06:39:17 -04:00
parent c165cef0a6
commit 6faeb9ba40
5 changed files with 93 additions and 0 deletions

View File

@ -535,6 +535,7 @@ void ghostty_surface_mouse_scroll(ghostty_surface_t,
double,
double,
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_request_close(ghostty_surface_t);
void ghostty_surface_split(ghostty_surface_t, ghostty_split_direction_e);

View File

@ -578,6 +578,13 @@ extension Ghostty {
}
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
// initial transition to stage 2, and not for any repeated events.
guard self.prevPressureStage < 2 else { return }

View File

@ -173,6 +173,10 @@ const Mouse = struct {
/// The last x/y sent for mouse reports.
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_x: f64 = 0,
pending_scroll_y: f64 = 0,
@ -2492,6 +2496,41 @@ fn processLinks(self: *Surface, pos: apprt.CursorPos) !bool {
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(
self: *Surface,
pos: apprt.CursorPos,

View File

@ -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(
self: *Surface,
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 {
const pos = surface.core_surface.imePoint();
x.* = pos.x;

View File

@ -63,6 +63,22 @@ pub const MouseMomentum = enum(u3) {
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.
pub const ScrollMods = packed struct(u8) {
/// True if this is a high-precision scroll event. For example, Apple