feat(web): restore tap/click/wheel mouse interaction when server strips mouse DECSETs#144
Open
TeigenZhang wants to merge 2 commits into
Open
feat(web): restore tap/click/wheel mouse interaction when server strips mouse DECSETs#144TeigenZhang wants to merge 2 commits into
TeigenZhang wants to merge 2 commits into
Conversation
added 2 commits
July 7, 2026 17:52
…-encode SGR when server strips mouse DECSETs v1.1.7 (3172bef, arrived via the master merge) strips mouse-tracking DECSET sequences from claude/codex/gemini output so the wheel keeps scrolling scrollback. Side effect: the browser xterm's mouseTrackingMode is permanently 'none' for those sessions, and the mobile touchend tap branch gates its synthetic click on exactly that mode — so tap-to-position-cursor silently died. Fix: when tracking reads 'none' but the session mode is one the server strips (claude/codex/gemini — the PTY-side TUI still has tracking ON), encode the SGR press+release report directly from the touch point and send it to the PTY, bypassing xterm's mouse encoder. No DOM click is dispatched, so xterm's local selection cannot trigger either. Tests: 3 new cases in test/terminal-touch-tap.test.ts (SGR encoding, grid clamping, shell-mode exclusion); verified E2E via Playwright iPhone emulation against both a stripped-stream instance and the production bundle.
…ssions Desktop click-to-position-cursor died under the server's mouse-DECSET strip (same root cause as the mobile touchend tap regression): xterm's native mouse encoder only emits SGR while mouseTrackingMode is ON, but the server strips the enabling DECSETs from claude/codex/gemini output. Hand-encode the report for plain left-clicks (_handleDesktopTerminalClick), skipping every click that already means something else (synthetic/compat, modified, double/triple, drag-selection, off-grid, xterm encoder live). Also widen forwarding to the wheel: Claude Code 2.1.187+ scrolls its own transcript on SGR wheel reports and no longer captures wheel as select-menu navigation (verified against 2.1.202), so forward the wheel to the TUI for strip-mode sessions at the buffer bottom (40ms-coalesced to avoid a tmux send-keys storm). Shift+wheel and any scrolled-up viewport stay on xterm's local scrollback. Guard synthetic taps/clicks on viewport-at-bottom so a scrolled-up report can't hit-test the wrong row. Tests: 12 cases in test/terminal-touch-tap.test.ts. Verified E2E via Playwright against the live instance (wheel up/down forward, Shift+wheel local, click).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Restores mouse interaction with the terminal (tap-to-position cursor, desktop click-to-position, and scroll-wheel forwarding) for sessions whose output the server strips of mouse-tracking DECSETs.
Root cause. To keep the wheel scrolling scrollback, the server strips
?1000/1002/1003/1006DECSET sequences from claude/codex/gemini output (isAltScreenStripMode,session.ts). Side effect: the browser xterm'smouseTrackingModeis permanently'none'for those sessions, even though the TUI on the PTY side still has tracking ON and understands SGR reports. Any UI that gates on xterm's live tracking mode — mobile touchend tap, desktop click, wheel forwarding — silently does nothing.Fix. When a session is one the server strips, hand-encode the SGR report from the pointer position and send it straight to the PTY, bypassing xterm's dormant encoder:
/modelmenu highlight ignores wheel reports). So the wheel is forwarded to the TUI for strip-mode sessions at the buffer bottom, coalesced into one PTY write per ~40ms to avoid asend-keysprocess storm.Shift+wheeland any scrolled-up viewport stay on xterm's local scrollback.Scrollback coordinate guard. SGR coordinates are viewport-relative, so a report computed while scrolled up would hit-test the wrong row. Synthetic taps/clicks/wheel are gated on the viewport being at the buffer bottom.
Behavior is unchanged for shell/opencode sessions and when a session genuinely has mouse tracking off.
Changes
terminal-ui.js—_handleDesktopTerminalClick,_sendSyntheticSgrTap/Wheel,_shouldForwardWheelToApp,_terminalViewportAtBottom,_clientPointToCell; wheel handler forwards to the app for strip-mode sessionstest/terminal-touch-tap.test.ts— 12 cases (SGR encoding, grid clamping, click-skip conditions, wheel gating/coalescing, scrollback guard, shell-mode exclusion)Test plan
npm test -- test/terminal-touch-tap.test.ts— 12/12 passnpm run check:frontend-syntaxShift+wheelstays on local scrollback/modelselect menu ignores wheel reports