feat(tui): add legacy Alt+letter key sequence support

In legacy terminal mode (non-Kitty protocol), Alt+key is sent as ESC
followed by the key character. This was only supported for specific keys
(space, backspace, arrows) but not for regular letters.

Add support for Alt+letter sequences to enable keybindings like Alt+Y.
This commit is contained in:
Sviatoslav Abakumov 2026-01-17 16:28:13 +04:00 committed by Mario Zechner
parent 6b4b4f4fc3
commit bafddc27ed
2 changed files with 19 additions and 0 deletions

View file

@ -971,6 +971,11 @@ export function matchesKey(data: string, keyId: KeyId): boolean {
return data === `\x1b${rawCtrlChar(key)}`;
}
if (alt && !ctrl && !shift && !_kittyProtocolActive && key >= "a" && key <= "z") {
// Legacy: alt+letter is ESC followed by the letter
if (data === `\x1b${key}`) return true;
}
if (ctrl && !shift && !alt) {
const raw = rawCtrlChar(key);
if (data === raw) return true;
@ -1073,6 +1078,10 @@ export function parseKey(data: string): string | undefined {
if (code >= 1 && code <= 26) {
return `ctrl+alt+${String.fromCharCode(code + 96)}`;
}
// Legacy alt+letter (ESC followed by letter a-z)
if (code >= 97 && code <= 122) {
return `alt+${String.fromCharCode(code)}`;
}
}
if (data === "\x1b[A") return "up";
if (data === "\x1b[B") return "down";

View file

@ -149,6 +149,12 @@ describe("matchesKey", () => {
assert.strictEqual(parseKey("\x1bB"), "alt+left");
assert.strictEqual(matchesKey("\x1bF", "alt+right"), true);
assert.strictEqual(parseKey("\x1bF"), "alt+right");
assert.strictEqual(matchesKey("\x1ba", "alt+a"), true);
assert.strictEqual(parseKey("\x1ba"), "alt+a");
assert.strictEqual(matchesKey("\x1by", "alt+y"), true);
assert.strictEqual(parseKey("\x1by"), "alt+y");
assert.strictEqual(matchesKey("\x1bz", "alt+z"), true);
assert.strictEqual(parseKey("\x1bz"), "alt+z");
setKittyProtocolActive(true);
assert.strictEqual(matchesKey("\x1b ", "alt+space"), false);
@ -161,6 +167,10 @@ describe("matchesKey", () => {
assert.strictEqual(parseKey("\x1bB"), undefined);
assert.strictEqual(matchesKey("\x1bF", "alt+right"), false);
assert.strictEqual(parseKey("\x1bF"), undefined);
assert.strictEqual(matchesKey("\x1ba", "alt+a"), false);
assert.strictEqual(parseKey("\x1ba"), undefined);
assert.strictEqual(matchesKey("\x1by", "alt+y"), false);
assert.strictEqual(parseKey("\x1by"), undefined);
setKittyProtocolActive(false);
});