// SPDX-License-Identifier: AGPL-3.0-or-later pub const KEYSYM_TABLE: &[(u32, &str)] = &[ (0xff1b, "Escape"), (0xffbe, "F1"), (0xffbf, "F2"), (0xffc0, "F3"), (0xffc1, "F4"), (0xffc2, "F5"), (0xffc3, "F6"), (0xffc4, "F7"), (0xffc5, "F8"), (0xffc6, "F9"), (0xffc7, "F10"), (0xffc8, "F11"), (0xffc9, "F12"), (0xffca, "F13"), (0xffcb, "F14"), (0xffcc, "F15"), (0xffcd, "F16"), (0xffce, "F17"), (0xffcf, "F18"), (0xffd0, "F19"), (0xffd1, "F20"), (0xffd2, "F21"), (0xffd3, "F22"), (0xffd4, "F23"), (0xffd5, "F24"), (0xff61, "PrintScreen"), (0xff14, "ScrollLock"), (0xff13, "Pause"), (0xff7f, "NumLock"), (0xff67, "ContextMenu"), (0x0060, "Backquote"), (0x007e, "Backquote"), (0x0031, "1"), (0x0032, "2"), (0x0033, "3"), (0x0034, "4"), (0x0035, "5"), (0x0036, "6"), (0x0037, "7"), (0x0038, "8"), (0x0039, "9"), (0x0030, "0"), (0x002d, "Minus"), (0x003d, "Equal"), (0xff08, "Backspace"), (0xff09, "Tab"), (0x0071, "Q"), (0x0077, "W"), (0x0065, "E"), (0x0072, "R"), (0x0074, "T"), (0x0079, "Y"), (0x0075, "U"), (0x0069, "I"), (0x006f, "O"), (0x0070, "P"), (0x005b, "BracketLeft"), (0x005d, "BracketRight"), (0x005c, "Backslash"), (0xffe5, "CapsLock"), (0x0061, "A"), (0x0073, "S"), (0x0064, "D"), (0x0066, "F"), (0x0067, "G"), (0x0068, "H"), (0x006a, "J"), (0x006b, "K"), (0x006c, "L"), (0x003b, "Semicolon"), (0x0027, "Quote"), (0xff0d, "Enter"), (0xffe1, "ShiftLeft"), (0x007a, "Z"), (0x0078, "X"), (0x0063, "C"), (0x0076, "V"), (0x0062, "B"), (0x006e, "N"), (0x006d, "M"), (0x002c, "Comma"), (0x002e, "Period"), (0x002f, "Slash"), (0xffe2, "ShiftRight"), (0xffe3, "ControlLeft"), (0xffeb, "MetaLeft"), (0xffe9, "AltLeft"), (0x0020, "Space"), (0xffea, "AltRight"), (0xffec, "MetaRight"), (0xffe4, "ControlRight"), (0xff80, "Space"), (0xff89, "Tab"), (0xff8d, "NumpadEnter"), (0xffbd, "NumpadEqual"), (0xffaa, "NumpadMultiply"), (0xffab, "NumpadAdd"), (0xffac, "NumpadComma"), (0xffad, "NumpadSubtract"), (0xffae, "NumpadDecimal"), (0xffaf, "NumpadDivide"), (0xffb0, "Numpad0"), (0xffb1, "Numpad1"), (0xffb2, "Numpad2"), (0xffb3, "Numpad3"), (0xffb4, "Numpad4"), (0xffb5, "Numpad5"), (0xffb6, "Numpad6"), (0xffb7, "Numpad7"), (0xffb8, "Numpad8"), (0xffb9, "Numpad9"), (0xff51, "ArrowLeft"), (0xff52, "ArrowUp"), (0xff53, "ArrowRight"), (0xff54, "ArrowDown"), (0xff63, "Insert"), (0xffff, "Delete"), (0xff50, "Home"), (0xff57, "End"), (0xff55, "PageUp"), (0xff56, "PageDown"), (0x1008ff12, "AudioVolumeMute"), (0x1008ff11, "AudioVolumeDown"), (0x1008ff13, "AudioVolumeUp"), (0x1008ff17, "MediaTrackNext"), (0x1008ff16, "MediaTrackPrevious"), (0x1008ff15, "MediaStop"), (0x1008ff14, "MediaPlayPause"), (0x1008ff26, "BrowserBack"), (0x1008ff27, "BrowserForward"), (0x1008ff29, "BrowserRefresh"), (0x1008ff28, "BrowserStop"), (0x1008ff1b, "BrowserSearch"), (0x1008ff30, "BrowserFavorites"), (0x1008ff18, "BrowserHome"), (0x1008ff19, "LaunchMail"), (0x1008ff32, "LaunchMediaPlayer"), (0x1008ff41, "LaunchApp1"), (0x1008ff42, "LaunchApp2"), (0x1008ff2a, "Power"), (0x1008ff2f, "Sleep"), (0x1008ff2b, "WakeUp"), (0xff23, "Convert"), (0xff22, "NonConvert"), (0xff2d, "KanaMode"), (0xff31, "Lang1"), (0xff34, "Lang2"), ]; pub fn keysym_to_name(keysym: u32) -> Option<&'static str> { KEYSYM_TABLE .iter() .find(|(sym, _)| *sym == keysym) .map(|(_, name)| *name) } pub fn fallback_name(keysym: u32) -> String { format!("Key{keysym}") } #[cfg(test)] mod tests { use super::*; #[test] fn common_letters_map_to_single_letter_names() { assert_eq!(keysym_to_name(0x0061), Some("A")); assert_eq!(keysym_to_name(0x006d), Some("M")); assert_eq!(keysym_to_name(0x007a), Some("Z")); } #[test] fn modifier_keysyms_produce_side_distinguished_names() { assert_eq!(keysym_to_name(0xffe1), Some("ShiftLeft")); assert_eq!(keysym_to_name(0xffe2), Some("ShiftRight")); assert_eq!(keysym_to_name(0xffe3), Some("ControlLeft")); assert_eq!(keysym_to_name(0xffe9), Some("AltLeft")); assert_eq!(keysym_to_name(0xffeb), Some("MetaLeft")); } #[test] fn function_keys_f1_through_f12() { assert_eq!(keysym_to_name(0xffbe), Some("F1")); assert_eq!(keysym_to_name(0xffc9), Some("F12")); assert_eq!(keysym_to_name(0xff13), Some("Pause")); assert_eq!(keysym_to_name(0xffca), Some("F13")); assert_eq!(keysym_to_name(0xffb0), Some("Numpad0")); assert_eq!(keysym_to_name(0x1008ff12), Some("AudioVolumeMute")); assert_eq!(keysym_to_name(0x1008ff41), Some("LaunchApp1")); } #[test] fn arrows_and_editing_keys_round_trip() { assert_eq!(keysym_to_name(0xff51), Some("ArrowLeft")); assert_eq!(keysym_to_name(0xff56), Some("PageDown")); assert_eq!(keysym_to_name(0xffff), Some("Delete")); } #[test] fn unknown_keysym_falls_back_to_key_n() { assert!(keysym_to_name(0x12345).is_none()); assert_eq!(fallback_name(0x12345), "Key74565"); } #[test] fn no_distinct_names_share_a_keysym() { for (i, (sym_i, name_i)) in KEYSYM_TABLE.iter().enumerate() { for (sym_j, name_j) in &KEYSYM_TABLE[i + 1..] { if sym_i == sym_j { assert_eq!(name_i, name_j, "duplicate keysym {sym_i:#x}"); } } } } }