Skip to content

Commit d501ca9

Browse files
committed
Forward touch scroll events as terminal input
Dispatches synthetic WheelEvents into hterm's existing onMouse_ pipeline so touch scroll gestures reach programs that listen for them. hterm handles mouse reporting (VT) and alternate screen arrow keys (DECSET 1007) automatically. On the primary screen with mouse reporting disabled, the existing visual scrollback behavior is preserved unchanged. Fixes #2375 Fixes #2537
1 parent cc391ff commit d501ca9

2 files changed

Lines changed: 38 additions & 5 deletions

File tree

app/TerminalView.m

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ - (void)userContentController:(WKUserContentController *)userContentController d
3131
}
3232
@end
3333

34-
@interface TerminalView ()
34+
@interface TerminalView () {
35+
CGFloat _prevScrollY;
36+
}
3537

3638
@property (nonatomic) NSMutableArray<UIKeyCommand *> *keyCommands;
3739
@property ScrollbarView *scrollbarView;
@@ -104,6 +106,7 @@ - (void)setTerminal:(Terminal *)terminal {
104106
}
105107

106108
_terminal = terminal;
109+
_prevScrollY = 0;
107110
[_terminal addObserver:self forKeyPath:@"loaded" options:NSKeyValueObservingOptionInitial context:nil];
108111
if (_terminal.loaded)
109112
[self installTerminalView];
@@ -268,7 +271,10 @@ - (void)userContentController:(WKUserContentController *)userContentController d
268271
}
269272

270273
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
271-
[self.terminal.webView evaluateJavaScript:[NSString stringWithFormat:@"exports.newScrollTop(%f)", scrollView.contentOffset.y] completionHandler:nil];
274+
CGFloat newY = scrollView.contentOffset.y;
275+
CGFloat delta = newY - _prevScrollY;
276+
_prevScrollY = newY;
277+
[self.terminal.webView evaluateJavaScript:[NSString stringWithFormat:@"exports.handleScroll(%f, %f)", newY, delta] completionHandler:nil];
272278
}
273279

274280
- (void)setKeyboardAppearance:(UIKeyboardAppearance)keyboardAppearance {

app/terminal/term.js

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,38 @@ term.scrollPort_.onTouch = (e) => {
110110
};
111111
// Scroll to bottom wrapper
112112
exports.scrollToBottom = () => term.scrollEnd();
113-
// Set scroll position
114-
exports.newScrollTop = (y) => {
115-
// two lines instead of one because the value you read out of scrollTop can be different from the value you write into it
113+
// Set scroll position and optionally forward delta as WheelEvents into hterm's
114+
// onMouse_ pipeline for mouse reporting (VT) and alternate screen arrow keys.
115+
let scrollDeltaRemainder = 0;
116+
exports.handleScroll = (y, delta) => {
116117
term.scrollPort_.screen_.scrollTop = y;
117118
lastScrollTop = term.scrollPort_.screen_.scrollTop;
119+
120+
if (delta === 0) return;
121+
if (term.vt.mouseReport === term.vt.MOUSE_REPORT_DISABLED && term.isPrimaryScreen())
122+
return;
123+
124+
const charH = term.scrollPort_.characterSize.height;
125+
if (!charH) return;
126+
127+
scrollDeltaRemainder += delta;
128+
const lines = Math.trunc(scrollDeltaRemainder / charH);
129+
if (lines === 0) return;
130+
scrollDeltaRemainder -= lines * charH;
131+
132+
const abs = Math.abs(lines);
133+
const down = lines > 0;
134+
for (let i = 0; i < abs; i++) {
135+
term.scrollPort_.screen_.dispatchEvent(new WheelEvent('wheel', {
136+
deltaY: down ? 1 : -1,
137+
deltaMode: WheelEvent.DOM_DELTA_LINE,
138+
bubbles: true,
139+
cancelable: true,
140+
}));
141+
}
118142
};
143+
// Keep old name for compatibility
144+
exports.newScrollTop = (y) => exports.handleScroll(y, 0);
119145

120146
// Send scroll height and position to native code
121147
let lastScrollHeight, lastScrollTop;
@@ -154,6 +180,7 @@ exports.getCharacterSize = () => {
154180
};
155181

156182
exports.clearScrollback = () => term.clearScrollback();
183+
157184
exports.setUserGesture = () => term.accessibilityReader_.hasUserGesture = true;
158185

159186
hterm.openUrl = (url) => native.openLink(url);

0 commit comments

Comments
 (0)