From 08bb0768ae224c8db04bbe016b050353ce13eee7 Mon Sep 17 00:00:00 2001 From: Ogulcan Celik Date: Mon, 15 Jun 2026 15:12:56 +0300 Subject: [PATCH] fix: handle kitty keypad input refs #570 --- docs/next/CHANGELOG.md | 1 + src/input/parse.rs | 40 +++++++++++++++++++++ tests/fixtures/keyboard_protocol_corpus.tsv | 18 ++++++++++ 3 files changed, 59 insertions(+) diff --git a/docs/next/CHANGELOG.md b/docs/next/CHANGELOG.md index 81b042e7..8f1c94da 100644 --- a/docs/next/CHANGELOG.md +++ b/docs/next/CHANGELOG.md @@ -33,6 +33,7 @@ - Claude Code session restore now accepts real `/clear`, `/resume`, and compacted session identity changes while still ignoring nested `claude -p` startup sessions that inherit the pane environment. (#620) - Auto-named tab labels now stay compact after closing, moving, or creating tabs while public tab ids remain stable. - F1-F4 key presses sent as `ESC[11~` through `ESC[14~` now reach pane apps instead of being dropped. (#574) +- Numeric keypad keys sent through the kitty keyboard protocol now enter their digits and operators instead of being dropped. (#570) ## [0.6.10] - 2026-06-11 diff --git a/src/input/parse.rs b/src/input/parse.rs index 11b873b6..bf377e88 100644 --- a/src/input/parse.rs +++ b/src/input/parse.rs @@ -253,6 +253,23 @@ fn kitty_codepoint_to_keycode(codepoint: u32) -> Option { 57362 => Some(KeyCode::Pause), 57363 => Some(KeyCode::Menu), 57376..=57398 => Some(KeyCode::F((codepoint - 57376 + 13) as u8)), + 57399 => Some(KeyCode::Char('0')), + 57400 => Some(KeyCode::Char('1')), + 57401 => Some(KeyCode::Char('2')), + 57402 => Some(KeyCode::Char('3')), + 57403 => Some(KeyCode::Char('4')), + 57404 => Some(KeyCode::Char('5')), + 57405 => Some(KeyCode::Char('6')), + 57406 => Some(KeyCode::Char('7')), + 57407 => Some(KeyCode::Char('8')), + 57408 => Some(KeyCode::Char('9')), + 57409 => Some(KeyCode::Char('.')), + 57410 => Some(KeyCode::Char('/')), + 57411 => Some(KeyCode::Char('*')), + 57412 => Some(KeyCode::Char('-')), + 57413 => Some(KeyCode::Char('+')), + 57415 => Some(KeyCode::Char('=')), + 57416 => Some(KeyCode::Char(',')), 57417 => Some(KeyCode::Left), 57418 => Some(KeyCode::Right), 57419 => Some(KeyCode::Up), @@ -731,6 +748,24 @@ mod tests { #[test] fn kitty_functional_key_matrix_is_covered() { let cases = [ + ("\x1b[57399;1u", KeyCode::Char('0')), + ("\x1b[57400;1u", KeyCode::Char('1')), + ("\x1b[57401;1u", KeyCode::Char('2')), + ("\x1b[57402;1u", KeyCode::Char('3')), + ("\x1b[57403;1u", KeyCode::Char('4')), + ("\x1b[57404;1u", KeyCode::Char('5')), + ("\x1b[57405;1u", KeyCode::Char('6')), + ("\x1b[57406;1u", KeyCode::Char('7')), + ("\x1b[57407;1u", KeyCode::Char('8')), + ("\x1b[57408;1u", KeyCode::Char('9')), + ("\x1b[57409;1u", KeyCode::Char('.')), + ("\x1b[57410;1u", KeyCode::Char('/')), + ("\x1b[57411;1u", KeyCode::Char('*')), + ("\x1b[57412;1u", KeyCode::Char('-')), + ("\x1b[57413;1u", KeyCode::Char('+')), + ("\x1b[57414;1u", KeyCode::Enter), + ("\x1b[57415;1u", KeyCode::Char('=')), + ("\x1b[57416;1u", KeyCode::Char(',')), ("\x1b[57417;1u", KeyCode::Left), ("\x1b[57418;1u", KeyCode::Right), ("\x1b[57419;1u", KeyCode::Up), @@ -755,6 +790,11 @@ mod tests { } } + #[test] + fn unknown_kitty_functional_key_remains_unsupported() { + assert!(parse_terminal_key_sequence("\x1b[57364;1u").is_none()); + } + fn assert_fixture_corpus_parses(corpus: &str) { for line in corpus.lines() { let line = line.trim(); diff --git a/tests/fixtures/keyboard_protocol_corpus.tsv b/tests/fixtures/keyboard_protocol_corpus.tsv index a709d4d9..bf9e7ff9 100644 --- a/tests/fixtures/keyboard_protocol_corpus.tsv +++ b/tests/fixtures/keyboard_protocol_corpus.tsv @@ -17,5 +17,23 @@ kitty_alt_backspace 1b5b3132373b3375 backspace alt press kitty_shift_letter 1b5b3130383a37363b323a3175 char:l shift press 76 kitty_shift_symbol 1b5b34393a33333b323a3175 char:1 shift press 33 kitty_release_letter 1b5b3130383a37363b323a3375 char:l shift release 76 +kitty_keypad_0 1b5b35373339393b3175 char:0 - press +kitty_keypad_1 1b5b35373430303b3175 char:1 - press +kitty_keypad_2 1b5b35373430313b3175 char:2 - press +kitty_keypad_3 1b5b35373430323b3175 char:3 - press +kitty_keypad_4 1b5b35373430333b3175 char:4 - press +kitty_keypad_5 1b5b35373430343b3175 char:5 - press +kitty_keypad_6 1b5b35373430353b3175 char:6 - press +kitty_keypad_7 1b5b35373430363b3175 char:7 - press +kitty_keypad_8 1b5b35373430373b3175 char:8 - press +kitty_keypad_9 1b5b35373430383b3175 char:9 - press +kitty_keypad_decimal 1b5b35373430393b3175 char:. - press +kitty_keypad_divide 1b5b35373431303b3175 char:/ - press +kitty_keypad_multiply 1b5b35373431313b3175 char:* - press +kitty_keypad_subtract 1b5b35373431323b3175 char:- - press +kitty_keypad_add 1b5b35373431333b3175 char:+ - press +kitty_keypad_enter 1b5b35373431343b3175 enter - press +kitty_keypad_equal 1b5b35373431353b3175 char:= - press +kitty_keypad_separator 1b5b35373431363b3175 char:, - press kitty_functional_up 1b5b35373431393b3175 up - press kitty_functional_home 1b5b35373432333b3175 home - press