diff options
| author | Can Celik <ogulcancelik@gmail.com> | 2026-08-29 00:06:44 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-08-29 00:06:44 +0300 |
| commit | c2637dc182ddc5425108824d5ed15d24ce38c4e3 (patch) | |
| tree | 70d2a45ed633ccca75495d040d9237df2b4f4157 /src/input | |
| parent | 82e6a80eb3ae39fb3d3ebd4d1fed19389767e605 (diff) | |
fix: handle associated text on special keys (#3350)
refs #3328
Diffstat (limited to 'src/input')
| -rw-r--r-- | src/input/parse.rs | 33 |
1 files changed, 31 insertions, 2 deletions
diff --git a/src/input/parse.rs b/src/input/parse.rs index ce87fd2f..15e0c6ad 100644 --- a/src/input/parse.rs +++ b/src/input/parse.rs @@ -203,7 +203,7 @@ fn parse_xterm_modified_special_sequence(data: &str) -> Option<TerminalKey> { let suffix_char = body.chars().last()?; if suffix_char.is_ascii_alphabetic() { let modifier_and_event = body.strip_suffix(suffix_char)?; - let (modifier_text, event_type) = split_modifier_and_event(modifier_and_event); + let (modifier_text, event_type) = split_xterm_modifier_and_event(modifier_and_event)?; let mod_value = modifier_text.parse::<u8>().ok()?.checked_sub(1)?; let code = match suffix_char { 'A' => KeyCode::Up, @@ -227,7 +227,7 @@ fn parse_xterm_modified_special_sequence(data: &str) -> Option<TerminalKey> { let tilde_body = body.strip_suffix('~')?; let (code_part, modifier_part) = tilde_body.split_once(';')?; - let (modifier_text, event_type) = split_modifier_and_event(modifier_part); + let (modifier_text, event_type) = split_xterm_modifier_and_event(modifier_part)?; let mod_value = modifier_text.parse::<u8>().ok()?.checked_sub(1)?; let code = match code_part { "2" => KeyCode::Insert, @@ -250,6 +250,19 @@ fn parse_xterm_modified_special_sequence(data: &str) -> Option<TerminalKey> { ) } +fn split_xterm_modifier_and_event(input: &str) -> Option<(&str, Option<&str>)> { + let modifier_and_event = + if let Some((modifier_and_event, associated_text)) = input.split_once(';') { + // Alacritty on macOS reports Cocoa function-key markers as associated + // text. The sequence final already identifies the key, so ignore them. + parse_kitty_associated_text(associated_text)?; + modifier_and_event + } else { + input + }; + Some(split_modifier_and_event(modifier_and_event)) +} + fn split_modifier_and_event(input: &str) -> (&str, Option<&str>) { match input.split_once(':') { Some((modifier, event)) if !modifier.is_empty() => (modifier, Some(event)), @@ -806,6 +819,22 @@ mod tests { } #[test] + fn parse_xterm_special_sequences_with_associated_text() { + for (sequence, expected_code) in [ + ("\x1b[1;1;63233B", KeyCode::Down), + ("\x1b[5;1;63276~", KeyCode::PageUp), + ] { + let key = parse_terminal_key_sequence(sequence).unwrap(); + assert_eq!(key.code, expected_code); + assert_eq!(key.modifiers, KeyModifiers::empty()); + assert_eq!(key.kind, crossterm::event::KeyEventKind::Press); + assert_eq!(key.generated_text, None); + } + + assert_eq!(parse_terminal_key_sequence("\x1b[1;1;63233;63234B"), None); + } + + #[test] fn parse_kitty_functional_up_arrow_sequence() { let key = parse_terminal_key_sequence("\x1b[57419;1u").unwrap(); assert_eq!(key.code, KeyCode::Up); |
