Do not report lock key presses without REPORT_ALL_KEYS in Kitty keyboard protocol

This commit is contained in:
Anthony Kim
2026-03-31 16:45:52 -07:00
parent ad730f2d54
commit 4a35a4880d
2 changed files with 40 additions and 0 deletions
+19
View File
@@ -506,6 +506,25 @@ describe('KittyKeyboard', () => {
const result = kitty.evaluate(createEvent({ key: 'Shift', code: 'ShiftLeft', shiftKey: false }), flags, KittyKeyboardEventType.RELEASE);
assert.strictEqual(result.key, undefined);
});
it('does not report CapsLock press without REPORT_ALL_KEYS_AS_ESCAPE_CODES', () => {
assert.strictEqual(kitty.evaluate(createEvent({ key: 'CapsLock', code: 'CapsLock' }), KittyKeyboardFlags.DISAMBIGUATE_ESCAPE_CODES).key, undefined);
assert.strictEqual(kitty.evaluate(createEvent({ key: 'CapsLock', code: 'CapsLock' }), KittyKeyboardFlags.REPORT_EVENT_TYPES).key, undefined);
assert.strictEqual(kitty.evaluate(createEvent({ key: 'CapsLock', code: 'CapsLock' }), KittyKeyboardFlags.DISAMBIGUATE_ESCAPE_CODES | KittyKeyboardFlags.REPORT_EVENT_TYPES).key, undefined);
});
it('does not report NumLock press without REPORT_ALL_KEYS_AS_ESCAPE_CODES', () => {
assert.strictEqual(kitty.evaluate(createEvent({ key: 'NumLock', code: 'NumLock' }), KittyKeyboardFlags.DISAMBIGUATE_ESCAPE_CODES).key, undefined);
});
it('does not report ScrollLock press without REPORT_ALL_KEYS_AS_ESCAPE_CODES', () => {
assert.strictEqual(kitty.evaluate(createEvent({ key: 'ScrollLock', code: 'ScrollLock' }), KittyKeyboardFlags.DISAMBIGUATE_ESCAPE_CODES).key, undefined);
});
it('does not report CapsLock release without REPORT_ALL_KEYS_AS_ESCAPE_CODES', () => {
const result = kitty.evaluate(createEvent({ key: 'CapsLock', code: 'CapsLock' }), flags, KittyKeyboardEventType.RELEASE);
assert.strictEqual(result.key, undefined);
});
});
describe('REPORT_ALL_KEYS_AS_ESCAPE_CODES flag', () => {
+21
View File
@@ -265,6 +265,19 @@ export class KittyKeyboard {
return ev.key === 'Shift' || ev.key === 'Control' || ev.key === 'Alt' || ev.key === 'Meta';
}
/**
* Check if a key is a lock key (CapsLock/NumLock/ScrollLock).
*
* Kitty's reference implementation classifies these as modifier keys for the
* purpose of suppressing press events (kitty/keys.c `is_modifier_key()`
* includes `GLFW_FKEY_CAPS_LOCK`, `GLFW_FKEY_SCROLL_LOCK`, `GLFW_FKEY_NUM_LOCK`),
* and its test suite asserts that a CapsLock press with no protocol flags
* produces empty output.
*/
private _isLockKey(ev: IKeyboardEvent): boolean {
return ev.key === 'CapsLock' || ev.key === 'NumLock' || ev.key === 'ScrollLock';
}
/**
* Build CSI letter sequence for arrow keys, Home, End.
* Format: CSI [1;mod] letter
@@ -422,6 +435,14 @@ export class KittyKeyboard {
return result;
}
// Spec § "Report all keys as escape codes": "Additionally, with this mode,
// events for pressing modifier keys are reported." — i.e. *without* this
// mode, modifier-key press events are suppressed. Kitty's is_modifier_key()
// treats CapsLock/NumLock/ScrollLock as modifier keys for this rule.
if (this._isLockKey(ev) && !(flags & KittyKeyboardFlags.REPORT_ALL_KEYS_AS_ESCAPE_CODES)) {
return result;
}
const csiLetter = this._csiLetterKeys[ev.key];
if (csiLetter) {
result.key = this._buildCsiLetterSequence(csiLetter, modifiers, eventType, reportEventTypes);