@@ -1,7 +1,7 @@
#[cfg(any(feature = "wayland", feature = "x11"))]
use collections::{HashMap, HashSet};
#[cfg(any(feature = "wayland", feature = "x11"))]
-use strum::EnumIter;
+use strum::{EnumIter, IntoEnumIterator as _};
#[cfg(any(feature = "wayland", feature = "x11"))]
use xkbcommon::xkb::{Keycode, Keysym};
@@ -47,16 +47,13 @@ impl LinuxKeyboardMapper {
let shift_mask = 1 << shift_mod;
shifted_state.update_mask(shift_mask, 0, 0, 0, 0, 0);
- for &scan_code in TYPEABLE_CODES {
- let keycode = Keycode::new(scan_code);
- let key = xkb_state.key_get_utf8(keycode);
+ for scan_code in LinuxScanCodes::iter() {
+ let keycode = Keycode::new(scan_code as u32);
+ let key = xkb_state.key_get_utf8(keycode);
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);
@@ -64,7 +61,13 @@ impl LinuxKeyboardMapper {
code_to_key.insert(keycode, key.clone());
inserted.insert(key);
}
+ }
+ let shifted_key = shifted_state.key_get_utf8(keycode);
+ if !shifted_key.is_empty() {
+ code_to_shifted_key.insert(keycode, shifted_key);
+ } else {
+ // keycode might be a dead 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);
@@ -186,46 +189,18 @@ pub(crate) fn underlying_dead_key(keysym: Keysym) -> Option<String> {
}
}
-#[cfg(any(feature = "wayland", feature = "x11"))]
-macro_rules! insert_letters_if_missing_internal {
- ($inserted:expr, $code_to_key:expr, $code:expr, $key:literal) => {
- if !$inserted.contains($key) {
- $code_to_key.insert($code, $key.to_string());
- }
- };
-}
-
#[cfg(any(feature = "wayland", feature = "x11"))]
fn insert_letters_if_missing(
inserted: &HashSet<String>,
code_to_key: &mut HashMap<Keycode, String>,
) {
- insert_letters_if_missing_internal!(inserted, code_to_key, Keycode::new(0x0026), "a");
- insert_letters_if_missing_internal!(inserted, code_to_key, Keycode::new(0x0038), "b");
- insert_letters_if_missing_internal!(inserted, code_to_key, Keycode::new(0x0036), "c");
- insert_letters_if_missing_internal!(inserted, code_to_key, Keycode::new(0x0028), "d");
- insert_letters_if_missing_internal!(inserted, code_to_key, Keycode::new(0x001a), "e");
- insert_letters_if_missing_internal!(inserted, code_to_key, Keycode::new(0x0029), "f");
- insert_letters_if_missing_internal!(inserted, code_to_key, Keycode::new(0x002a), "g");
- insert_letters_if_missing_internal!(inserted, code_to_key, Keycode::new(0x002b), "h");
- insert_letters_if_missing_internal!(inserted, code_to_key, Keycode::new(0x001f), "i");
- insert_letters_if_missing_internal!(inserted, code_to_key, Keycode::new(0x002c), "j");
- insert_letters_if_missing_internal!(inserted, code_to_key, Keycode::new(0x002d), "k");
- insert_letters_if_missing_internal!(inserted, code_to_key, Keycode::new(0x002e), "l");
- insert_letters_if_missing_internal!(inserted, code_to_key, Keycode::new(0x003a), "m");
- insert_letters_if_missing_internal!(inserted, code_to_key, Keycode::new(0x0039), "n");
- insert_letters_if_missing_internal!(inserted, code_to_key, Keycode::new(0x0020), "o");
- insert_letters_if_missing_internal!(inserted, code_to_key, Keycode::new(0x0021), "p");
- insert_letters_if_missing_internal!(inserted, code_to_key, Keycode::new(0x0018), "q");
- insert_letters_if_missing_internal!(inserted, code_to_key, Keycode::new(0x001b), "r");
- insert_letters_if_missing_internal!(inserted, code_to_key, Keycode::new(0x0027), "s");
- insert_letters_if_missing_internal!(inserted, code_to_key, Keycode::new(0x001c), "t");
- insert_letters_if_missing_internal!(inserted, code_to_key, Keycode::new(0x001e), "u");
- insert_letters_if_missing_internal!(inserted, code_to_key, Keycode::new(0x0037), "v");
- insert_letters_if_missing_internal!(inserted, code_to_key, Keycode::new(0x0019), "w");
- insert_letters_if_missing_internal!(inserted, code_to_key, Keycode::new(0x0035), "x");
- insert_letters_if_missing_internal!(inserted, code_to_key, Keycode::new(0x001d), "y");
- insert_letters_if_missing_internal!(inserted, code_to_key, Keycode::new(0x0034), "z");
+ for scan_code in LinuxScanCodes::LETTERS.iter() {
+ let keycode = Keycode::new(*scan_code as u32);
+ let key = scan_code.to_str();
+ if !inserted.contains(key) {
+ code_to_key.insert(keycode, key.to_string());
+ }
+ }
}
#[cfg(any(feature = "wayland", feature = "x11"))]
@@ -278,13 +253,43 @@ enum LinuxScanCodes {
Comma = 0x003b,
Period = 0x003c,
Slash = 0x003d,
+ // This key is typically located near LeftShift key, varies on international keyboards: Dan: <> Dutch: ][ Ger: <> UK: \|
IntlBackslash = 0x005e,
+ // Used for Brazilian /? and Japanese _ 'ro'.
IntlRo = 0x0061,
}
#[cfg(any(feature = "wayland", feature = "x11"))]
-#[cfg(test)]
impl LinuxScanCodes {
+ const LETTERS: &'static [LinuxScanCodes] = &[
+ LinuxScanCodes::A,
+ LinuxScanCodes::B,
+ LinuxScanCodes::C,
+ LinuxScanCodes::D,
+ LinuxScanCodes::E,
+ LinuxScanCodes::F,
+ LinuxScanCodes::G,
+ LinuxScanCodes::H,
+ LinuxScanCodes::I,
+ LinuxScanCodes::J,
+ LinuxScanCodes::K,
+ LinuxScanCodes::L,
+ LinuxScanCodes::M,
+ LinuxScanCodes::N,
+ LinuxScanCodes::O,
+ LinuxScanCodes::P,
+ LinuxScanCodes::Q,
+ LinuxScanCodes::R,
+ LinuxScanCodes::S,
+ LinuxScanCodes::T,
+ LinuxScanCodes::U,
+ LinuxScanCodes::V,
+ LinuxScanCodes::W,
+ LinuxScanCodes::X,
+ LinuxScanCodes::Y,
+ LinuxScanCodes::Z,
+ ];
+
fn to_str(&self) -> &str {
match self {
LinuxScanCodes::A => "a",
@@ -334,67 +339,13 @@ impl LinuxScanCodes {
LinuxScanCodes::Comma => ",",
LinuxScanCodes::Period => ".",
LinuxScanCodes::Slash => "/",
- LinuxScanCodes::IntlBackslash => "⧸",
- LinuxScanCodes::IntlRo => "ʁ",
+ LinuxScanCodes::IntlBackslash => "unknown",
+ LinuxScanCodes::IntlRo => "unknown",
}
}
}
-// All typeable scan codes for the standard US keyboard layout, ANSI104
-#[cfg(any(feature = "wayland", feature = "x11"))]
-const TYPEABLE_CODES: &[u32] = &[
- 0x0026, // a
- 0x0038, // b
- 0x0036, // c
- 0x0028, // d
- 0x001a, // e
- 0x0029, // f
- 0x002a, // g
- 0x002b, // h
- 0x001f, // i
- 0x002c, // j
- 0x002d, // k
- 0x002e, // l
- 0x003a, // m
- 0x0039, // n
- 0x0020, // o
- 0x0021, // p
- 0x0018, // q
- 0x001b, // r
- 0x0027, // s
- 0x001c, // t
- 0x001e, // u
- 0x0037, // v
- 0x0019, // w
- 0x0035, // x
- 0x001d, // y
- 0x0034, // z
- 0x0013, // Digit 0
- 0x000a, // Digit 1
- 0x000b, // Digit 2
- 0x000c, // Digit 3
- 0x000d, // Digit 4
- 0x000e, // Digit 5
- 0x000f, // Digit 6
- 0x0010, // Digit 7
- 0x0011, // Digit 8
- 0x0012, // Digit 9
- 0x0031, // ` Backquote
- 0x0014, // - Minus
- 0x0015, // = Equal
- 0x0022, // [ Left bracket
- 0x0023, // ] Right bracket
- 0x0033, // \ Backslash
- 0x002f, // ; Semicolon
- 0x0030, // ' Quote
- 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)]
+#[cfg(all(test, any(feature = "wayland", feature = "x11")))]
mod tests {
use std::sync::LazyLock;
@@ -402,6 +353,8 @@ mod tests {
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 crate::platform::linux::keyboard::LinuxScanCodes;
+
use super::LinuxKeyboardMapper;
static XCB_CONNECTION: LazyLock<XCBConnection> =
@@ -431,10 +384,12 @@ mod tests {
fn test_us_layout_mapper() {
let mapper = create_test_mapper();
for scan_code in super::LinuxScanCodes::iter() {
+ if scan_code == LinuxScanCodes::IntlBackslash || scan_code == LinuxScanCodes::IntlRo {
+ continue;
+ }
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);
+ assert_eq!(key, Some(scan_code.to_str().to_string()));
}
}
}