Skip to content

Commit 81ce3f5

Browse files
committed
Fix kitty keyboard "Report event types" behavior not matching spec
According to spec: - The Enter, Tab and Backspace keys will not have release events unless "Report all keys as escape codes" is also set. - Key events that result in text are reported as plain UTF-8 text, so events are not supported for them, unless the application requests "key report" mode. I checked kitty's behavior. While it does report release events for keys that result in text as CSI sequences, press and repeat events for these are reported as plain UTF-8 text. This commit changes Xterm.js to match this behavior.
1 parent 0911688 commit 81ce3f5

2 files changed

Lines changed: 70 additions & 5 deletions

File tree

src/common/input/KittyKeyboard.test.ts

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -453,26 +453,86 @@ 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('UTF-8 text press event', () => {
457457
const result = kitty.evaluate(createEvent({ key: 'a' }), flags, KittyKeyboardEventType.PRESS);
458-
assert.strictEqual(result.key, '\x1b[97u');
458+
assert.strictEqual(result.key, 'a');
459+
});
460+
461+
it('Escape key press event (default, no suffix)', () => {
462+
const result = kitty.evaluate(createEvent({ key: 'Escape' }), flags, KittyKeyboardEventType.PRESS);
463+
assert.strictEqual(result.key, '\x1b[27u');
464+
});
465+
466+
it('Enter key press event → legacy \\r', () => {
467+
const result = kitty.evaluate(createEvent({ key: 'Enter' }), flags, KittyKeyboardEventType.PRESS);
468+
assert.strictEqual(result.key, '\r');
469+
});
470+
471+
it('Tab key press event → legacy \\t', () => {
472+
const result = kitty.evaluate(createEvent({ key: 'Tab' }), flags, KittyKeyboardEventType.PRESS);
473+
assert.strictEqual(result.key, '\t');
474+
});
475+
476+
it('Backspace key press event → legacy \\x7f', () => {
477+
const result = kitty.evaluate(createEvent({ key: 'Backspace' }), flags, KittyKeyboardEventType.PRESS);
478+
assert.strictEqual(result.key, '\x7f');
459479
});
460480

461481
it('press event explicit :1 when modifiers present', () => {
462482
const result = kitty.evaluate(createEvent({ key: 'a', ctrlKey: true }), flags, KittyKeyboardEventType.PRESS);
463483
assert.strictEqual(result.key, '\x1b[97;5u');
464484
});
465485

466-
it('repeat event → :2 suffix', () => {
486+
it('UTF-8 text repeat event', () => {
467487
const result = kitty.evaluate(createEvent({ key: 'a' }), flags, KittyKeyboardEventType.REPEAT);
468-
assert.strictEqual(result.key, '\x1b[97;1:2u');
488+
assert.strictEqual(result.key, 'a');
489+
});
490+
491+
it('Escape key repeat event → :2 suffix', () => {
492+
const result = kitty.evaluate(createEvent({ key: 'Escape' }), flags, KittyKeyboardEventType.REPEAT);
493+
assert.strictEqual(result.key, '\x1b[27;1:2u');
494+
});
495+
496+
it('Enter key repeat event → legacy \\r', () => {
497+
const result = kitty.evaluate(createEvent({ key: 'Enter' }), flags, KittyKeyboardEventType.REPEAT);
498+
assert.strictEqual(result.key, '\r');
499+
});
500+
501+
it('Tab key repeat event → legacy \\t', () => {
502+
const result = kitty.evaluate(createEvent({ key: 'Tab' }), flags, KittyKeyboardEventType.REPEAT);
503+
assert.strictEqual(result.key, '\t');
504+
});
505+
506+
it('Backspace key repeat event → legacy \\x7f', () => {
507+
const result = kitty.evaluate(createEvent({ key: 'Backspace' }), flags, KittyKeyboardEventType.REPEAT);
508+
assert.strictEqual(result.key, '\x7f');
469509
});
470510

471511
it('release event → :3 suffix', () => {
472512
const result = kitty.evaluate(createEvent({ key: 'a' }), flags, KittyKeyboardEventType.RELEASE);
473513
assert.strictEqual(result.key, '\x1b[97;1:3u');
474514
});
475515

516+
it('Escape key release event → :3 suffix', () => {
517+
const result = kitty.evaluate(createEvent({ key: 'Escape' }), flags, KittyKeyboardEventType.RELEASE);
518+
assert.strictEqual(result.key, '\x1b[27;1:3u');
519+
});
520+
521+
it('Enter key release event is not reported', () => {
522+
const result = kitty.evaluate(createEvent({ key: 'Enter' }), flags, KittyKeyboardEventType.RELEASE);
523+
assert.strictEqual(result.key, undefined);
524+
});
525+
526+
it('Tab key release event is not reported', () => {
527+
const result = kitty.evaluate(createEvent({ key: 'Tab' }), flags, KittyKeyboardEventType.RELEASE);
528+
assert.strictEqual(result.key, undefined);
529+
});
530+
531+
it('Backspace key release event is not reported', () => {
532+
const result = kitty.evaluate(createEvent({ key: 'Backspace' }), flags, KittyKeyboardEventType.RELEASE);
533+
assert.strictEqual(result.key, undefined);
534+
});
535+
476536
it('release with modifier → mod:3', () => {
477537
const result = kitty.evaluate(createEvent({ key: 'a', ctrlKey: true }), flags, KittyKeyboardEventType.RELEASE);
478538
assert.strictEqual(result.key, '\x1b[97;5:3u');

src/common/input/KittyKeyboard.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,12 @@ export class KittyKeyboard {
477477

478478
if (flags & KittyKeyboardFlags.REPORT_ALL_KEYS_AS_ESCAPE_CODES) {
479479
useCsiU = true;
480-
} else if (reportEventTypes) {
480+
} else if (reportEventTypes && eventType === KittyKeyboardEventType.RELEASE) {
481+
// Per spec, Enter/Tab/Backspace will not have release events unless "Report all keys as
482+
// escape codes" (which is handled by the branch above) is also set.
483+
if (keyCode === 13 || keyCode === 9 || keyCode === 127) {
484+
return result;
485+
}
481486
useCsiU = true;
482487
} else if (flags & KittyKeyboardFlags.DISAMBIGUATE_ESCAPE_CODES) {
483488
// Per spec, Enter/Tab/Backspace "still generate the same bytes as in legacy

0 commit comments

Comments
 (0)