try add a test

Junkui Zhang created

Change summary

crates/gpui/src/platform/linux/keyboard.rs | 161 ++++++++++++++++++++++++
1 file changed, 161 insertions(+)

Detailed changes

crates/gpui/src/platform/linux/keyboard.rs 🔗

@@ -1,6 +1,8 @@
 #[cfg(any(feature = "wayland", feature = "x11"))]
 use collections::{HashMap, HashSet};
 #[cfg(any(feature = "wayland", feature = "x11"))]
+use strum::EnumIter;
+#[cfg(any(feature = "wayland", feature = "x11"))]
 use xkbcommon::xkb::{Keycode, Keysym};
 
 use crate::{PlatformKeyboardLayout, SharedString};
@@ -226,6 +228,118 @@ fn insert_letters_if_missing(
     insert_letters_if_missing_internal!(inserted, code_to_key, Keycode::new(0x0034), "z");
 }
 
+#[cfg(any(feature = "wayland", feature = "x11"))]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, EnumIter)]
+enum LinuxScanCodes {
+    A = 0x0026,
+    B = 0x0038,
+    C = 0x0036,
+    D = 0x0028,
+    E = 0x001a,
+    F = 0x0029,
+    G = 0x002a,
+    H = 0x002b,
+    I = 0x001f,
+    J = 0x002c,
+    K = 0x002d,
+    L = 0x002e,
+    M = 0x003a,
+    N = 0x0039,
+    O = 0x0020,
+    P = 0x0021,
+    Q = 0x0018,
+    R = 0x001b,
+    S = 0x0027,
+    T = 0x001c,
+    U = 0x001e,
+    V = 0x0037,
+    W = 0x0019,
+    X = 0x0035,
+    Y = 0x001d,
+    Z = 0x0034,
+    Digit0 = 0x0013,
+    Digit1 = 0x000a,
+    Digit2 = 0x000b,
+    Digit3 = 0x000c,
+    Digit4 = 0x000d,
+    Digit5 = 0x000e,
+    Digit6 = 0x000f,
+    Digit7 = 0x0010,
+    Digit8 = 0x0011,
+    Digit9 = 0x0012,
+    Backquote = 0x0031,
+    Minus = 0x0014,
+    Equal = 0x0015,
+    LeftBracket = 0x0022,
+    RightBracket = 0x0023,
+    Backslash = 0x0033,
+    Semicolon = 0x002f,
+    Quote = 0x0030,
+    Comma = 0x003b,
+    Period = 0x003c,
+    Slash = 0x003d,
+    IntlBackslash = 0x005e,
+    IntlRo = 0x0061,
+}
+
+#[cfg(any(feature = "wayland", feature = "x11"))]
+#[cfg(test)]
+impl LinuxScanCodes {
+    fn to_str(&self) -> &str {
+        match self {
+            LinuxScanCodes::A => "a",
+            LinuxScanCodes::B => "b",
+            LinuxScanCodes::C => "c",
+            LinuxScanCodes::D => "d",
+            LinuxScanCodes::E => "e",
+            LinuxScanCodes::F => "f",
+            LinuxScanCodes::G => "g",
+            LinuxScanCodes::H => "h",
+            LinuxScanCodes::I => "i",
+            LinuxScanCodes::J => "j",
+            LinuxScanCodes::K => "k",
+            LinuxScanCodes::L => "l",
+            LinuxScanCodes::M => "m",
+            LinuxScanCodes::N => "n",
+            LinuxScanCodes::O => "o",
+            LinuxScanCodes::P => "p",
+            LinuxScanCodes::Q => "q",
+            LinuxScanCodes::R => "r",
+            LinuxScanCodes::S => "s",
+            LinuxScanCodes::T => "t",
+            LinuxScanCodes::U => "u",
+            LinuxScanCodes::V => "v",
+            LinuxScanCodes::W => "w",
+            LinuxScanCodes::X => "x",
+            LinuxScanCodes::Y => "y",
+            LinuxScanCodes::Z => "z",
+            LinuxScanCodes::Digit0 => "0",
+            LinuxScanCodes::Digit1 => "1",
+            LinuxScanCodes::Digit2 => "2",
+            LinuxScanCodes::Digit3 => "3",
+            LinuxScanCodes::Digit4 => "4",
+            LinuxScanCodes::Digit5 => "5",
+            LinuxScanCodes::Digit6 => "6",
+            LinuxScanCodes::Digit7 => "7",
+            LinuxScanCodes::Digit8 => "8",
+            LinuxScanCodes::Digit9 => "9",
+            LinuxScanCodes::Backquote => "`",
+            LinuxScanCodes::Minus => "-",
+            LinuxScanCodes::Equal => "=",
+            LinuxScanCodes::LeftBracket => "[",
+            LinuxScanCodes::RightBracket => "]",
+            LinuxScanCodes::Backslash => "\\",
+            LinuxScanCodes::Semicolon => ";",
+            LinuxScanCodes::Quote => "'",
+            LinuxScanCodes::Comma => ",",
+            LinuxScanCodes::Period => ".",
+            LinuxScanCodes::Slash => "/",
+            LinuxScanCodes::IntlBackslash => "⧸",
+            LinuxScanCodes::IntlRo => "ʁ",
+        }
+    }
+}
+
 // All typeable scan codes for the standard US keyboard layout, ANSI104
 #[cfg(any(feature = "wayland", feature = "x11"))]
 const TYPEABLE_CODES: &[u32] = &[
@@ -276,4 +390,51 @@ const TYPEABLE_CODES: &[u32] = &[
     0x003b, // , Comma
     0x003c, // . Period
     0x003d, // / Slash
+    0x005e, // This key is typically located near LeftShift key, varies on international keyboards: Dan: <> Dutch: ][ Ger: <> UK: \|
+    0x0061, // Used for Brazilian /? and Japanese _ 'ro'.
 ];
+
+#[cfg(test)]
+mod tests {
+    use std::sync::LazyLock;
+
+    use strum::IntoEnumIterator;
+    use x11rb::{protocol::xkb::ConnectionExt as _, xcb_ffi::XCBConnection};
+    use xkbcommon::xkb::x11::ffi::{XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION};
+
+    use super::LinuxKeyboardMapper;
+
+    static XCB_CONNECTION: LazyLock<XCBConnection> =
+        LazyLock::new(|| XCBConnection::connect(None).unwrap().0);
+
+    fn create_test_mapper() -> LinuxKeyboardMapper {
+        let _ = XCB_CONNECTION
+            .xkb_use_extension(XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION)
+            .unwrap()
+            .reply()
+            .unwrap();
+        let xkb_context = xkbcommon::xkb::Context::new(xkbcommon::xkb::CONTEXT_NO_FLAGS);
+        let xkb_device_id = xkbcommon::xkb::x11::get_core_keyboard_device_id(&*XCB_CONNECTION);
+        let xkb_state = {
+            let xkb_keymap = xkbcommon::xkb::x11::keymap_new_from_device(
+                &xkb_context,
+                &*XCB_CONNECTION,
+                xkb_device_id,
+                xkbcommon::xkb::KEYMAP_COMPILE_NO_FLAGS,
+            );
+            xkbcommon::xkb::x11::state_new_from_device(&xkb_keymap, &*XCB_CONNECTION, xkb_device_id)
+        };
+        LinuxKeyboardMapper::new(&xkb_state)
+    }
+
+    #[test]
+    fn test_us_layout_mapper() {
+        let mapper = create_test_mapper();
+        for scan_code in super::LinuxScanCodes::iter() {
+            let keycode = xkbcommon::xkb::Keycode::new(scan_code as u32);
+            let key = mapper.get_key(keycode, &mut crate::Modifiers::default());
+            // assert_eq!(key, Some(scan_code.to_str().to_string()));
+            println!("Keycode: {:?}, Key: {:?}", keycode, key);
+        }
+    }
+}