Skip to content

fix(terminal): scroll alt-screen apps with wheel/touchpad; respect Select-to-Copy (#50)#53

Merged
kipavy merged 2 commits into
devfrom
fix-terminal-altscroll-selectcopy-50
Jul 24, 2026
Merged

fix(terminal): scroll alt-screen apps with wheel/touchpad; respect Select-to-Copy (#50)#53
kipavy merged 2 commits into
devfrom
fix-terminal-altscroll-selectcopy-50

Conversation

@kipavy

@kipavy kipavy commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Fixes the two terminal issues reported in #50.

1. Wheel / touchpad scroll does nothing in full-screen apps (nano/less/vim)

These programs run in xterm's alternate screen buffer, where there's no scrollback to move. xterm 6.0 has no built-in alternate-scroll option, and its internal wheel path dampens sub-50px touchpad deltas toward zero — so touchpad scrolling in nano was effectively a no-op (the exact symptom in the issue).

Fix: a custom wheel handler (useTerminal.ts) that, when the alt buffer is active and the app isn't tracking the mouse, translates the wheel delta into Up/Down arrow presses:

  • Sub-row accumulation — touchpads emit many tiny pixel deltas; a carried remainder means slow scrolling still advances a line once enough pixels accumulate.
  • Fling clamp — a single event moves at most one page, so a hard flick can't flood the PTY.
  • Stays out of the way — normal buffer keeps native scrollback (returns true); apps that track the mouse (e.g. vim set mouse=a) keep getting real mouse events; applicationCursorKeysMode is honored so DECCKM apps get ESC O A/B.
  • preventDefault so the gesture doesn't also scroll an ancestor.
  • Synthesized arrows route through the same broadcast path as typed input, so split-pane broadcast behaves identically for scroll and keystrokes.

The row math is a pure, unit-tested core (terminalWheelCore.ts) covering pixel/line/page modes, carry accumulation, direction reversal, the fling clamp, and degenerate inputs.

2. Selecting text always copies, even with "Select to Copy" off

handleMouseUp in terminalClipboard.ts wrote the selection to the clipboard unconditionally — only the feedback badge checked the toggle (default true). So a user who turned the setting off still got copy-on-select.

Fix: gate the clipboard write on getToggle("select-to-copy"). Explicit Ctrl+Shift+C still copies regardless.

Note: the issue also mentions wanting the selection to "disappear very quickly." That reads as ambiguous, so this PR addresses the concrete, unambiguous bug (toggle ignored) and leaves selection-clearing behavior unchanged — happy to follow up if a specific behavior is wanted.

Testing

  • New terminalWheelCore.test.ts (pure core).
  • Full suite green: 853 passed; tsc --noEmit clean.

🤖 Generated with Claude Code

…t Select-to-Copy (#50)

Two terminal fixes reported in #50:

- Wheel/touchpad scroll did nothing in full-screen apps (nano/less/vim).
  These run in the alternate screen buffer, where xterm has no scrollback
  to move; its built-in translation also dampens sub-50px touchpad deltas to
  zero, so scrolling was effectively a no-op. Add a custom wheel handler that
  translates the delta into Up/Down arrow presses, carrying the sub-row
  remainder so touchpads (many tiny pixel deltas) scroll smoothly, and
  clamping a fling to one page. It stays out of the way when the app tracks
  the mouse itself (e.g. vim `set mouse=a`) and in the normal buffer (native
  scrollback unchanged). Synthesized arrows route through the same broadcast
  path as typed input, and the row math lives in a pure, unit-tested core
  (terminalWheelCore).

- Copy-on-select ignored the "Select to Copy" toggle: mouseup copied the
  selection unconditionally while only the feedback badge honored the
  setting. Gate the clipboard write on the toggle; explicit Ctrl+Shift+C
  still copies regardless.
@kipavy

kipavy commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

✅ Manual e2e validation (headless dev build, tauri-driver)

Drove the live debug app and exercised both fixes through real DOM/pointer input in a less (alternate-screen) + local shell session. Both pass.

1. Alt-screen wheel / touchpad scroll

Opened less -N /tmp/f.txt (500 lines) — alternate buffer, the exact issue-#50 scenario (nano behaves identically).

Input Result
Wheel down deltaY 160 top line 1 → 11 (10 rows)
10 × tiny deltaY 6 (each < xterm's 50px dampening floor) top 11 → 14 (accumulated 3 rows) — the precise touchpad bug; stock xterm floors these to zero
Wheel up deltaY -112 scrolled back up 6 rows

defaultPrevented: true on every event confirms the new attachCustomWheelEventHandler is the authoritative path.

2. Select-to-Copy respects the toggle

Set a clipboard sentinel, then drag-selected a line of terminal output.

"Select to Copy" Selection made? Clipboard Copy badge
On (default) yes overwritten with selected text shown ✓
Off yes (text highlighted) unchanged (sentinel intact) not shown ✓

So with the toggle off the selection is still made but nothing is copied — the reported bug is fixed, and copy-on-select still works when the toggle is on. Ctrl+Shift+C remains a separate explicit-copy path.

Validation only — no code changed since the reviewed commit.

`files` is already declared `mut` at the top of the function, so the
`let mut files = files;` rebinding is a no-op that fails CI's
`cargo clippy -- -D warnings` (redundant_locals). Pre-existing on dev
(introduced in #43); removing it unblocks the build check for this PR.
@kipavy
kipavy merged commit 409c38d into dev Jul 24, 2026
2 checks passed
@kipavy
kipavy deleted the fix-terminal-altscroll-selectcopy-50 branch July 24, 2026 07:31
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.

1 participant