Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/browser/CoreBrowserTerminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
1 change: 1 addition & 0 deletions src/browser/services/Services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,4 +163,5 @@ export interface IKeyboardService {
evaluateKeyDown(event: KeyboardEvent): IKeyboardResult;
evaluateKeyUp(event: KeyboardEvent): IKeyboardResult | undefined;
readonly useKitty: boolean;
readonly useWin32InputMode: boolean;
}
9 changes: 9 additions & 0 deletions src/common/input/Win32InputMode.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
Expand Down
15 changes: 14 additions & 1 deletion src/common/input/Win32InputMode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Loading