diff --git a/core/src/keyboard/key.rs b/core/src/keyboard/key.rs index 8edb280c..5a1cd9ce 100644 --- a/core/src/keyboard/key.rs +++ b/core/src/keyboard/key.rs @@ -30,6 +30,91 @@ impl Key { Self::Unidentified => Key::Unidentified, } } + + /// Tries to convert this logical [`Key`] into its latin character, using the + /// [`Physical`] key provided for translation if it isn't already in latin. + /// + /// Returns `None` if no latin variant could be found. + /// + /// ``` + /// use iced_core::keyboard::key::{Key, Named, Physical, Code}; + /// + /// // Latin c + /// assert_eq!( + /// Key::Character("c".into()).to_latin(Physical::Code(Code::KeyC)), + /// Some('c'), + /// ); + /// + /// // Cyrillic с + /// assert_eq!( + /// Key::Character("с".into()).to_latin(Physical::Code(Code::KeyC)), + /// Some('c'), + /// ); + /// + /// // Arrow Left + /// assert_eq!( + /// Key::Named(Named::ArrowLeft).to_latin(Physical::Code(Code::ArrowLeft)), + /// None, + /// ); + /// ``` + pub fn to_latin(&self, physical_key: Physical) -> Option { + let Self::Character(s) = self else { + return None; + }; + + let mut chars = s.chars(); + let c = chars.next()?; + + if chars.next().is_none() && c <= '\u{ff}' { + return Some(c); + } + + let Physical::Code(code) = physical_key else { + return None; + }; + + let latin = match code { + Code::KeyA => 'a', + Code::KeyB => 'b', + Code::KeyC => 'c', + Code::KeyD => 'd', + Code::KeyE => 'e', + Code::KeyF => 'f', + Code::KeyG => 'g', + Code::KeyH => 'h', + Code::KeyI => 'i', + Code::KeyJ => 'j', + Code::KeyK => 'k', + Code::KeyL => 'l', + Code::KeyM => 'm', + Code::KeyN => 'n', + Code::KeyO => 'o', + Code::KeyP => 'p', + Code::KeyQ => 'q', + Code::KeyR => 'r', + Code::KeyS => 's', + Code::KeyT => 't', + Code::KeyU => 'u', + Code::KeyV => 'v', + Code::KeyW => 'w', + Code::KeyX => 'x', + Code::KeyY => 'y', + Code::KeyZ => 'z', + Code::Digit0 => '0', + Code::Digit1 => '1', + Code::Digit2 => '2', + Code::Digit3 => '3', + Code::Digit4 => '4', + Code::Digit5 => '5', + Code::Digit6 => '6', + Code::Digit7 => '7', + Code::Digit8 => '8', + Code::Digit9 => '9', + _ => return None, + }; + + Some(latin) + } } impl From for Key { diff --git a/widget/src/text_editor.rs b/widget/src/text_editor.rs index 0672bee0..ceddb89a 100644 --- a/widget/src/text_editor.rs +++ b/widget/src/text_editor.rs @@ -1160,6 +1160,10 @@ pub struct KeyPress { /// /// You should use this key for any single key bindings (e.g. motions). pub modified_key: keyboard::Key, + /// The physical key pressed. + /// + /// You should use this key for layout-independent bindings. + pub physical_key: keyboard::key::Physical, /// The state of the keyboard modifiers. pub modifiers: keyboard::Modifiers, /// The text produced by the key press. @@ -1174,6 +1178,7 @@ impl Binding { let KeyPress { key, modified_key, + physical_key, modifiers, text, status, @@ -1183,21 +1188,13 @@ impl Binding { return None; } - let combination = match key.as_ref() { - keyboard::Key::Character("c") if modifiers.command() => { - Some(Self::Copy) - } - keyboard::Key::Character("x") if modifiers.command() => { - Some(Self::Cut) - } - keyboard::Key::Character("v") - if modifiers.command() && !modifiers.alt() => - { + let combination = match key.to_latin(physical_key) { + Some('c') if modifiers.command() => Some(Self::Copy), + Some('x') if modifiers.command() => Some(Self::Cut), + Some('v') if modifiers.command() && !modifiers.alt() => { Some(Self::Paste) } - keyboard::Key::Character("a") if modifiers.command() => { - Some(Self::SelectAll) - } + Some('a') if modifiers.command() => Some(Self::SelectAll), _ => None, }; @@ -1359,6 +1356,7 @@ impl Update { Event::Keyboard(keyboard::Event::KeyPressed { key, modified_key, + physical_key, modifiers, text, .. @@ -1374,6 +1372,7 @@ impl Update { let key_press = KeyPress { key: key.clone(), modified_key: modified_key.clone(), + physical_key: *physical_key, modifiers: *modifiers, text: text.clone(), status, diff --git a/widget/src/text_input.rs b/widget/src/text_input.rs index 39880cc8..9c80dfd0 100644 --- a/widget/src/text_input.rs +++ b/widget/src/text_input.rs @@ -902,6 +902,7 @@ where key, text, modified_key, + physical_key, .. }) => { let state = state::(tree); @@ -909,8 +910,8 @@ where if let Some(focus) = &mut state.is_focused { let modifiers = state.keyboard_modifiers; - match key.as_ref() { - keyboard::Key::Character("c") + match key.to_latin(*physical_key) { + Some('c') if state.keyboard_modifiers.command() && !self.is_secure => { @@ -926,7 +927,7 @@ where shell.capture_event(); return; } - keyboard::Key::Character("x") + Some('x') if state.keyboard_modifiers.command() && !self.is_secure => { @@ -955,7 +956,7 @@ where update_cache(state, &self.value); return; } - keyboard::Key::Character("v") + Some('v') if state.keyboard_modifiers.command() && !state.keyboard_modifiers.alt() => { @@ -994,9 +995,7 @@ where update_cache(state, &self.value); return; } - keyboard::Key::Character("a") - if state.keyboard_modifiers.command() => - { + Some('a') if state.keyboard_modifiers.command() => { let cursor_before = state.cursor; state.cursor.select_all(&self.value);