Skip to content

Commit f15a790

Browse files
committed
Fix text-producing keys in Kitty keyboard REPORT_EVENT_TYPES mode
In REPORT_EVENT_TYPES mode (CSI > 3 u), text-producing keys like Shift+1 should send the actual character ('!') for PRESS events, not CSI u escape sequences. Only REPEAT and RELEASE events should use CSI u for text-producing keys, while function keys use CSI u for all event types. Fixes issue where Shift+1 was not outputting '!' character.
1 parent 34e0179 commit f15a790

2 files changed

Lines changed: 32 additions & 3 deletions

File tree

src/common/input/KittyKeyboard.test.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -453,9 +453,21 @@ describe('KittyKeyboard', () => {
453453
describe('event types (press/repeat/release)', () => {
454454
const flags = KittyKeyboardFlags.DISAMBIGUATE_ESCAPE_CODES | KittyKeyboardFlags.REPORT_EVENT_TYPES;
455455

456-
it('press event (default, no suffix)', () => {
456+
it('text-producing key uses legacy encoding in REPORT_EVENT_TYPES mode', () => {
457+
// Per spec: "In report event types mode, function keys are encoded as CSI u...
458+
// all other keys are encoded in legacy mode"
457459
const result = kitty.evaluate(createEvent({ key: 'a' }), flags, KittyKeyboardEventType.PRESS);
458-
assert.strictEqual(result.key, '\x1b[97u');
460+
assert.strictEqual(result.key, 'a');
461+
});
462+
463+
it('Shift+1 (text-producing) sends character in PRESS, CSI u in RELEASE', () => {
464+
// Regression test for issue where Shift+1 was not sending '!' character
465+
// PRESS event should send the character
466+
const pressResult = kitty.evaluate(createEvent({ key: '!', code: 'Digit1', shiftKey: true }), flags, KittyKeyboardEventType.PRESS);
467+
assert.strictEqual(pressResult.key, '!');
468+
// RELEASE event should send CSI u sequence
469+
const releaseResult = kitty.evaluate(createEvent({ key: '!', code: 'Digit1', shiftKey: true }), flags, KittyKeyboardEventType.RELEASE);
470+
assert.strictEqual(releaseResult.key, '\x1b[49;2:3u');
459471
});
460472

461473
it('press event explicit :1 when modifiers present', () => {

src/common/input/KittyKeyboard.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,24 @@ export class KittyKeyboard {
478478
if (flags & KittyKeyboardFlags.REPORT_ALL_KEYS_AS_ESCAPE_CODES) {
479479
useCsiU = true;
480480
} else if (reportEventTypes) {
481-
useCsiU = true;
481+
// In REPORT_EVENT_TYPES mode:
482+
// - Function keys always use CSI u (for all event types)
483+
// - Text-producing keys use legacy encoding for plain PRESS, but CSI u for:
484+
// - PRESS with modifiers (except plain Shift)
485+
// - REPEAT and RELEASE events
486+
if (isFunc) {
487+
useCsiU = true;
488+
} else {
489+
// For text-producing keys
490+
if (eventType !== KittyKeyboardEventType.PRESS) {
491+
// REPEAT and RELEASE always use CSI u
492+
useCsiU = true;
493+
} else if (modifiers > 0) {
494+
// PRESS with modifiers uses CSI u, except for plain Shift
495+
const plainShiftOnly = ev.shiftKey && !ev.ctrlKey && !ev.altKey && !ev.metaKey && ev.key.length === 1;
496+
useCsiU = !plainShiftOnly;
497+
}
498+
}
482499
} else if (flags & KittyKeyboardFlags.DISAMBIGUATE_ESCAPE_CODES) {
483500
// Per spec, Enter/Tab/Backspace "still generate the same bytes as in legacy
484501
// mode" and consider space to be a text-generating key, so these skip the isFunc fast-path

0 commit comments

Comments
 (0)