From afc6f0b7eba2db5e22532f7c88c609adaec27676 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sun, 11 Jan 2026 09:00:08 -0800 Subject: [PATCH 1/2] Fix caps not working in win32InputMode Part of #2357 --- src/browser/CoreBrowserTerminal.ts | 4 ++-- src/browser/services/Services.ts | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/browser/CoreBrowserTerminal.ts b/src/browser/CoreBrowserTerminal.ts index dca090f673..c26e670515 100644 --- a/src/browser/CoreBrowserTerminal.ts +++ b/src/browser/CoreBrowserTerminal.ts @@ -1113,8 +1113,8 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { // HACK: Process A-Z in the keypress event to fix an issue with macOS IMEs where lower case // letters cannot be input while caps lock is on. Skip this hack when using kitty protocol - // as it needs to send proper CSI u sequences for all key events. - if (!this._keyboardService.useKitty && event.key && !event.ctrlKey && !event.altKey && !event.metaKey && event.key.length === 1) { + // or Win32 input mode as they need to send proper sequences for all key events. + if (!this._keyboardService.useKitty && !this._keyboardService.useWin32InputMode && event.key && !event.ctrlKey && !event.altKey && !event.metaKey && event.key.length === 1) { if (event.key.charCodeAt(0) >= 65 && event.key.charCodeAt(0) <= 90) { return true; } diff --git a/src/browser/services/Services.ts b/src/browser/services/Services.ts index cac62915aa..535afa6468 100644 --- a/src/browser/services/Services.ts +++ b/src/browser/services/Services.ts @@ -163,4 +163,5 @@ export interface IKeyboardService { evaluateKeyDown(event: KeyboardEvent): IKeyboardResult; evaluateKeyUp(event: KeyboardEvent): IKeyboardResult | undefined; readonly useKitty: boolean; + readonly useWin32InputMode: boolean; } From a1fca4feb8fc507548f0399bee230a57e55058cb Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sun, 11 Jan 2026 09:02:44 -0800 Subject: [PATCH 2/2] Fix ctrl+letter when inside pwsh->WSL --- src/common/input/Win32InputMode.test.ts | 9 +++++++++ src/common/input/Win32InputMode.ts | 15 ++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/common/input/Win32InputMode.test.ts b/src/common/input/Win32InputMode.test.ts index b3b72e6f20..3381a29145 100644 --- a/src/common/input/Win32InputMode.test.ts +++ b/src/common/input/Win32InputMode.test.ts @@ -119,6 +119,15 @@ describe('Win32InputMode', () => { it('symbol', () => test({ code: 'Digit4', key: '$', keyCode: 52, shiftKey: true }, true, p => assert.strictEqual(p!.uc, 36))); }); + describe('ctrl+letter control characters', () => { + it('Ctrl+A produces 0x01', () => test({ code: 'KeyA', key: 'a', keyCode: 65, ctrlKey: true }, true, p => assert.strictEqual(p!.uc, 0x01))); + it('Ctrl+C produces 0x03 (ETX)', () => test({ code: 'KeyC', key: 'c', keyCode: 67, ctrlKey: true }, true, p => assert.strictEqual(p!.uc, 0x03))); + it('Ctrl+Z produces 0x1A', () => test({ code: 'KeyZ', key: 'z', keyCode: 90, ctrlKey: true }, true, p => assert.strictEqual(p!.uc, 0x1A))); + it('Ctrl+Shift+A (uppercase) produces 0x01', () => test({ code: 'KeyA', key: 'A', keyCode: 65, ctrlKey: true, shiftKey: true }, true, p => assert.strictEqual(p!.uc, 0x01))); + it('Ctrl+Shift+C (uppercase) produces 0x03', () => test({ code: 'KeyC', key: 'C', keyCode: 67, ctrlKey: true, shiftKey: true }, true, p => assert.strictEqual(p!.uc, 0x03))); + it('Ctrl+Alt+C does not produce control char', () => test({ code: 'KeyC', key: 'c', keyCode: 67, ctrlKey: true, altKey: true }, true, p => assert.strictEqual(p!.uc, 99))); + }); + describe('scan codes', () => { it('letter A', () => test({ code: 'KeyA', key: 'a', keyCode: 65 }, true, p => assert.strictEqual(p!.sc, 0x1E))); it('Escape', () => test({ code: 'Escape', key: 'Escape', keyCode: 27 }, true, p => assert.strictEqual(p!.sc, 0x01))); diff --git a/src/common/input/Win32InputMode.ts b/src/common/input/Win32InputMode.ts index c1c88cf268..f446e6b55c 100644 --- a/src/common/input/Win32InputMode.ts +++ b/src/common/input/Win32InputMode.ts @@ -186,7 +186,20 @@ function getScanCode(ev: IKeyboardEvent): number { function getUnicodeChar(ev: IKeyboardEvent): number { // Only single-character keys produce unicode output if (ev.key.length === 1) { - return ev.key.codePointAt(0) || 0; + const codePoint = ev.key.codePointAt(0) || 0; + + // Handle Ctrl+letter combinations - these produce control characters (0x01-0x1A) + if (ev.ctrlKey && !ev.altKey && !ev.metaKey) { + // Convert A-Z or a-z to control character (Ctrl+A = 0x01, Ctrl+C = 0x03, etc.) + if (codePoint >= 0x41 && codePoint <= 0x5A) { // A-Z + return codePoint - 0x40; + } + if (codePoint >= 0x61 && codePoint <= 0x7A) { // a-z + return codePoint - 0x60; + } + } + + return codePoint; } return 0; }