Skip to content

Commit a3228bd

Browse files
authored
Merge pull request xtermjs#5604 from Tyriar/2357_2
Fix capital letters and ctrl+letter in win32-input-mode
2 parents f4c77d3 + a1fca4f commit a3228bd

File tree

4 files changed

+26
-3
lines changed

4 files changed

+26
-3
lines changed

src/browser/CoreBrowserTerminal.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,8 +1113,8 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
11131113

11141114
// HACK: Process A-Z in the keypress event to fix an issue with macOS IMEs where lower case
11151115
// letters cannot be input while caps lock is on. Skip this hack when using kitty protocol
1116-
// as it needs to send proper CSI u sequences for all key events.
1117-
if (!this._keyboardService.useKitty && event.key && !event.ctrlKey && !event.altKey && !event.metaKey && event.key.length === 1) {
1116+
// or Win32 input mode as they need to send proper sequences for all key events.
1117+
if (!this._keyboardService.useKitty && !this._keyboardService.useWin32InputMode && event.key && !event.ctrlKey && !event.altKey && !event.metaKey && event.key.length === 1) {
11181118
if (event.key.charCodeAt(0) >= 65 && event.key.charCodeAt(0) <= 90) {
11191119
return true;
11201120
}

src/browser/services/Services.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,4 +163,5 @@ export interface IKeyboardService {
163163
evaluateKeyDown(event: KeyboardEvent): IKeyboardResult;
164164
evaluateKeyUp(event: KeyboardEvent): IKeyboardResult | undefined;
165165
readonly useKitty: boolean;
166+
readonly useWin32InputMode: boolean;
166167
}

src/common/input/Win32InputMode.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,15 @@ describe('Win32InputMode', () => {
119119
it('symbol', () => test({ code: 'Digit4', key: '$', keyCode: 52, shiftKey: true }, true, p => assert.strictEqual(p!.uc, 36)));
120120
});
121121

122+
describe('ctrl+letter control characters', () => {
123+
it('Ctrl+A produces 0x01', () => test({ code: 'KeyA', key: 'a', keyCode: 65, ctrlKey: true }, true, p => assert.strictEqual(p!.uc, 0x01)));
124+
it('Ctrl+C produces 0x03 (ETX)', () => test({ code: 'KeyC', key: 'c', keyCode: 67, ctrlKey: true }, true, p => assert.strictEqual(p!.uc, 0x03)));
125+
it('Ctrl+Z produces 0x1A', () => test({ code: 'KeyZ', key: 'z', keyCode: 90, ctrlKey: true }, true, p => assert.strictEqual(p!.uc, 0x1A)));
126+
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)));
127+
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)));
128+
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)));
129+
});
130+
122131
describe('scan codes', () => {
123132
it('letter A', () => test({ code: 'KeyA', key: 'a', keyCode: 65 }, true, p => assert.strictEqual(p!.sc, 0x1E)));
124133
it('Escape', () => test({ code: 'Escape', key: 'Escape', keyCode: 27 }, true, p => assert.strictEqual(p!.sc, 0x01)));

src/common/input/Win32InputMode.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,20 @@ function getScanCode(ev: IKeyboardEvent): number {
186186
function getUnicodeChar(ev: IKeyboardEvent): number {
187187
// Only single-character keys produce unicode output
188188
if (ev.key.length === 1) {
189-
return ev.key.codePointAt(0) || 0;
189+
const codePoint = ev.key.codePointAt(0) || 0;
190+
191+
// Handle Ctrl+letter combinations - these produce control characters (0x01-0x1A)
192+
if (ev.ctrlKey && !ev.altKey && !ev.metaKey) {
193+
// Convert A-Z or a-z to control character (Ctrl+A = 0x01, Ctrl+C = 0x03, etc.)
194+
if (codePoint >= 0x41 && codePoint <= 0x5A) { // A-Z
195+
return codePoint - 0x40;
196+
}
197+
if (codePoint >= 0x61 && codePoint <= 0x7A) { // a-z
198+
return codePoint - 0x60;
199+
}
200+
}
201+
202+
return codePoint;
190203
}
191204
return 0;
192205
}

0 commit comments

Comments
 (0)