diff --git a/include/ghostty.h b/include/ghostty.h index 77259202a..163044c1b 100644 --- a/include/ghostty.h +++ b/include/ghostty.h @@ -55,6 +55,21 @@ typedef enum { GHOSTTY_MOUSE_MIDDLE, } ghostty_input_mouse_button_e; +typedef enum { + GHOSTTY_MOUSE_MOMENTUM_NONE, + GHOSTTY_MOUSE_MOMENTUM_BEGAN, + GHOSTTY_MOUSE_MOMENTUM_STATIONARY, + GHOSTTY_MOUSE_MOMENTUM_CHANGED, + GHOSTTY_MOUSE_MOMENTUM_ENDED, + GHOSTTY_MOUSE_MOMENTUM_CANCELLED, + GHOSTTY_MOUSE_MOMENTUM_MAY_BEGIN, +} ghostty_input_mouse_momentum_e; + +// This is a packed struct (see src/input/mouse.zig) but the C standard +// afaik doesn't let us reliably define packed structs so we build it up +// from scratch. +typedef int ghostty_input_scroll_mods_t; + typedef enum { GHOSTTY_MODS_NONE = 0, GHOSTTY_MODS_SHIFT = 1 << 0, @@ -265,7 +280,7 @@ void ghostty_surface_key(ghostty_surface_t, ghostty_input_action_e, ghostty_inpu void ghostty_surface_char(ghostty_surface_t, uint32_t); void ghostty_surface_mouse_button(ghostty_surface_t, ghostty_input_mouse_state_e, ghostty_input_mouse_button_e, ghostty_input_mods_e); void ghostty_surface_mouse_pos(ghostty_surface_t, double, double); -void ghostty_surface_mouse_scroll(ghostty_surface_t, double, double); +void ghostty_surface_mouse_scroll(ghostty_surface_t, double, double, ghostty_input_scroll_mods_t); 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); diff --git a/macos/Sources/Ghostty/SurfaceView.swift b/macos/Sources/Ghostty/SurfaceView.swift index 1655eb849..1d48c1597 100644 --- a/macos/Sources/Ghostty/SurfaceView.swift +++ b/macos/Sources/Ghostty/SurfaceView.swift @@ -298,7 +298,7 @@ extension Ghostty { y *= 0.1 } - ghostty_surface_mouse_scroll(surface, x, y) + ghostty_surface_mouse_scroll(surface, x, y, 0) } override func keyDown(with event: NSEvent) { diff --git a/src/apprt/embedded.zig b/src/apprt/embedded.zig index 36e7d3e77..cc171b3b0 100644 --- a/src/apprt/embedded.zig +++ b/src/apprt/embedded.zig @@ -502,7 +502,13 @@ pub const CAPI = struct { surface.cursorPosCallback(x, y); } - export fn ghostty_surface_mouse_scroll(surface: *Surface, x: f64, y: f64) void { + export fn ghostty_surface_mouse_scroll( + surface: *Surface, + x: f64, + y: f64, + scroll_mods: c_int, + ) void { + _ = scroll_mods; surface.scrollCallback(x, y); } diff --git a/src/input/mouse.zig b/src/input/mouse.zig index 224abef35..2073cbb18 100644 --- a/src/input/mouse.zig +++ b/src/input/mouse.zig @@ -1,3 +1,5 @@ +const std = @import("std"); + /// The state of a mouse button. /// /// This is backed by a c_int so we can use this as-is for our embedding API. @@ -45,3 +47,42 @@ pub const MouseButton = enum(c_int) { ten = 10, eleven = 11, }; + +/// The "momentum" of a mouse scroll event. This matches the macOS events +/// because it is the only reliable source right now of momentum events. +/// This is used to handle "intertial scrolling" (i.e. flicking). +/// +/// https://developer.apple.com/documentation/appkit/nseventphase +pub const MouseMomentum = enum(u3) { + none = 0, + began = 1, + stationary = 2, + changed = 3, + ended = 4, + cancelled = 5, + may_begin = 6, +}; + +/// 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 + /// devices such as Magic Mouse, trackpads, etc. are high-precision + /// and send very detailed scroll events. + precision: bool = false, + + /// The momentum phase (if available, supported) of the scroll event. + /// This is used to handle "intertial scrolling" (i.e. flicking). + momentum: MouseMomentum = .none, + + _padding: u4 = 0, + + // For our own understanding + test { + const testing = std.testing; + try testing.expectEqual(@bitCast(u8, ScrollMods{}), @as(u8, 0b0)); + try testing.expectEqual( + @bitCast(u8, ScrollMods{ .precision = true }), + @as(u8, 0b0000_0001), + ); + } +};