Skip to content

Surface: correct scroll-event semantics (scrolling was far too fast)#9

Merged
arach merged 1 commit into
arach:mainfrom
robgough:fix/scroll-event-semantics
Jul 12, 2026
Merged

Surface: correct scroll-event semantics (scrolling was far too fast)#9
arach merged 1 commit into
arach:mainfrom
robgough:fix/scroll-event-semantics

Conversation

@robgough

@robgough robgough commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Another one from running Termini in Belfry (see #3, #8): scrolling in the macOS surface is drastically too fast, because scrollWheel passes the wrong thing in ghostty_surface_mouse_scroll's flags argument.

The bug. That argument is a scroll-mods bitmask — bit 0 is the precision flag, bits 1–3 the momentum phase (src/input/mouse.zig in ghostty) — but scrollWheel passes the keyboard modifier bitmask and never sets precision. Two consequences:

  • Trackpad deltas (scrollingDeltaX/Y with hasPreciseScrollingDeltas) are pixel values, but without the precision bit ghostty interprets them as discrete wheel ticks and multiplies each by the cell height — so one pixel of finger travel scrolls a whole line, roughly cell-height× too fast (~30× at typical font sizes).
  • Keyboard modifiers land in the wrong bits: shift (bit 0) flips the precision flag, so holding shift while scrolling randomly changes scroll speed; ctrl/alt/super corrupt the momentum phase.

The fix mirrors ghostty's own SurfaceView_AppKit.swift scrollWheel: hasPreciseScrollingDeltas sets the precision flag and deltas pass as pixels (with the same 2× feel multiplier ghostty uses), discrete wheel ticks pass through unscaled, and NSEvent.momentumPhase is mapped onto ghostty_input_mouse_momentum_e so inertial flick-scrolling decays properly instead of replaying raw deltas.

The iOS surface's pan-gesture path already sets the precision bit correctly and is untouched.

Verified by feel in Belfry (trackpad, mouse wheel, and momentum flicks) against Ghostty.app as the reference; swift build clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RHWv6ccUfu4nK3yiGB4ocZ

ghostty_surface_mouse_scroll's last argument is a scroll-mods bitmask
(bit 0 = precision, bits 1-3 = momentum phase; ghostty
src/input/mouse.zig), but scrollWheel passed the keyboard-modifier
bitmask and never set precision. Ghostty therefore treated trackpad
pixel deltas as discrete wheel ticks and multiplied each by the cell
height -- one line per pixel of finger travel, ~30x too fast -- and
holding shift while scrolling happened to flip the precision bit.

Mirror ghostty's own AppKit surface view: hasPreciseScrollingDeltas
sets the precision flag (deltas are pixels, with ghostty's 2x feel
multiplier), discrete wheel ticks pass through unscaled, and
momentumPhase is forwarded so inertial scrolling decays properly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RHWv6ccUfu4nK3yiGB4ocZ
@arach
arach merged commit 0c5edbd into arach:main Jul 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants