From 57eefd7aa5ab8a87738cc3498546196d191ecc95 Mon Sep 17 00:00:00 2001 From: Codeman maintainer Date: Wed, 17 Jun 2026 18:02:21 +0200 Subject: [PATCH] fix(terminal): don't scroll/fling on a sub-threshold tap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The touchmove handler accumulated pixelAccum/velocity and could scrollLines on every move — including micro-drift below the 8px tap threshold. A jittery tap (<8px) stayed classified as a tap (didScroll=false, so tap-to-position fired) yet still left a non-zero velocity, which touchend turned into a momentum fling. Result: one tap both positioned the cursor and scrolled. Gate the scroll/velocity accumulation behind didScroll so sub-threshold movement is inert, matching the handler's stated tap-vs-scroll intent. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/web/public/terminal-ui.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/web/public/terminal-ui.js b/src/web/public/terminal-ui.js index 65afc5b6..65e767ee 100644 --- a/src/web/public/terminal-ui.js +++ b/src/web/public/terminal-ui.js @@ -401,11 +401,14 @@ Object.assign(CodemanApp.prototype, { if (!didScroll && Math.abs(touchY - touchStartY) >= TAP_THRESHOLD) { didScroll = true; } - // Only preventDefault once it's a real scroll — preventing micro-drift - // touchmove kills click synthesis, which iOS needs to show the keyboard. - if (didScroll) { - ev.preventDefault(); - } + // Below the tap threshold, treat the gesture as a potential tap: + // don't preventDefault (iOS needs click synthesis to show the + // keyboard) and don't accumulate scroll distance or velocity. Without + // this guard, sub-threshold micro-drift still scrolls a line and + // leaves a non-zero velocity that touchend turns into a momentum + // fling, so a jittery tap would both position the cursor AND scroll. + if (!didScroll) return; + ev.preventDefault(); const delta = touchLastY - touchY; // positive = scroll down pixelAccum += delta; velocity = delta * 1.2;