keyboard_codes/mapping/
standard.rs

1use crate::error::KeyParseError;
2use crate::types::{Key, Modifier, Platform};
3
4/// Standard key mapping table (string -> key -> multi-platform codes)
5/// Structure: (key_string, key_enum, windows_code, linux_code, macos_code)
6pub const STANDARD_KEY_MAPPINGS: &[(&str, Key, usize, usize, usize)] = &[
7    ("Escape", Key::Escape, 0x1B, 1, 53),
8    ("Enter", Key::Enter, 0x0D, 28, 36),
9    ("Tab", Key::Tab, 0x09, 15, 48),
10    ("Backspace", Key::Backspace, 0x08, 14, 51),
11    ("Space", Key::Space, 0x20, 57, 49),
12    ("Insert", Key::Insert, 0x2D, 110, 114),
13    ("Delete", Key::Delete, 0x2E, 111, 117),
14    ("Home", Key::Home, 0x24, 102, 115),
15    ("End", Key::End, 0x23, 107, 119),
16    ("PageUp", Key::PageUp, 0x21, 104, 116),
17    ("PageDown", Key::PageDown, 0x22, 109, 121),
18    ("ArrowLeft", Key::ArrowLeft, 0x25, 105, 123),
19    ("ArrowUp", Key::ArrowUp, 0x26, 103, 126),
20    ("ArrowRight", Key::ArrowRight, 0x27, 106, 124),
21    ("ArrowDown", Key::ArrowDown, 0x28, 108, 125),
22    ("A", Key::A, 0x41, 30, 0),
23    ("B", Key::B, 0x42, 48, 11),
24    ("C", Key::C, 0x43, 46, 8),
25    ("D", Key::D, 0x44, 32, 2),
26    ("E", Key::E, 0x45, 18, 14),
27    ("F", Key::F, 0x46, 33, 3),
28    ("G", Key::G, 0x47, 34, 5),
29    ("H", Key::H, 0x48, 35, 4),
30    ("I", Key::I, 0x49, 23, 34),
31    ("J", Key::J, 0x4A, 36, 38),
32    ("K", Key::K, 0x4B, 37, 40),
33    ("L", Key::L, 0x4C, 38, 37),
34    ("M", Key::M, 0x4D, 50, 46),
35    ("N", Key::N, 0x4E, 49, 45),
36    ("O", Key::O, 0x4F, 24, 31),
37    ("P", Key::P, 0x50, 25, 35),
38    ("Q", Key::Q, 0x51, 16, 12),
39    ("R", Key::R, 0x52, 19, 15),
40    ("S", Key::S, 0x53, 31, 1),
41    ("T", Key::T, 0x54, 20, 17),
42    ("U", Key::U, 0x55, 22, 32),
43    ("V", Key::V, 0x56, 47, 9),
44    ("W", Key::W, 0x57, 17, 13),
45    ("X", Key::X, 0x58, 45, 7),
46    ("Y", Key::Y, 0x59, 21, 16),
47    ("Z", Key::Z, 0x5A, 44, 6),
48    ("D0", Key::D0, 0x30, 11, 29),
49    ("D1", Key::D1, 0x31, 2, 18),
50    ("D2", Key::D2, 0x32, 3, 19),
51    ("D3", Key::D3, 0x33, 4, 20),
52    ("D4", Key::D4, 0x34, 5, 21),
53    ("D5", Key::D5, 0x35, 6, 23),
54    ("D6", Key::D6, 0x36, 7, 22),
55    ("D7", Key::D7, 0x37, 8, 26),
56    ("D8", Key::D8, 0x38, 9, 28),
57    ("D9", Key::D9, 0x39, 10, 25),
58    ("Num0", Key::Num0, 0x60, 82, 82),
59    ("Num1", Key::Num1, 0x61, 79, 83),
60    ("Num2", Key::Num2, 0x62, 80, 84),
61    ("Num3", Key::Num3, 0x63, 81, 85),
62    ("Num4", Key::Num4, 0x64, 75, 86),
63    ("Num5", Key::Num5, 0x65, 76, 87),
64    ("Num6", Key::Num6, 0x66, 77, 88),
65    ("Num7", Key::Num7, 0x67, 71, 89),
66    ("Num8", Key::Num8, 0x68, 72, 91),
67    ("Num9", Key::Num9, 0x69, 73, 92),
68    ("NumMultiply", Key::NumMultiply, 0x6A, 55, 67),
69    ("NumAdd", Key::NumAdd, 0x6B, 78, 69),
70    ("NumSubtract", Key::NumSubtract, 0x6D, 74, 78),
71    ("NumDivide", Key::NumDivide, 0x6F, 53, 75),
72    ("NumDecimal", Key::NumDecimal, 0x6E, 83, 65),
73    ("F1", Key::F1, 0x70, 59, 122),
74    ("F2", Key::F2, 0x71, 60, 120),
75    ("F3", Key::F3, 0x72, 61, 99),
76    ("F4", Key::F4, 0x73, 62, 118),
77    ("F5", Key::F5, 0x74, 63, 96),
78    ("F6", Key::F6, 0x75, 64, 97),
79    ("F7", Key::F7, 0x76, 65, 98),
80    ("F8", Key::F8, 0x77, 66, 100),
81    ("F9", Key::F9, 0x78, 67, 101),
82    ("F10", Key::F10, 0x79, 68, 109),
83    ("F11", Key::F11, 0x7A, 87, 103),
84    ("F12", Key::F12, 0x7B, 88, 111),
85    ("F13", Key::F13, 0x7C, 183, 104),
86    ("F14", Key::F14, 0x7D, 184, 105),
87    ("F15", Key::F15, 0x7E, 185, 106),
88    ("F16", Key::F16, 0x7F, 186, 107),
89    ("F17", Key::F17, 0x80, 187, 108),
90    ("F18", Key::F18, 0x81, 188, 110),
91    ("F19", Key::F19, 0x82, 189, 112),
92    ("F20", Key::F20, 0x83, 190, 113),
93    ("F21", Key::F21, 0x84, 191, 102),
94    ("F22", Key::F22, 0x85, 192, 121),
95    ("F23", Key::F23, 0x86, 193, 122),
96    ("F24", Key::F24, 0x87, 194, 123),
97    ("CapsLock", Key::CapsLock, 0x14, 58, 57),
98    ("NumLock", Key::NumLock, 0x90, 69, 71),
99    ("ScrollLock", Key::ScrollLock, 0x91, 70, 72),
100    ("Pause", Key::Pause, 0x13, 119, 117),
101    ("Apps", Key::Apps, 0x5D, 135, 110),
102    ("Sleep", Key::Sleep, 0x5F, 142, 142),
103    ("MediaPlayPause", Key::MediaPlayPause, 0xB3, 164, 163),
104    ("MediaStop", Key::MediaStop, 0xB2, 165, 165),
105    ("MediaNext", Key::MediaNext, 0xB0, 163, 171),
106    ("MediaPrevious", Key::MediaPrevious, 0xB1, 166, 172),
107    ("VolumeUp", Key::VolumeUp, 0xAF, 123, 126),
108    ("VolumeDown", Key::VolumeDown, 0xAE, 122, 125),
109    ("VolumeMute", Key::VolumeMute, 0xAD, 121, 127),
110    ("BrowserBack", Key::BrowserBack, 0xA6, 166, 178),
111    ("BrowserForward", Key::BrowserForward, 0xA7, 167, 179),
112    ("BrowserRefresh", Key::BrowserRefresh, 0xA8, 168, 177),
113    ("BrowserHome", Key::BrowserHome, 0xAC, 178, 174),
114];
115
116/// Standard modifier key mapping table
117pub const STANDARD_MODIFIER_MAPPINGS: &[(&str, Modifier, usize, usize, usize)] = &[
118    ("Alt", Modifier::Alt, 0x12, 56, 61),
119    ("Control", Modifier::Control, 0x11, 29, 59),
120    ("Shift", Modifier::Shift, 0x10, 42, 60),
121    ("Meta", Modifier::Meta, 0x5B, 125, 55),
122    ("LeftAlt", Modifier::LeftAlt, 0xA4, 56, 61),
123    ("RightAlt", Modifier::RightAlt, 0xA5, 100, 61),
124    ("LeftControl", Modifier::LeftControl, 0xA2, 29, 59),
125    ("RightControl", Modifier::RightControl, 0xA3, 97, 59),
126    ("LeftShift", Modifier::LeftShift, 0xA0, 42, 60),
127    ("RightShift", Modifier::RightShift, 0xA1, 54, 60),
128    ("LeftMeta", Modifier::LeftMeta, 0x5B, 125, 55),
129    ("RightMeta", Modifier::RightMeta, 0x5C, 126, 55),
130];
131
132/// Parse a key from a string using standard mappings (case-sensitive)
133pub fn parse_key_from_str(s: &str) -> Result<Key, KeyParseError> {
134    STANDARD_KEY_MAPPINGS
135        .iter()
136        .find(|(name, _, _, _, _)| *name == s)
137        .map(|(_, key, _, _, _)| *key)
138        .ok_or_else(|| KeyParseError::UnknownKey(s.to_string()))
139}
140
141/// Parse a modifier from a string using standard mappings (case-sensitive)
142pub fn parse_modifier_from_str(s: &str) -> Result<Modifier, KeyParseError> {
143    STANDARD_MODIFIER_MAPPINGS
144        .iter()
145        .find(|(name, _, _, _, _)| *name == s)
146        .map(|(_, modifier, _, _, _)| *modifier)
147        .ok_or_else(|| KeyParseError::UnknownModifier(s.to_string()))
148}
149
150/// Parse a key from a string with case-insensitive support
151pub fn parse_key_ignore_case(s: &str) -> Result<Key, KeyParseError> {
152    STANDARD_KEY_MAPPINGS
153        .iter()
154        .find(|(name, _, _, _, _)| name.eq_ignore_ascii_case(s))
155        .map(|(_, key, _, _, _)| *key)
156        .ok_or_else(|| KeyParseError::UnknownKey(s.to_string()))
157}
158
159/// Parse a modifier from a string with case-insensitive support
160pub fn parse_modifier_ignore_case(s: &str) -> Result<Modifier, KeyParseError> {
161    STANDARD_MODIFIER_MAPPINGS
162        .iter()
163        .find(|(name, _, _, _, _)| name.eq_ignore_ascii_case(s))
164        .map(|(_, modifier, _, _, _)| *modifier)
165        .ok_or_else(|| KeyParseError::UnknownModifier(s.to_string()))
166}
167
168/// Convert a key to a platform-specific code using standard mappings
169pub fn key_to_code(key: Key, platform: Platform) -> usize {
170    STANDARD_KEY_MAPPINGS
171        .iter()
172        .find(|(_, k, _, _, _)| k == &key)
173        .map(|(_, _, win, linux, mac)| match platform {
174            Platform::Windows => *win,
175            Platform::Linux => *linux,
176            Platform::MacOS => *mac,
177        })
178        .unwrap_or_else(|| panic!("Unsupported key in standard mapping: {:?}", key))
179}
180
181/// Convert a modifier to a platform-specific code using standard mappings
182pub fn modifier_to_code(modifier: Modifier, platform: Platform) -> usize {
183    STANDARD_MODIFIER_MAPPINGS
184        .iter()
185        .find(|(_, m, _, _, _)| m == &modifier)
186        .map(|(_, _, win, linux, mac)| match platform {
187            Platform::Windows => *win,
188            Platform::Linux => *linux,
189            Platform::MacOS => *mac,
190        })
191        .unwrap_or_else(|| panic!("Unsupported modifier in standard mapping: {:?}", modifier))
192}
193
194/// Parse a key from a platform-specific code using standard mappings
195pub fn key_from_code(code: usize, platform: Platform) -> Option<Key> {
196    STANDARD_KEY_MAPPINGS
197        .iter()
198        .find(|(_, _, win, linux, mac)| match platform {
199            Platform::Windows => *win == code,
200            Platform::Linux => *linux == code,
201            Platform::MacOS => *mac == code,
202        })
203        .map(|(_, key, _, _, _)| *key)
204}
205
206/// Parse a modifier from a platform-specific code using standard mappings
207pub fn modifier_from_code(code: usize, platform: Platform) -> Option<Modifier> {
208    STANDARD_MODIFIER_MAPPINGS
209        .iter()
210        .find(|(_, _, win, linux, mac)| match platform {
211            Platform::Windows => *win == code,
212            Platform::Linux => *linux == code,
213            Platform::MacOS => *mac == code,
214        })
215        .map(|(_, modifier, _, _, _)| *modifier)
216}
217
218// Implement KeyCodeMapper for Key
219impl crate::types::KeyCodeMapper for Key {
220    fn to_code(&self, platform: Platform) -> usize {
221        key_to_code(*self, platform)
222    }
223
224    fn from_code(code: usize, platform: Platform) -> Option<Self> {
225        key_from_code(code, platform)
226    }
227}
228
229// Implement KeyCodeMapper for Modifier
230impl crate::types::KeyCodeMapper for Modifier {
231    fn to_code(&self, platform: Platform) -> usize {
232        modifier_to_code(*self, platform)
233    }
234
235    fn from_code(code: usize, platform: Platform) -> Option<Self> {
236        modifier_from_code(code, platform)
237    }
238}
239
240#[cfg(test)]
241mod tests {
242    use super::*;
243
244    #[test]
245    fn test_parse_key_from_str() {
246        assert_eq!(parse_key_from_str("Escape").unwrap(), Key::Escape);
247        assert_eq!(parse_key_from_str("A").unwrap(), Key::A);
248        assert!(parse_key_from_str("UnknownKey").is_err());
249    }
250
251    #[test]
252    fn test_parse_modifier_from_str() {
253        assert_eq!(parse_modifier_from_str("Shift").unwrap(), Modifier::Shift);
254        assert_eq!(
255            parse_modifier_from_str("Control").unwrap(),
256            Modifier::Control
257        );
258        assert!(parse_modifier_from_str("UnknownModifier").is_err());
259    }
260
261    #[test]
262    fn test_parse_key_ignore_case() {
263        assert_eq!(parse_key_ignore_case("escape").unwrap(), Key::Escape);
264        assert_eq!(parse_key_ignore_case("ESCAPE").unwrap(), Key::Escape);
265        assert_eq!(parse_key_ignore_case("Escape").unwrap(), Key::Escape);
266        assert_eq!(parse_key_ignore_case("a").unwrap(), Key::A);
267        assert_eq!(parse_key_ignore_case("A").unwrap(), Key::A);
268    }
269
270    #[test]
271    fn test_parse_modifier_ignore_case() {
272        assert_eq!(
273            parse_modifier_ignore_case("shift").unwrap(),
274            Modifier::Shift
275        );
276        assert_eq!(
277            parse_modifier_ignore_case("SHIFT").unwrap(),
278            Modifier::Shift
279        );
280        assert_eq!(
281            parse_modifier_ignore_case("Shift").unwrap(),
282            Modifier::Shift
283        );
284        assert_eq!(
285            parse_modifier_ignore_case("control").unwrap(),
286            Modifier::Control
287        );
288        assert_eq!(
289            parse_modifier_ignore_case("CONTROL").unwrap(),
290            Modifier::Control
291        );
292    }
293
294    #[test]
295    fn test_key_to_code() {
296        assert_eq!(key_to_code(Key::Enter, Platform::Windows), 0x0D);
297        assert_eq!(key_to_code(Key::Enter, Platform::Linux), 28);
298        assert_eq!(key_to_code(Key::Enter, Platform::MacOS), 36);
299    }
300
301    #[test]
302    fn test_key_from_code() {
303        assert_eq!(key_from_code(0x1B, Platform::Windows), Some(Key::Escape));
304        assert_eq!(key_from_code(1, Platform::Linux), Some(Key::Escape));
305        assert_eq!(key_from_code(53, Platform::MacOS), Some(Key::Escape));
306    }
307
308    #[test]
309    fn test_key_code_mapper_impl() {
310        use crate::types::KeyCodeMapper;
311
312        let key = Key::Enter;
313        assert_eq!(key.to_code(Platform::Windows), 0x0D);
314        assert_eq!(Key::from_code(0x0D, Platform::Windows), Some(Key::Enter));
315    }
316}