diff --git a/app/TerminalView.m b/app/TerminalView.m index a1eeba926e..b27d02568e 100644 --- a/app/TerminalView.m +++ b/app/TerminalView.m @@ -31,7 +31,9 @@ - (void)userContentController:(WKUserContentController *)userContentController d } @end -@interface TerminalView () +@interface TerminalView () { + CGFloat _prevScrollY; +} @property (nonatomic) NSMutableArray *keyCommands; @property ScrollbarView *scrollbarView; @@ -104,6 +106,7 @@ - (void)setTerminal:(Terminal *)terminal { } _terminal = terminal; + _prevScrollY = 0; [_terminal addObserver:self forKeyPath:@"loaded" options:NSKeyValueObservingOptionInitial context:nil]; if (_terminal.loaded) [self installTerminalView]; @@ -268,7 +271,12 @@ - (void)userContentController:(WKUserContentController *)userContentController d } - (void)scrollViewDidScroll:(UIScrollView *)scrollView { - [self.terminal.webView evaluateJavaScript:[NSString stringWithFormat:@"exports.newScrollTop(%f)", scrollView.contentOffset.y] completionHandler:nil]; + CGFloat newY = scrollView.contentOffset.y; + [self.terminal.webView evaluateJavaScript:[NSString stringWithFormat:@"exports.newScrollTop(%f)", newY] completionHandler:nil]; + CGFloat delta = newY - _prevScrollY; + _prevScrollY = newY; + if (delta != 0) + [self.terminal.webView evaluateJavaScript:[NSString stringWithFormat:@"exports.handleScrollDelta(%f)", delta] completionHandler:nil]; } - (void)setKeyboardAppearance:(UIKeyboardAppearance)keyboardAppearance { diff --git a/app/terminal/term.js b/app/terminal/term.js index 300fe6e128..ae4916f990 100644 --- a/app/terminal/term.js +++ b/app/terminal/term.js @@ -154,6 +154,27 @@ exports.getCharacterSize = () => { }; exports.clearScrollback = () => term.clearScrollback(); + +// Forward scroll delta as synthetic WheelEvents into hterm's onMouse_ pipeline. +let scrollDeltaRemainder = 0; +exports.handleScrollDelta = (delta) => { + if (term.vt.mouseReport === term.vt.MOUSE_REPORT_DISABLED && term.isPrimaryScreen()) + return; + const charH = term.scrollPort_.characterSize.height; + if (!charH) return; + scrollDeltaRemainder += delta; + const lines = Math.trunc(scrollDeltaRemainder / charH); + if (lines === 0) return; + scrollDeltaRemainder -= lines * charH; + for (let i = 0; i < Math.abs(lines); i++) { + term.scrollPort_.screen_.dispatchEvent(new WheelEvent('wheel', { + deltaY: lines > 0 ? 1 : -1, + deltaMode: WheelEvent.DOM_DELTA_LINE, + cancelable: true, + })); + } +}; + exports.setUserGesture = () => term.accessibilityReader_.hasUserGesture = true; hterm.openUrl = (url) => native.openLink(url);