From 34388ab5df393ef1b9e7b5a0a5f4097565634c76 Mon Sep 17 00:00:00 2001 From: Tim Culverhouse Date: Sun, 2 Mar 2025 07:14:29 -0600 Subject: [PATCH] surface: calculate scroll amount directly from yoff/xoff for non-precision scrolls Calculate the scroll amount for non-precision scrolls as a direct multiple of yoff. This fixes an issue where Ghostty sends scroll wheel events (or arrow keys if in alternate scroll mode) that are variable, dependent on the screen size. I checked multiple terminals, and each responds to a single wheel click by sending only a single wheel / arrow key - independent of screen size. ```sh printf "\x1b[?1049h" printf "\x1b[?1007h" cat -v ``` Using the above procedure, with varying screen sizes: ``` # 50% Screen height | terminal | arrows keys sent| wheels events sent| |------------|-----------------|-------------------| | alacritty | 3 | 1 | | foot | 3 | 1 | | xterm | 5 | 1 | | kitty | 3 | 1 | | ghostty | 2 | 2 | # 100% Screen height | terminal | arrows keys sent| wheels events sent| |------------|-----------------|-------------------| | alacritty | 3 | 1 | | foot | 3 | 1 | | xterm | 5 | 1 | | kitty | 5 | 1 | | ghostty | 3 | 3 | ``` Both ghostty and kitty scale the number of arrow keys sent in proportion to the screen size. However, when mouse reporting is on, only ghostty does this. This commit makes Ghostty behave like foot, and more generally removes the dependence on screen size. --- src/Surface.zig | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/src/Surface.zig b/src/Surface.zig index 6651dd8c2..d64b32eb5 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -2348,22 +2348,12 @@ pub fn scrollCallback( if (self.mouse.hidden) self.showMouse(); const y: ScrollAmount = if (yoff == 0) .{} else y: { - // Non-precision scrolling is easy to calculate. We don't use - // the given offset at all and instead just treat a positive - // as a scroll up and a negative as a scroll down and scroll in - // steps. + // Non-precision scrolls don't accumulate. We cast that raw yoff to an isize and interpret + // it as the number of lines to scroll. if (!scroll_mods.precision) { - // Calculate our magnitude of scroll. This is constant (not - // dependent on yoff). - const grid_size = self.size.grid(); - const grid_rows_f64: f64 = @floatFromInt(grid_size.rows); - const y_delta_f64: f64 = @round((grid_rows_f64 * self.config.mouse_scroll_multiplier) / 15.0); - const y_delta_usize: usize = @max(1, @as(usize, @intFromFloat(y_delta_f64))); - - // Calculate our direction of scroll based on the sign of yoff. - const y_sign: isize = if (yoff >= 0) 1 else -1; - const y_delta_isize: isize = y_sign * @as(isize, @intCast(y_delta_usize)); - + // Calculate our magnitude of scroll. This is a direct multiple of yoff + const y_delta_f64: f64 = @round(yoff * self.config.mouse_scroll_multiplier); + const y_delta_isize: isize = @intFromFloat(y_delta_f64); break :y .{ .delta = y_delta_isize }; } @@ -2404,10 +2394,8 @@ pub fn scrollCallback( // For detailed comments see the y calculation above. const x: ScrollAmount = if (xoff == 0) .{} else x: { if (!scroll_mods.precision) { - const x_delta_f64: f64 = @round(1 * self.config.mouse_scroll_multiplier); - const x_delta_usize: usize = @max(1, @as(usize, @intFromFloat(x_delta_f64))); - const x_sign: isize = if (xoff >= 0) 1 else -1; - const x_delta_isize: isize = x_sign * @as(isize, @intCast(x_delta_usize)); + const x_delta_f64: f64 = @round(xoff * self.config.mouse_scroll_multiplier); + const x_delta_isize: isize = @intFromFloat(x_delta_f64); break :x .{ .delta = x_delta_isize }; }