diff --git a/src/browser/CoreBrowserTerminal.ts b/src/browser/CoreBrowserTerminal.ts index 51d40224..6e0c7ad1 100644 --- a/src/browser/CoreBrowserTerminal.ts +++ b/src/browser/CoreBrowserTerminal.ts @@ -1156,9 +1156,10 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { this.textarea!.value = ''; } + const wasModifierOnly = this._keyboardService.useWin32InputMode && wasModifierKeyOnlyEvent(event); this._onKey.fire({ key: result.key, domEvent: event }); this._showCursor(); - this.coreService.triggerDataEvent(result.key, true); + this.coreService.triggerDataEvent(result.key, !wasModifierOnly); // Cancel events when not in screen reader mode so events don't get bubbled up and handled by // other listeners. When screen reader mode is enabled, we don't cancel them (unless ctrl or alt @@ -1199,7 +1200,8 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { // Handle key release for Kitty keyboard protocol const result = this._keyboardService.evaluateKeyUp(ev); if (result?.key) { - this.coreService.triggerDataEvent(result.key, true); + const wasModifierOnly = this._keyboardService.useWin32InputMode && wasModifierKeyOnlyEvent(ev); + this.coreService.triggerDataEvent(result.key, !wasModifierOnly); } this.updateCursorStyle(ev); @@ -1410,5 +1412,10 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { function wasModifierKeyOnlyEvent(ev: KeyboardEvent): boolean { return ev.keyCode === 16 || // Shift ev.keyCode === 17 || // Ctrl - ev.keyCode === 18; // Alt + ev.keyCode === 18 || // Alt + ev.keyCode === 91 || // Meta (Left) + ev.keyCode === 92 || // Meta (Right) + ev.keyCode === 93 || // Meta (Menu) + ev.keyCode === 224 || // Meta (Firefox) + ev.key === 'Meta'; } diff --git a/src/browser/Terminal.test.ts b/src/browser/Terminal.test.ts index 66637e37..ba2ce6dd 100644 --- a/src/browser/Terminal.test.ts +++ b/src/browser/Terminal.test.ts @@ -401,6 +401,42 @@ describe('Terminal', () => { }); }); + describe('keyDown', () => { + it('should not scroll down on modifier-only input in win32 input mode', async () => { + term.options.vtExtensions = { win32InputMode: true }; + term.coreService.decPrivateModes.win32InputMode = true; + (term as any).textarea = { value: '' }; + + await term.writeP('test\r\n'.repeat(term.rows * 3)); + const startYDisp = term.buffer.ydisp; + term.scrollLines(-1); + const scrolledYDisp = term.buffer.ydisp; + assert.equal(scrolledYDisp, startYDisp - 1); + + const evKeyDown = { + type: 'keydown', + key: 'Control', + keyCode: 17, + ctrlKey: true, + preventDefault: () => { }, + stopPropagation: () => { } + } as KeyboardEvent; + + const evKeyUp = { + type: 'keyup', + key: 'Control', + keyCode: 17, + preventDefault: () => { }, + stopPropagation: () => { } + } as KeyboardEvent; + + term.keyDown(evKeyDown); + assert.equal(term.buffer.ydisp, scrolledYDisp); + (term as any)._keyUp(evKeyUp); + assert.equal(term.buffer.ydisp, scrolledYDisp); + }); + }); + describe('scroll() function', () => { describe('when scrollback > 0', () => { it('should create a new line and scroll', () => {