diff --git a/crates/gpui/src/platform/linux/keyboard.rs b/crates/gpui/src/platform/linux/keyboard.rs index 968132c1afa6a809519c30e5bc5cc928961d6a03..733005a953c136546683279aa0284962f6cf2d97 100644 --- a/crates/gpui/src/platform/linux/keyboard.rs +++ b/crates/gpui/src/platform/linux/keyboard.rs @@ -1,7 +1,7 @@ #[cfg(any(feature = "wayland", feature = "x11"))] use collections::{HashMap, HashSet}; #[cfg(any(feature = "wayland", feature = "x11"))] -use xkbcommon::xkb::Keycode; +use xkbcommon::xkb::{Keycode, Keysym}; use crate::{PlatformKeyboardLayout, SharedString}; @@ -48,11 +48,26 @@ impl LinuxKeyboardMapper { for &scan_code in TYPEABLE_CODES { let keycode = Keycode::new(scan_code); let key = xkb_state.key_get_utf8(keycode); - code_to_key.insert(keycode, key.clone()); - inserted.insert(key); - let shifted_key = shifted_state.key_get_utf8(keycode); - code_to_shifted_key.insert(keycode, shifted_key); + if !key.is_empty() { + code_to_key.insert(keycode, key.clone()); + inserted.insert(key); + + let shifted_key = shifted_state.key_get_utf8(keycode); + code_to_shifted_key.insert(keycode, shifted_key); + } else { + // keycode might be a dead key + let keysym = xkb_state.key_get_one_sym(keycode); + if let Some(key) = underlying_dead_key(keysym) { + code_to_key.insert(keycode, key.clone()); + inserted.insert(key); + } + + let shifted_keysym = shifted_state.key_get_one_sym(keycode); + if let Some(shifted_key) = underlying_dead_key(shifted_keysym) { + code_to_shifted_key.insert(keycode, shifted_key); + } + } } insert_letters_if_missing(&inserted, &mut code_to_key); @@ -109,6 +124,66 @@ fn is_alphabetic_key(keycode: Keycode) -> bool { ) } +/** + * Returns which symbol the dead key represents + * + */ +#[cfg(any(feature = "wayland", feature = "x11"))] +pub(crate) fn underlying_dead_key(keysym: Keysym) -> Option { + match keysym { + Keysym::dead_grave => Some("`".to_owned()), + Keysym::dead_acute => Some("´".to_owned()), + Keysym::dead_circumflex => Some("^".to_owned()), + Keysym::dead_tilde => Some("~".to_owned()), + Keysym::dead_macron => Some("¯".to_owned()), + Keysym::dead_breve => Some("˘".to_owned()), + Keysym::dead_abovedot => Some("˙".to_owned()), + Keysym::dead_diaeresis => Some("¨".to_owned()), + Keysym::dead_abovering => Some("˚".to_owned()), + Keysym::dead_doubleacute => Some("˝".to_owned()), + Keysym::dead_caron => Some("ˇ".to_owned()), + Keysym::dead_cedilla => Some("¸".to_owned()), + Keysym::dead_ogonek => Some("˛".to_owned()), + Keysym::dead_iota => Some("ͅ".to_owned()), + Keysym::dead_voiced_sound => Some("゙".to_owned()), + Keysym::dead_semivoiced_sound => Some("゚".to_owned()), + Keysym::dead_belowdot => Some("̣̣".to_owned()), + Keysym::dead_hook => Some("̡".to_owned()), + Keysym::dead_horn => Some("̛".to_owned()), + Keysym::dead_stroke => Some("̶̶".to_owned()), + Keysym::dead_abovecomma => Some("̓̓".to_owned()), + Keysym::dead_abovereversedcomma => Some("ʽ".to_owned()), + Keysym::dead_doublegrave => Some("̏".to_owned()), + Keysym::dead_belowring => Some("˳".to_owned()), + Keysym::dead_belowmacron => Some("̱".to_owned()), + Keysym::dead_belowcircumflex => Some("ꞈ".to_owned()), + Keysym::dead_belowtilde => Some("̰".to_owned()), + Keysym::dead_belowbreve => Some("̮".to_owned()), + Keysym::dead_belowdiaeresis => Some("̤".to_owned()), + Keysym::dead_invertedbreve => Some("̯".to_owned()), + Keysym::dead_belowcomma => Some("̦".to_owned()), + Keysym::dead_currency => None, + Keysym::dead_lowline => None, + Keysym::dead_aboveverticalline => None, + Keysym::dead_belowverticalline => None, + Keysym::dead_longsolidusoverlay => None, + Keysym::dead_a => None, + Keysym::dead_A => None, + Keysym::dead_e => None, + Keysym::dead_E => None, + Keysym::dead_i => None, + Keysym::dead_I => None, + Keysym::dead_o => None, + Keysym::dead_O => None, + Keysym::dead_u => None, + Keysym::dead_U => None, + Keysym::dead_small_schwa => Some("ə".to_owned()), + Keysym::dead_capital_schwa => Some("Ə".to_owned()), + Keysym::dead_greek => None, + _ => None, + } +} + #[cfg(any(feature = "wayland", feature = "x11"))] macro_rules! insert_letters_if_missing_internal { ($inserted:expr, $code_to_key:expr, $code:expr, $key:literal) => {