From 74a6dfb19779ecc13b52483e15634b0e5f49b416 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 29 Jan 2018 11:28:48 -0800 Subject: [PATCH 1/3] Send arrow events on mouse wheel in alt buffer Fixes #426 --- src/Terminal.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Terminal.ts b/src/Terminal.ts index 6e501d03..e1452f44 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -991,7 +991,20 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT // } on(el, 'wheel', (ev: WheelEvent) => { - if (!this.mouseEvents) return; + if (!this.mouseEvents) { + // Convert wheel events into up/down events when the buffer does not have scrollback, this + // enables scrolling in apps hosted in the alt buffer such as vim or tmux. + if (!this.buffer.hasScrollback) { + let sequence = C0.ESC + (this.applicationCursor ? 'O' : '['); + if (ev.wheelDeltaY > 0) { + sequence += 'A'; + } else { + sequence += 'B'; + } + this.send(sequence); + } + return; + } if (this.x10Mouse || this.vt300Mouse || this.decLocator) return; sendButton(ev); ev.preventDefault(); From e137530581511a15fb060b9a838be8a59072336e Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 5 Mar 2018 14:22:20 -0800 Subject: [PATCH 2/3] Scroll by exact line amount in alt buffer, unify scroll logic Fixes #1304 --- src/Terminal.ts | 21 +++++++++----- src/Types.ts | 1 + src/Viewport.ts | 58 ++++++++++++++++++++++++++++++------- src/utils/TestUtils.test.ts | 3 ++ 4 files changed, 66 insertions(+), 17 deletions(-) diff --git a/src/Terminal.ts b/src/Terminal.ts index ec96d4ff..d234cbd4 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -1056,15 +1056,22 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT on(el, 'wheel', (ev: WheelEvent) => { if (!this.mouseEvents) { // Convert wheel events into up/down events when the buffer does not have scrollback, this - // enables scrolling in apps hosted in the alt buffer such as vim or tmux. + // enables scrolling in apps hosted in the alt buffer such as vim or tmux. if (!this.buffer.hasScrollback) { - let sequence = C0.ESC + (this.applicationCursor ? 'O' : '['); - if (ev.wheelDeltaY > 0) { - sequence += 'A'; - } else { - sequence += 'B'; + const amount = this.viewport.getLinesScrolled(ev); + + // Do nothing if there's no vertical scroll + if (amount === 0) { + return; } - this.send(sequence); + + // Construct and send sequences + const sequence = C0.ESC + (this.applicationCursor ? 'O' : '[') + ( ev.deltaY < 0 ? 'A' : 'B'); + let data = ''; + for (let i = 0; i < Math.abs(amount); i++) { + data += sequence; + } + this.send(data); } return; } diff --git a/src/Types.ts b/src/Types.ts index be292dbf..dd50ce06 100644 --- a/src/Types.ts +++ b/src/Types.ts @@ -89,6 +89,7 @@ export interface IInputHandlingTerminal extends IEventEmitter { export interface IViewport { scrollBarWidth: number; syncScrollArea(): void; + getLinesScrolled(ev: WheelEvent): number; onWheel(ev: WheelEvent): void; onTouchStart(ev: TouchEvent): void; onTouchMove(ev: TouchEvent): void; diff --git a/src/Viewport.ts b/src/Viewport.ts index 35a2aa68..c64bfbb7 100644 --- a/src/Viewport.ts +++ b/src/Viewport.ts @@ -21,6 +21,11 @@ export class Viewport implements IViewport { private lastRecordedBufferHeight: number = 0; private lastTouchY: number; + // Stores a partial line amount when scrolling, this is used to keep track of how much of a line + // is scrolled so we can "scroll" over partial lines and feel natural on touchpads. This is a + // quick fix and could have a more robust solution in place that reset the value when needed. + private _wheelPartialScroll: number; + /** * Creates a new Viewport. * @param terminal The terminal this viewport belongs to. @@ -113,22 +118,55 @@ export class Viewport implements IViewport { * @param ev The mouse wheel event. */ public onWheel(ev: WheelEvent): void { - if (ev.deltaY === 0) { - // Do nothing if it's not a vertical scroll event + const amount = this._getPixelsScrolled(ev); + if (amount === 0) { return; } - // Fallback to WheelEvent.DOM_DELTA_PIXEL - let multiplier = 1; - if (ev.deltaMode === WheelEvent.DOM_DELTA_LINE) { - multiplier = this.currentRowHeight; - } else if (ev.deltaMode === WheelEvent.DOM_DELTA_PAGE) { - multiplier = this.currentRowHeight * this.terminal.rows; - } - this.viewportElement.scrollTop += ev.deltaY * multiplier; + this.viewportElement.scrollTop += amount; // Prevent the page from scrolling when the terminal scrolls ev.preventDefault(); } + private _getPixelsScrolled(ev: WheelEvent): number { + // Do nothing if it's not a vertical scroll event + if (ev.deltaY === 0) { + return 0; + } + + // Fallback to WheelEvent.DOM_DELTA_PIXEL + let amount = ev.deltaY; + if (ev.deltaMode === WheelEvent.DOM_DELTA_LINE) { + amount *= this.currentRowHeight; + } else if (ev.deltaMode === WheelEvent.DOM_DELTA_PAGE) { + amount *= this.currentRowHeight * this.terminal.rows; + } + return amount; + } + + /** + * Gets the number of pixels scrolled by the mouse event taking into account what type of delta + * is being used. + * @param ev The mouse wheel event. + */ + public getLinesScrolled(ev: WheelEvent): number { + // Do nothing if it's not a vertical scroll event + if (ev.deltaY === 0) { + return 0; + } + + // Fallback to WheelEvent.DOM_DELTA_LINE + let amount = ev.deltaY; + if (ev.deltaMode === WheelEvent.DOM_DELTA_PIXEL) { + amount /= this.currentRowHeight + 0.0; // Prevent integer division + this._wheelPartialScroll += amount; + amount = Math.floor(Math.abs(this._wheelPartialScroll)) * (this._wheelPartialScroll > 0 ? 1 : -1); + this._wheelPartialScroll %= 1; + } else if (ev.deltaMode === WheelEvent.DOM_DELTA_PAGE) { + amount *= this.terminal.rows; + } + return amount; + } + /** * Handles the touchstart event, recording the touch occurred. * @param ev The touch event. diff --git a/src/utils/TestUtils.test.ts b/src/utils/TestUtils.test.ts index 8ba16179..88b375e0 100644 --- a/src/utils/TestUtils.test.ts +++ b/src/utils/TestUtils.test.ts @@ -337,6 +337,9 @@ export class MockViewport implements IViewport { throw new Error('Method not implemented.'); } syncScrollArea(): void { } + getLinesScrolled(ev: WheelEvent): number { + throw new Error('Method not implemented.'); + } } export class MockCompositionHelper implements ICompositionHelper { From ff6ef1b63a3996906191142c98b1dd277d6ce24f Mon Sep 17 00:00:00 2001 From: Thomas Zilz Date: Tue, 6 Mar 2018 11:39:14 +0100 Subject: [PATCH 3/3] Initialise _wheelPartialScroll to 0 to prevent NaN --- src/Viewport.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Viewport.ts b/src/Viewport.ts index c64bfbb7..e276d113 100644 --- a/src/Viewport.ts +++ b/src/Viewport.ts @@ -24,7 +24,7 @@ export class Viewport implements IViewport { // Stores a partial line amount when scrolling, this is used to keep track of how much of a line // is scrolled so we can "scroll" over partial lines and feel natural on touchpads. This is a // quick fix and could have a more robust solution in place that reset the value when needed. - private _wheelPartialScroll: number; + private _wheelPartialScroll: number = 0; /** * Creates a new Viewport.