diff --git a/web/src/attach.ts b/web/src/attach.ts index 58da3ec..95d05dc 100644 --- a/web/src/attach.ts +++ b/web/src/attach.ts @@ -143,8 +143,10 @@ export function createAttachConnection( // • alt screen with no mouse tracking → nothing to do; the app owns input. // `touch-action: none` (CSS) keeps the browser from cancelling the custom // gesture stream; only the terminal surface opts out of native page panning. + // Listeners MUST sit on `.xterm`, not `.xterm-viewport`: `.xterm-screen` is a + // later sibling of the viewport, so it paints over it and takes every touch. { - const vp = el.querySelector(".xterm-viewport") as HTMLElement | null; + const root = term.element as HTMLElement | undefined; const screen = el.querySelector(".xterm-screen") as HTMLElement | null; const cellH = () => { const core = (term as unknown as { @@ -152,11 +154,11 @@ export function createAttachConnection( })._core; return core?._renderService?.dimensions?.css?.cell?.height || 16; }; - if (vp) { + if (root) { let lastY = 0; let lastX = 0; let remainder = 0; - vp.addEventListener( + root.addEventListener( "touchstart", (e) => { if (e.touches.length !== 1) return; @@ -166,7 +168,7 @@ export function createAttachConnection( }, { passive: true }, ); - vp.addEventListener( + root.addEventListener( "touchmove", (e) => { if (e.touches.length !== 1) return; diff --git a/web/src/styles.css b/web/src/styles.css index 77ce344..d6224ef 100644 --- a/web/src/styles.css +++ b/web/src/styles.css @@ -1332,10 +1332,12 @@ input.leaf-rename:focus { .attach-body .xterm .xterm-viewport { overflow-y: auto; scrollbar-width: none; - /* Maestro drives scrollback from touchmove (see attach.ts). `pan-y` hands - the gesture to the browser, which may cancel the event stream before the - terminal sees it; `none` keeps a drag inside the terminal under our - control while the rest of the page retains native scrolling. */ +} + +/* Maestro drives scrollback from touchmove (see attach.ts), so the browser must + not claim the gesture. On `.xterm`, not the viewport: `.xterm-screen` paints + over the viewport and is what a finger lands on. */ +.attach-body .xterm { touch-action: none; }