From edaa3a1a092763cb25fd9e21772c95ee56a75a15 Mon Sep 17 00:00:00 2001 From: Ogulcan Celik Date: Tue, 14 Apr 2026 01:04:51 +0300 Subject: fix unify app key normalization for enhanced keyboard reporting --- src/input/mod.rs | 5 ++++- src/input/model.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) (limited to 'src/input') diff --git a/src/input/mod.rs b/src/input/mod.rs index 109fd312..67e8a14d 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -8,7 +8,10 @@ pub use encode::encode_key; pub use encode::{ encode_cursor_key, encode_mouse_button, encode_mouse_scroll, encode_terminal_key, }; -pub use model::{KeyboardProtocol, MouseProtocolEncoding, MouseProtocolMode, TerminalKey}; +pub use model::{ + normalize_app_key_binding, KeyboardProtocol, MouseProtocolEncoding, MouseProtocolMode, + TerminalKey, +}; pub use parse::parse_terminal_key_sequence; #[cfg(test)] diff --git a/src/input/model.rs b/src/input/model.rs index 9339b965..5721f82b 100644 --- a/src/input/model.rs +++ b/src/input/model.rs @@ -1,5 +1,57 @@ use crossterm::event::{KeyCode, KeyEvent, KeyModifiers}; +pub fn normalize_app_key_binding( + code: KeyCode, + modifiers: KeyModifiers, + shifted_codepoint: Option, +) -> (KeyCode, KeyModifiers) { + let KeyCode::Char(raw_char) = code else { + return (code, modifiers); + }; + + let shifted_char = shifted_codepoint + .and_then(char::from_u32) + .or_else(|| modifiers.contains(KeyModifiers::SHIFT).then_some(raw_char)) + .and_then(shifted_printable_char); + + let normalized_char = shifted_char.unwrap_or(raw_char); + let mut normalized_modifiers = modifiers; + if shifted_char.is_some() { + normalized_modifiers.remove(KeyModifiers::SHIFT); + } + + (KeyCode::Char(normalized_char), normalized_modifiers) +} + +fn shifted_printable_char(ch: char) -> Option { + match ch { + 'a'..='z' => Some(ch.to_ascii_uppercase()), + 'A'..='Z' => Some(ch), + '`' | '~' => Some('~'), + '1' | '!' => Some('!'), + '2' | '@' => Some('@'), + '3' | '#' => Some('#'), + '4' | '$' => Some('$'), + '5' | '%' => Some('%'), + '6' | '^' => Some('^'), + '7' | '&' => Some('&'), + '8' | '*' => Some('*'), + '9' | '(' => Some('('), + '0' | ')' => Some(')'), + '-' | '_' => Some('_'), + '=' | '+' => Some('+'), + '[' | '{' => Some('{'), + ']' | '}' => Some('}'), + '\\' | '|' => Some('|'), + ';' | ':' => Some(':'), + '\'' | '"' => Some('"'), + ',' | '<' => Some('<'), + '.' | '>' => Some('>'), + '/' | '?' => Some('?'), + _ => None, + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct TerminalKey { pub code: KeyCode, -- cgit v1.2.3