9721941962
lib/wheelReports.ts SCROLL_SPEED = 0.7: a touchpad's travel is scaled, and a wheel notch's reports are carried as a fraction (rounded, so the first notch still moves; reset when the direction turns). xterm's own scrollback gets the same scrollSensitivity.
77 lines
3.0 KiB
TypeScript
77 lines
3.0 KiB
TypeScript
/**
|
||
* @file wheelReports.ts — turns a browser wheel event into the number of SGR
|
||
* wheel reports a terminal pane gets, in proportion to how far the finger or
|
||
* the wheel moved, the way a native terminal does.
|
||
*
|
||
* xterm.js sends ONE report per wheel event whatever its size, and damps a
|
||
* touchpad's pixel deltas ×0.3 before it counts even that one — a touchpad
|
||
* swipe crawled. In our panes every report moves a fixed stretch (Claude's
|
||
* `CLAUDE_CODE_SCROLL_SPEED`, tmux's copy-mode `WHEEL_LINES`), so a report is
|
||
* sent per `LINES_PER_REPORT` rows of travel: a touchpad scrolls 1:1 with the
|
||
* finger, and a wheel notch always sends at least one. `SCROLL_SPEED` then
|
||
* slows both down (the user asked for 30 % less): a touchpad's travel is
|
||
* scaled, and a notch's reports are carried as a fraction, rounded, so the
|
||
* first notch still moves and the average comes out at that share.
|
||
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
||
*/
|
||
|
||
/** Rows one report scrolls in a Claude pane (server/lib/pty-run.js CLAUDE_SCROLL_SPEED). */
|
||
export const LINES_PER_REPORT = 5;
|
||
|
||
/** Share of the travel a pane scrolls (0.7 = 30 % slower than 1:1). */
|
||
export const SCROLL_SPEED = 0.7;
|
||
|
||
/** A pixel delta this large or larger is a wheel notch, not a touchpad step (xterm.js's own cut). */
|
||
const NOTCH_PX = 50;
|
||
|
||
const DOM_DELTA_PIXEL = 0;
|
||
const DOM_DELTA_LINE = 1;
|
||
const DOM_DELTA_PAGE = 2;
|
||
|
||
export interface WheelState {
|
||
/** Touchpad travel not yet sent, in rows (signed). */
|
||
partial: number;
|
||
/** Wheel-notch reports owed but not sent yet (signed, a fraction). */
|
||
notch?: number;
|
||
/** Direction of the last notch (the carry above may round to either sign). */
|
||
notchDir?: number;
|
||
}
|
||
|
||
/**
|
||
* Signed report count for `ev` — negative scrolls up. `rowPx` is one row's
|
||
* height on screen (CSS scale included), `rows` the terminal's height.
|
||
*/
|
||
export function wheelReports(
|
||
state: WheelState,
|
||
ev: Pick<WheelEvent, "deltaY" | "deltaMode">,
|
||
rowPx: number,
|
||
rows: number
|
||
): number {
|
||
if (!ev.deltaY || !(rowPx > 0)) return 0;
|
||
const sign = ev.deltaY < 0 ? -1 : 1;
|
||
if (ev.deltaMode === DOM_DELTA_PIXEL && Math.abs(ev.deltaY) < NOTCH_PX) {
|
||
// Touchpad: carry the remainder, so slow swipes still add up.
|
||
if (Math.sign(state.partial) === -sign) state.partial = 0; // turned around
|
||
state.partial += (ev.deltaY / rowPx) * SCROLL_SPEED;
|
||
const n = Math.trunc(state.partial / LINES_PER_REPORT);
|
||
state.partial -= n * LINES_PER_REPORT;
|
||
return n;
|
||
}
|
||
// A notch (or a fast flick): at least one report, more for a long one.
|
||
state.partial = 0;
|
||
if (state.notchDir !== sign) state.notch = 0; // turned around
|
||
state.notchDir = sign;
|
||
const lines =
|
||
ev.deltaMode === DOM_DELTA_LINE
|
||
? ev.deltaY
|
||
: ev.deltaMode === DOM_DELTA_PAGE
|
||
? ev.deltaY * rows
|
||
: ev.deltaY / rowPx;
|
||
const owed =
|
||
(state.notch ?? 0) +
|
||
sign * Math.max(1, Math.round(Math.abs(lines) / LINES_PER_REPORT)) * SCROLL_SPEED;
|
||
const n = sign * Math.round(Math.abs(owed));
|
||
state.notch = owed - n;
|
||
return n;
|
||
}
|