xterm's native touch scrolling crawled a line at a time and stalled after a few. Map finger drags on the viewport to term.scrollLines (skipped on the alt screen, which the app owns) and claim vertical pans via touch-action: pan-y. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -130,6 +130,51 @@ export function createAttachConnection(
|
||||
term.loadAddon(fit);
|
||||
term.open(body);
|
||||
|
||||
// Touch scrollback: xterm's built-in touch handling on the viewport is jittery
|
||||
// (drags crawl a line at a time and stall after a few), so map finger drags to
|
||||
// term.scrollLines ourselves. Skipped on the alternate screen (full-screen
|
||||
// TUIs like tmux/Claude Code) — there's no scrollback to move and the app owns
|
||||
// the gesture. `touch-action: pan-y` (CSS) tells the browser we handle Y.
|
||||
{
|
||||
const vp = el.querySelector(".xterm-viewport") as HTMLElement | null;
|
||||
const cellH = () => {
|
||||
const core = (term as unknown as {
|
||||
_core?: { _renderService?: { dimensions?: { css?: { cell?: { height: number } } } } };
|
||||
})._core;
|
||||
return core?._renderService?.dimensions?.css?.cell?.height || 16;
|
||||
};
|
||||
if (vp) {
|
||||
let lastY = 0;
|
||||
let remainder = 0;
|
||||
vp.addEventListener(
|
||||
"touchstart",
|
||||
(e) => {
|
||||
if (e.touches.length !== 1) return;
|
||||
lastY = e.touches[0].clientY;
|
||||
remainder = 0;
|
||||
},
|
||||
{ passive: true },
|
||||
);
|
||||
vp.addEventListener(
|
||||
"touchmove",
|
||||
(e) => {
|
||||
if (e.touches.length !== 1) return;
|
||||
if (term.buffer.active.type === "alternate") return; // app-owned
|
||||
const y = e.touches[0].clientY;
|
||||
const px = lastY - y + remainder; // finger up → scroll toward newer
|
||||
lastY = y;
|
||||
const lines = Math.trunc(px / cellH());
|
||||
remainder = px - lines * cellH();
|
||||
if (lines !== 0) {
|
||||
term.scrollLines(lines);
|
||||
e.preventDefault();
|
||||
}
|
||||
},
|
||||
{ passive: false },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Mobile: the special-key bar is only useful while the soft keyboard is up,
|
||||
// so reveal it only when the terminal's hidden textarea is focused (CSS still
|
||||
// gates it to coarse pointers). Tapping a keycap keeps focus via pointerdown
|
||||
|
||||
@@ -1148,6 +1148,9 @@ textarea {
|
||||
.attach-body .xterm .xterm-viewport {
|
||||
overflow-y: auto;
|
||||
scrollbar-width: none;
|
||||
/* We drive scrollback from touchmove (see attach.ts); claim vertical pans so
|
||||
the browser doesn't fight the handler or trigger gestures mid-scroll. */
|
||||
touch-action: pan-y;
|
||||
}
|
||||
|
||||
.attach-body .xterm .xterm-viewport::-webkit-scrollbar {
|
||||
|
||||
Reference in New Issue
Block a user