镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

fix: scroll full-screen apps with a finger on touch devices - #20

Open
zarv1k wants to merge 1 commit into
cloudcli-ai:mainfrom
zarv1k:fix/touch-scroll-mouse-reporting
Open

zarv1k wants to merge 1 commit into
cloudcli-ai:mainfrom
zarv1k:fix/touch-scroll-mouse-reporting

Conversation

@zarv1k

@zarv1k zarv1k commented Oct 2, 2026

Copy link
Copy Markdown

Summary

On touch devices a finger could not scroll full-screen apps — Claude Code, vim, less, htop — while a mouse wheel could. Two separate causes:

  1. Mouse reporting / alternate screen. These apps run on the alternate screen, usually with mouse tracking on. xterm.js skips its own touch handling entirely while mouse events are active (if (this.coreMouseService.areMouseEventsActive) return; in its touchstart/touchmove listeners), and the alternate buffer has no scrollback for a viewport scroll to move anyway. Such apps scroll themselves when the terminal forwards the wheel.

    New src/touch.ts: while the app owns scrolling (terminal.modes.mouseTrackingMode !== 'none' or the alternate buffer is active), a vertical drag is turned into WheelEvents on .xterm-screen. xterm then handles them exactly like a real wheel — SGR 64/65 with mouse reporting, arrow keys without it — and a flick keeps gliding briefly after the finger lifts. A plain shell on the normal buffer is left to xterm's own touch scrolling.

  2. Native text selection on iOS. CloudCLI's mobile stylesheet sets .xterm, .xterm .xterm-viewport { user-select: text !important } (for the built-in Shell's tap-hold selection). That applies to the plugin's terminals too, and on iOS it lets WebKit claim a finger drag as native text selection — after which touchmove never reaches the terminal at all. The plugin's stylesheet now restores xterm's own user-select: none for .wt-root .xterm.

Testing

  • npm run typecheck and npm run build pass.
  • Headless Chromium with touch emulation (CDP touch events):
    • alternate screen + SGR mouse: swiping up/down sends ESC[<65;… / ESC[<64;… reports, with more arriving during the glide; a slow drag that parks before lifting does not glide;
    • alternate screen without mouse: swiping sends ESC[B / ESC[A;
    • normal buffer with scrollback: xterm scrolls the viewport itself and nothing is sent to the PTY.
  • Checked on an iPhone (installed PWA): scrolling works in Claude Code, less and vim, and in a plain shell's scrollback.
  • npm test: resize reaches the PTY and a dropped connection keeps the shell alive… fail on unmodified main too in my environment (Debian 13, Node 24). This change only touches the frontend.

Claude Code, vim and less run on the alternate screen, usually with mouse
reporting on. xterm.js drops its own touch handling while mouse events are
active, and the alternate screen has no scrollback to move anyway - these
apps scroll themselves when the terminal forwards the wheel. So a mouse
wheel scrolled them and a finger did nothing.

While the app owns scrolling (mouse tracking on, or the alternate buffer),
a vertical drag is now turned into wheel events on the terminal, which
xterm forwards exactly like a real wheel (SGR 64/65, or arrow keys without
mouse reporting), with inertia after a flick. A plain shell on the normal
buffer keeps xterm's own touch scrolling.

Also undo CloudCLI's mobile 'user-select:text!important' on .xterm inside
the plugin: on iOS it lets WebKit claim the drag as native text selection,
after which touchmove never reaches the terminal at all.
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