forward mouse wheel as xterm wheel escapes when TUI asks for it (T-74)
test / unit + widget + golden + a11y (push) Failing after 31s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
test / dart doc (lib API) (push) Failing after 1m0s

Previously every PointerScrollEvent fell straight to PgUp/PgDown
keyInput as a "universal scroll" workaround. That kept plain shells
scrolling but starved vim mouse=a / htop / less of the wheel events
they expect.

Now `_onPointerSignal` checks `terminal.mouseMode.reportScroll`
first (the cascade of mouse handlers cares about this flag). If
the inner program declared ?1000h / ?1002h / ?1003h (optionally
+?1006h SGR), the wheel forwards as `wheelUp` / `wheelDown` button
events through the existing `renderTerminal.mouseEvent` path. Plain
shells stay on PgUp/PgDown because their mouse mode is `none` —
the existing test for that path keeps passing unchanged.

Click + drag forwarding through the gesture handler was already
wired (renderTerminal.mouseEvent for taps), so T-74's acceptance
list is met by this scroll fix alone.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-05-18 13:51:55 +02:00
co-authored by Claude
parent 74f9a45539
commit ae8d774529
5 changed files with 62 additions and 7 deletions
+19 -7
View File
@@ -8,6 +8,8 @@ import 'package:flutter/services.dart';
import 'package:clide/src/terminal/src/core/buffer/cell_offset.dart';
import 'package:clide/src/terminal/src/core/input/keys.dart';
import 'package:clide/src/terminal/src/core/mouse/button.dart';
import 'package:clide/src/terminal/src/core/mouse/button_state.dart';
import 'package:clide/src/terminal/src/terminal.dart';
import 'package:clide/src/terminal/src/ui/controller.dart';
import 'package:clide/src/terminal/src/ui/cursor_type.dart';
@@ -155,13 +157,23 @@ class TerminalViewState extends State<TerminalView> {
final lh = renderTerminal.lineHeight;
if (lh <= 0) return;
final lines = (event.scrollDelta.dy / lh).round().clamp(-5, 5);
// Always send PgUp/PgDown for scroll — the mouse-escape-sequence
// path tends to be a no-op in TUI apps (claude, vim) that capture
// mouse for other purposes. PgUp/PgDown is the universal scroll.
for (var i = 0; i < lines.abs(); i++) {
widget.terminal.keyInput(
lines < 0 ? TerminalKey.pageUp : TerminalKey.pageDown,
);
if (lines == 0) return;
final button = lines > 0 ? TerminalMouseButton.wheelDown : TerminalMouseButton.wheelUp;
final count = lines.abs();
// If the inner program has declared a mouse mode that reports
// scroll (?1000h / ?1002h / ?1003h / +?1006h for SGR), forward
// proper xterm wheel-button escapes so the TUI can react (vim
// mouse=a scroll, less line-by-line, htop highlight). Otherwise
// fall back to PgUp/PgDown so plain shells still scroll (T-74).
if (widget.terminal.mouseMode.reportScroll) {
for (var i = 0; i < count; i++) {
renderTerminal.mouseEvent(button, TerminalMouseButtonState.down, event.localPosition);
}
return;
}
final key = lines < 0 ? TerminalKey.pageUp : TerminalKey.pageDown;
for (var i = 0; i < count; i++) {
widget.terminal.keyInput(key);
}
}