diff --git a/window/src/os/macos/window.rs b/window/src/os/macos/window.rs index 6daaa37fa..447ff9362 100644 --- a/window/src/os/macos/window.rs +++ b/window/src/os/macos/window.rs @@ -1084,6 +1084,7 @@ impl WindowView { .map(|kc| normalize_shifted_unmodified_key(kc, virtual_key)); match (&key, &raw) { + // Avoid eg: \x01 when we can use CTRL-A (KeyCode::Char(c), Some(raw)) if c.is_ascii_control() => (raw.clone(), None), _ => (key, raw), } diff --git a/window/src/os/wayland/window.rs b/window/src/os/wayland/window.rs index 4534fa606..221e9395f 100644 --- a/window/src/os/wayland/window.rs +++ b/window/src/os/wayland/window.rs @@ -298,35 +298,27 @@ impl Window { map_keyboard_auto_with_repeat( &seat, KeyRepeatKind::System, - move |event: KbEvent, _| { - println!("key event"); - match event { - KbEvent::Key { - rawkey, - keysym, - state, - utf8, - .. - } => { - Connection::with_window_inner(window_id, move |inner| { - inner.handle_key( - state == KeyState::Pressed, - rawkey, - keysym, - utf8.clone(), - ); - Ok(()) - }); - } - KbEvent::Modifiers { modifiers } => { - let mods = modifier_keys(modifiers); - Connection::with_window_inner(window_id, move |inner| { - inner.handle_modifiers(mods); - Ok(()) - }); - } - _ => {} + move |event: KbEvent, _| match event { + KbEvent::Key { + rawkey, + keysym, + state, + utf8, + .. + } => { + Connection::with_window_inner(window_id, move |inner| { + inner.handle_key(state == KeyState::Pressed, rawkey, keysym, utf8.clone()); + Ok(()) + }); } + KbEvent::Modifiers { modifiers } => { + let mods = modifier_keys(modifiers); + Connection::with_window_inner(window_id, move |inner| { + inner.handle_modifiers(mods); + Ok(()) + }); + } + _ => {} }, move |event: KeyRepeatEvent, _| { Connection::with_window_inner(window_id, move |inner| { @@ -363,18 +355,31 @@ impl Window { impl WindowInner { fn handle_key(&mut self, key_is_down: bool, rawkey: u32, keysym: u32, utf8: Option) { - let key = match utf8 { - Some(text) if text.chars().count() == 1 => KeyCode::Char(text.chars().nth(0).unwrap()), - Some(text) => KeyCode::Composed(text), - None => { - println!("no mapping for keysym {} and rawkey {}", keysym, rawkey); - return; + let raw_key = keysym_to_keycode(keysym); + let (key, raw_key) = match utf8 { + Some(text) if text.chars().count() == 1 => { + (KeyCode::Char(text.chars().nth(0).unwrap()), raw_key) } + Some(text) => (KeyCode::Composed(text), raw_key), + None => match raw_key { + Some(key) => (key, None), + None => { + println!("no mapping for keysym {:x} and rawkey {:x}", keysym, rawkey); + return; + } + }, + }; + // Avoid redundant key == raw_key + let (key, raw_key) = match (key, raw_key) { + // Avoid eg: \x01 when we can use CTRL-A + (KeyCode::Char(c), Some(raw)) if c.is_ascii_control() => (raw.clone(), None), + (key, Some(raw)) if key == raw => (key, None), + pair => pair, }; let key_event = KeyEvent { key_is_down, key, - raw_key: None, + raw_key, modifiers: self.modifiers, repeat_count: 1, }; diff --git a/window/src/os/xkeysyms.rs b/window/src/os/xkeysyms.rs index 7051125c1..30d54db25 100644 --- a/window/src/os/xkeysyms.rs +++ b/window/src/os/xkeysyms.rs @@ -28,6 +28,16 @@ pub fn modifiers_from_state(state: u16) -> Modifiers { /// for missing keys, look into `/usr/include/X11/keysymdef.h` /// and/or define them in KeyCode. pub fn keysym_to_keycode(keysym: u32) -> Option { + let utf32 = xkbcommon::xkb::keysym_to_utf32(keysym); + if utf32 >= 0x20 { + // Unsafety: this is ok because we trust that keysym_to_utf32 + // is only going to return valid utf32 codepoints. + // Note that keysym_to_utf32 returns 0 for no match. + unsafe { + return Some(KeyCode::Char(std::char::from_u32_unchecked(utf32))); + } + } + use xkbcommon::xkb::keysyms::*; #[allow(non_upper_case_globals)] Some(match keysym { @@ -42,6 +52,9 @@ pub fn keysym_to_keycode(keysym: u32) -> Option { KEY_Pause => KeyCode::Pause, KEY_Print => KeyCode::Print, + // latin-1 + i @ KEY_space..=KEY_ydiaeresis => KeyCode::Char(i as u8 as char), + // cursor movement KEY_Home => KeyCode::Home, KEY_End => KeyCode::End,