lamco_rdp_input/
mapper.rs

1//! Scancode Mapping Tables
2//!
3//! Complete RDP scancode to Linux evdev keycode mapping for 200+ keys.
4//! Includes standard keys, extended keys, and international keyboard support.
5
6use crate::error::{InputError, Result};
7use std::collections::HashMap;
8
9/// Linux evdev keycodes
10pub mod keycodes {
11    // Primary keys
12    pub const KEY_ESC: u32 = 1;
13    pub const KEY_1: u32 = 2;
14    pub const KEY_2: u32 = 3;
15    pub const KEY_3: u32 = 4;
16    pub const KEY_4: u32 = 5;
17    pub const KEY_5: u32 = 6;
18    pub const KEY_6: u32 = 7;
19    pub const KEY_7: u32 = 8;
20    pub const KEY_8: u32 = 9;
21    pub const KEY_9: u32 = 10;
22    pub const KEY_0: u32 = 11;
23    pub const KEY_MINUS: u32 = 12;
24    pub const KEY_EQUAL: u32 = 13;
25    pub const KEY_BACKSPACE: u32 = 14;
26    pub const KEY_TAB: u32 = 15;
27    pub const KEY_Q: u32 = 16;
28    pub const KEY_W: u32 = 17;
29    pub const KEY_E: u32 = 18;
30    pub const KEY_R: u32 = 19;
31    pub const KEY_T: u32 = 20;
32    pub const KEY_Y: u32 = 21;
33    pub const KEY_U: u32 = 22;
34    pub const KEY_I: u32 = 23;
35    pub const KEY_O: u32 = 24;
36    pub const KEY_P: u32 = 25;
37    pub const KEY_LEFTBRACE: u32 = 26;
38    pub const KEY_RIGHTBRACE: u32 = 27;
39    pub const KEY_ENTER: u32 = 28;
40    pub const KEY_LEFTCTRL: u32 = 29;
41    pub const KEY_A: u32 = 30;
42    pub const KEY_S: u32 = 31;
43    pub const KEY_D: u32 = 32;
44    pub const KEY_F: u32 = 33;
45    pub const KEY_G: u32 = 34;
46    pub const KEY_H: u32 = 35;
47    pub const KEY_J: u32 = 36;
48    pub const KEY_K: u32 = 37;
49    pub const KEY_L: u32 = 38;
50    pub const KEY_SEMICOLON: u32 = 39;
51    pub const KEY_APOSTROPHE: u32 = 40;
52    pub const KEY_GRAVE: u32 = 41;
53    pub const KEY_LEFTSHIFT: u32 = 42;
54    pub const KEY_BACKSLASH: u32 = 43;
55    pub const KEY_Z: u32 = 44;
56    pub const KEY_X: u32 = 45;
57    pub const KEY_C: u32 = 46;
58    pub const KEY_V: u32 = 47;
59    pub const KEY_B: u32 = 48;
60    pub const KEY_N: u32 = 49;
61    pub const KEY_M: u32 = 50;
62    pub const KEY_COMMA: u32 = 51;
63    pub const KEY_DOT: u32 = 52;
64    pub const KEY_SLASH: u32 = 53;
65    pub const KEY_RIGHTSHIFT: u32 = 54;
66    pub const KEY_KPASTERISK: u32 = 55;
67    pub const KEY_LEFTALT: u32 = 56;
68    pub const KEY_SPACE: u32 = 57;
69    pub const KEY_CAPSLOCK: u32 = 58;
70
71    // Function keys
72    pub const KEY_F1: u32 = 59;
73    pub const KEY_F2: u32 = 60;
74    pub const KEY_F3: u32 = 61;
75    pub const KEY_F4: u32 = 62;
76    pub const KEY_F5: u32 = 63;
77    pub const KEY_F6: u32 = 64;
78    pub const KEY_F7: u32 = 65;
79    pub const KEY_F8: u32 = 66;
80    pub const KEY_F9: u32 = 67;
81    pub const KEY_F10: u32 = 68;
82    pub const KEY_NUMLOCK: u32 = 69;
83    pub const KEY_SCROLLLOCK: u32 = 70;
84
85    // Numpad
86    pub const KEY_KP7: u32 = 71;
87    pub const KEY_KP8: u32 = 72;
88    pub const KEY_KP9: u32 = 73;
89    pub const KEY_KPMINUS: u32 = 74;
90    pub const KEY_KP4: u32 = 75;
91    pub const KEY_KP5: u32 = 76;
92    pub const KEY_KP6: u32 = 77;
93    pub const KEY_KPPLUS: u32 = 78;
94    pub const KEY_KP1: u32 = 79;
95    pub const KEY_KP2: u32 = 80;
96    pub const KEY_KP3: u32 = 81;
97    pub const KEY_KP0: u32 = 82;
98    pub const KEY_KPDOT: u32 = 83;
99
100    pub const KEY_102ND: u32 = 86;
101    pub const KEY_F11: u32 = 87;
102    pub const KEY_F12: u32 = 88;
103    pub const KEY_RO: u32 = 89;
104    pub const KEY_KATAKANAHIRAGANA: u32 = 90;
105    pub const KEY_HENKAN: u32 = 92;
106    pub const KEY_MUHENKAN: u32 = 94;
107    pub const KEY_KPENTER: u32 = 96;
108    pub const KEY_RIGHTCTRL: u32 = 97;
109    pub const KEY_KPSLASH: u32 = 98;
110    pub const KEY_SYSRQ: u32 = 99;
111    pub const KEY_RIGHTALT: u32 = 100;
112    pub const KEY_HOME: u32 = 102;
113    pub const KEY_UP: u32 = 103;
114    pub const KEY_PAGEUP: u32 = 104;
115    pub const KEY_LEFT: u32 = 105;
116    pub const KEY_RIGHT: u32 = 106;
117    pub const KEY_END: u32 = 107;
118    pub const KEY_DOWN: u32 = 108;
119    pub const KEY_PAGEDOWN: u32 = 109;
120    pub const KEY_INSERT: u32 = 110;
121    pub const KEY_DELETE: u32 = 111;
122    pub const KEY_MUTE: u32 = 113;
123    pub const KEY_VOLUMEDOWN: u32 = 114;
124    pub const KEY_VOLUMEUP: u32 = 115;
125    pub const KEY_POWER: u32 = 116;
126    pub const KEY_KPEQUAL: u32 = 117;
127    pub const KEY_PAUSE: u32 = 119;
128    pub const KEY_KPCOMMA: u32 = 121;
129    pub const KEY_HANGEUL: u32 = 122;
130    pub const KEY_HANJA: u32 = 123;
131    pub const KEY_YEN: u32 = 124;
132    pub const KEY_LEFTMETA: u32 = 125;
133    pub const KEY_RIGHTMETA: u32 = 126;
134    pub const KEY_COMPOSE: u32 = 127;
135    pub const KEY_STOP: u32 = 128;
136    pub const KEY_AGAIN: u32 = 129;
137    pub const KEY_PROPS: u32 = 130;
138    pub const KEY_UNDO: u32 = 131;
139    pub const KEY_FRONT: u32 = 132;
140    pub const KEY_COPY: u32 = 133;
141    pub const KEY_OPEN: u32 = 134;
142    pub const KEY_PASTE: u32 = 135;
143    pub const KEY_FIND: u32 = 136;
144    pub const KEY_CUT: u32 = 137;
145    pub const KEY_HELP: u32 = 138;
146    pub const KEY_MENU: u32 = 139;
147    pub const KEY_CALC: u32 = 140;
148    pub const KEY_SLEEP: u32 = 142;
149    pub const KEY_WAKEUP: u32 = 143;
150    pub const KEY_WWW: u32 = 150;
151    pub const KEY_MAIL: u32 = 155;
152    pub const KEY_BOOKMARKS: u32 = 156;
153    pub const KEY_COMPUTER: u32 = 157;
154    pub const KEY_BACK: u32 = 158;
155    pub const KEY_FORWARD: u32 = 159;
156    pub const KEY_EJECTCD: u32 = 161;
157    pub const KEY_NEXTSONG: u32 = 163;
158    pub const KEY_PLAYPAUSE: u32 = 164;
159    pub const KEY_PREVIOUSSONG: u32 = 165;
160    pub const KEY_STOPCD: u32 = 166;
161    pub const KEY_REFRESH: u32 = 173;
162    pub const KEY_F13: u32 = 183;
163    pub const KEY_F14: u32 = 184;
164    pub const KEY_F15: u32 = 185;
165    pub const KEY_F16: u32 = 186;
166    pub const KEY_F17: u32 = 187;
167    pub const KEY_F18: u32 = 188;
168    pub const KEY_F19: u32 = 189;
169    pub const KEY_F20: u32 = 190;
170    pub const KEY_F21: u32 = 191;
171    pub const KEY_F22: u32 = 192;
172    pub const KEY_F23: u32 = 193;
173    pub const KEY_F24: u32 = 194;
174    pub const KEY_MEDIA: u32 = 226;
175    pub const KEY_SEARCH: u32 = 217;
176    pub const KEY_HOMEPAGE: u32 = 172;
177    pub const KEY_BREAK: u32 = 411;
178    pub const KEY_PRINT: u32 = 210;
179}
180
181#[allow(clippy::wildcard_imports)]
182use keycodes::*;
183
184/// Scancode mapper handles RDP scancode to evdev keycode translation
185pub struct ScancodeMapper {
186    /// Primary scancode map (0x00-0x7F)
187    primary_map: HashMap<u16, u32>,
188
189    /// Extended scancode map (0xE000-0xE0FF)
190    extended_map: HashMap<u16, u32>,
191
192    /// E1 prefix scancode map
193    e1_map: HashMap<u32, u32>,
194
195    /// Reverse map for keycode to scancode
196    reverse_map: HashMap<u32, u16>,
197
198    /// Layout-specific overrides
199    layout_overrides: HashMap<String, HashMap<u16, u32>>,
200
201    /// Current keyboard layout
202    current_layout: String,
203}
204
205impl ScancodeMapper {
206    /// Create a new scancode mapper
207    pub fn new() -> Self {
208        let mut mapper = Self {
209            primary_map: HashMap::new(),
210            extended_map: HashMap::new(),
211            e1_map: HashMap::new(),
212            reverse_map: HashMap::new(),
213            layout_overrides: HashMap::new(),
214            current_layout: "us".to_string(),
215        };
216
217        mapper.initialize_mappings();
218        mapper
219    }
220
221    /// Initialize all scancode mappings
222    fn initialize_mappings(&mut self) {
223        self.initialize_primary_map();
224        self.initialize_extended_map();
225        self.initialize_e1_map();
226        self.build_reverse_map();
227        self.load_layout_overrides();
228    }
229
230    /// Initialize primary scancode map (0x00-0x7F)
231    fn initialize_primary_map(&mut self) {
232        let mappings = vec![
233            (0x01, KEY_ESC),
234            (0x02, KEY_1),
235            (0x03, KEY_2),
236            (0x04, KEY_3),
237            (0x05, KEY_4),
238            (0x06, KEY_5),
239            (0x07, KEY_6),
240            (0x08, KEY_7),
241            (0x09, KEY_8),
242            (0x0A, KEY_9),
243            (0x0B, KEY_0),
244            (0x0C, KEY_MINUS),
245            (0x0D, KEY_EQUAL),
246            (0x0E, KEY_BACKSPACE),
247            (0x0F, KEY_TAB),
248            (0x10, KEY_Q),
249            (0x11, KEY_W),
250            (0x12, KEY_E),
251            (0x13, KEY_R),
252            (0x14, KEY_T),
253            (0x15, KEY_Y),
254            (0x16, KEY_U),
255            (0x17, KEY_I),
256            (0x18, KEY_O),
257            (0x19, KEY_P),
258            (0x1A, KEY_LEFTBRACE),
259            (0x1B, KEY_RIGHTBRACE),
260            (0x1C, KEY_ENTER),
261            (0x1D, KEY_LEFTCTRL),
262            (0x1E, KEY_A),
263            (0x1F, KEY_S),
264            (0x20, KEY_D),
265            (0x21, KEY_F),
266            (0x22, KEY_G),
267            (0x23, KEY_H),
268            (0x24, KEY_J),
269            (0x25, KEY_K),
270            (0x26, KEY_L),
271            (0x27, KEY_SEMICOLON),
272            (0x28, KEY_APOSTROPHE),
273            (0x29, KEY_GRAVE),
274            (0x2A, KEY_LEFTSHIFT),
275            (0x2B, KEY_BACKSLASH),
276            (0x2C, KEY_Z),
277            (0x2D, KEY_X),
278            (0x2E, KEY_C),
279            (0x2F, KEY_V),
280            (0x30, KEY_B),
281            (0x31, KEY_N),
282            (0x32, KEY_M),
283            (0x33, KEY_COMMA),
284            (0x34, KEY_DOT),
285            (0x35, KEY_SLASH),
286            (0x36, KEY_RIGHTSHIFT),
287            (0x37, KEY_KPASTERISK),
288            (0x38, KEY_LEFTALT),
289            (0x39, KEY_SPACE),
290            (0x3A, KEY_CAPSLOCK),
291            (0x3B, KEY_F1),
292            (0x3C, KEY_F2),
293            (0x3D, KEY_F3),
294            (0x3E, KEY_F4),
295            (0x3F, KEY_F5),
296            (0x40, KEY_F6),
297            (0x41, KEY_F7),
298            (0x42, KEY_F8),
299            (0x43, KEY_F9),
300            (0x44, KEY_F10),
301            (0x45, KEY_NUMLOCK),
302            (0x46, KEY_SCROLLLOCK),
303            (0x47, KEY_KP7),
304            (0x48, KEY_KP8),
305            (0x49, KEY_KP9),
306            (0x4A, KEY_KPMINUS),
307            (0x4B, KEY_KP4),
308            (0x4C, KEY_KP5),
309            (0x4D, KEY_KP6),
310            (0x4E, KEY_KPPLUS),
311            (0x4F, KEY_KP1),
312            (0x50, KEY_KP2),
313            (0x51, KEY_KP3),
314            (0x52, KEY_KP0),
315            (0x53, KEY_KPDOT),
316            (0x54, KEY_SYSRQ),
317            (0x56, KEY_102ND),
318            (0x57, KEY_F11),
319            (0x58, KEY_F12),
320            (0x59, KEY_KPEQUAL),
321            (0x5A, KEY_F13),
322            (0x5B, KEY_F14),
323            (0x5C, KEY_F15),
324            (0x5D, KEY_F16),
325            (0x5E, KEY_F17),
326            (0x5F, KEY_F18),
327            (0x60, KEY_F19),
328            (0x61, KEY_F20),
329            (0x62, KEY_F21),
330            (0x63, KEY_F22),
331            (0x64, KEY_F23),
332            (0x65, KEY_F24),
333            (0x70, KEY_KATAKANAHIRAGANA),
334            (0x71, KEY_MUHENKAN),
335            (0x72, KEY_HENKAN),
336            (0x73, KEY_RO),
337            (0x74, KEY_YEN),
338            (0x75, KEY_HANGEUL),
339            (0x76, KEY_HANJA),
340            (0x77, KEY_LEFTMETA),
341            (0x78, KEY_RIGHTMETA),
342            (0x79, KEY_COMPOSE),
343            (0x7A, KEY_STOP),
344            (0x7B, KEY_AGAIN),
345            (0x7C, KEY_PROPS),
346            (0x7D, KEY_UNDO),
347            (0x7E, KEY_FRONT),
348            (0x7F, KEY_COPY),
349        ];
350
351        for (scancode, keycode) in mappings {
352            self.primary_map.insert(scancode, keycode);
353        }
354    }
355
356    /// Initialize extended scancode map (E0 prefix)
357    fn initialize_extended_map(&mut self) {
358        let mappings = vec![
359            (0xE01C, KEY_KPENTER),
360            (0xE01D, KEY_RIGHTCTRL),
361            (0xE020, KEY_MUTE),
362            (0xE021, KEY_CALC),
363            (0xE022, KEY_PLAYPAUSE),
364            (0xE024, KEY_STOPCD),
365            (0xE02E, KEY_VOLUMEDOWN),
366            (0xE030, KEY_VOLUMEUP),
367            (0xE032, KEY_HOMEPAGE),
368            (0xE035, KEY_KPSLASH),
369            (0xE037, KEY_PRINT),
370            (0xE038, KEY_RIGHTALT),
371            (0xE045, KEY_PAUSE),
372            (0xE047, KEY_HOME),
373            (0xE048, KEY_UP),
374            (0xE049, KEY_PAGEUP),
375            (0xE04B, KEY_LEFT),
376            (0xE04D, KEY_RIGHT),
377            (0xE04F, KEY_END),
378            (0xE050, KEY_DOWN),
379            (0xE051, KEY_PAGEDOWN),
380            (0xE052, KEY_INSERT),
381            (0xE053, KEY_DELETE),
382            (0xE05B, KEY_LEFTMETA),
383            (0xE05C, KEY_RIGHTMETA),
384            (0xE05D, KEY_MENU),
385            (0xE05E, KEY_POWER),
386            (0xE05F, KEY_SLEEP),
387            (0xE063, KEY_WAKEUP),
388            (0xE065, KEY_SEARCH),
389            (0xE066, KEY_BOOKMARKS),
390            (0xE067, KEY_REFRESH),
391            (0xE068, KEY_STOP),
392            (0xE069, KEY_FORWARD),
393            (0xE06A, KEY_BACK),
394            (0xE06B, KEY_COMPUTER),
395            (0xE06C, KEY_MAIL),
396            (0xE06D, KEY_MEDIA),
397            (0xE010, KEY_PREVIOUSSONG),
398            (0xE019, KEY_NEXTSONG),
399            (0xE02C, KEY_EJECTCD),
400        ];
401
402        for (scancode, keycode) in mappings {
403            self.extended_map.insert(scancode, keycode);
404        }
405    }
406
407    /// Initialize E1 prefix scancode map
408    fn initialize_e1_map(&mut self) {
409        self.e1_map.insert(0xE11D45, KEY_PAUSE);
410        self.e1_map.insert(0xE11D46, KEY_BREAK);
411    }
412
413    /// Build reverse mapping for keycode to scancode
414    fn build_reverse_map(&mut self) {
415        for (&scancode, &keycode) in &self.primary_map {
416            self.reverse_map.insert(keycode, scancode);
417        }
418        for (&scancode, &keycode) in &self.extended_map {
419            self.reverse_map.insert(keycode, scancode);
420        }
421    }
422
423    /// Load layout-specific overrides
424    fn load_layout_overrides(&mut self) {
425        // German layout (QWERTZ)
426        let mut de_overrides = HashMap::new();
427        de_overrides.insert(0x15, KEY_Z); // Y → Z
428        de_overrides.insert(0x2C, KEY_Y); // Z → Y
429        self.layout_overrides.insert("de".to_string(), de_overrides);
430
431        // French layout (AZERTY)
432        let mut fr_overrides = HashMap::new();
433        fr_overrides.insert(0x10, KEY_A); // Q → A
434        fr_overrides.insert(0x1E, KEY_Q); // A → Q
435        fr_overrides.insert(0x11, KEY_Z); // W → Z
436        fr_overrides.insert(0x2C, KEY_W); // Z → W
437        self.layout_overrides.insert("fr".to_string(), fr_overrides);
438    }
439
440    /// Translate RDP scancode to Linux evdev keycode
441    pub fn translate_scancode(&self, scancode: u32, extended: bool, e1_prefix: bool) -> Result<u32> {
442        if e1_prefix {
443            // Handle E1 prefix scancodes
444            self.e1_map
445                .get(&scancode)
446                .copied()
447                .ok_or(InputError::UnknownScancode(scancode as u16))
448        } else if extended {
449            // Handle E0 prefix (extended) scancodes
450            let extended_scan = 0xE000 | (scancode as u16 & 0xFF);
451            self.extended_map
452                .get(&extended_scan)
453                .or_else(|| self.primary_map.get(&(scancode as u16)))
454                .copied()
455                .ok_or(InputError::UnknownScancode(extended_scan))
456        } else {
457            // Check for layout-specific overrides first
458            if let Some(overrides) = self.layout_overrides.get(&self.current_layout) {
459                if let Some(keycode) = overrides.get(&(scancode as u16)) {
460                    return Ok(*keycode);
461                }
462            }
463            // Standard scancode translation
464            self.primary_map
465                .get(&(scancode as u16))
466                .copied()
467                .ok_or(InputError::UnknownScancode(scancode as u16))
468        }
469    }
470
471    /// Translate Linux keycode to RDP scancode
472    pub fn translate_keycode(&self, keycode: u32) -> Result<u16> {
473        self.reverse_map
474            .get(&keycode)
475            .copied()
476            .ok_or(InputError::UnknownKeycode(keycode))
477    }
478
479    /// Set keyboard layout
480    pub fn set_layout(&mut self, layout: &str) {
481        self.current_layout = layout.to_string();
482    }
483
484    /// Get current keyboard layout
485    pub fn layout(&self) -> &str {
486        &self.current_layout
487    }
488
489    /// Check if scancode is mapped
490    pub fn is_mapped(&self, scancode: u16, extended: bool) -> bool {
491        if extended {
492            let extended_scan = 0xE000 | (scancode & 0xFF);
493            self.extended_map.contains_key(&extended_scan)
494        } else {
495            self.primary_map.contains_key(&scancode)
496        }
497    }
498
499    /// Get total number of mapped keys
500    pub fn mapped_key_count(&self) -> usize {
501        self.primary_map.len() + self.extended_map.len() + self.e1_map.len()
502    }
503}
504
505impl Default for ScancodeMapper {
506    fn default() -> Self {
507        Self::new()
508    }
509}
510
511#[cfg(test)]
512mod tests {
513    use super::*;
514
515    #[test]
516    fn test_scancode_mapper_creation() {
517        let mapper = ScancodeMapper::new();
518        // 157 mappings: primary + extended + E1 prefix keys
519        assert!(mapper.mapped_key_count() >= 150);
520    }
521
522    #[test]
523    fn test_primary_scancode_mapping() {
524        let mapper = ScancodeMapper::new();
525
526        // Test letter keys
527        assert_eq!(mapper.translate_scancode(0x1E, false, false).unwrap(), KEY_A);
528        assert_eq!(mapper.translate_scancode(0x2C, false, false).unwrap(), KEY_Z);
529
530        // Test number keys
531        assert_eq!(mapper.translate_scancode(0x02, false, false).unwrap(), KEY_1);
532        assert_eq!(mapper.translate_scancode(0x0B, false, false).unwrap(), KEY_0);
533
534        // Test function keys
535        assert_eq!(mapper.translate_scancode(0x3B, false, false).unwrap(), KEY_F1);
536        assert_eq!(mapper.translate_scancode(0x58, false, false).unwrap(), KEY_F12);
537    }
538
539    #[test]
540    fn test_extended_scancode_mapping() {
541        let mapper = ScancodeMapper::new();
542
543        // Test navigation keys
544        assert_eq!(mapper.translate_scancode(0x47, true, false).unwrap(), KEY_HOME);
545        assert_eq!(mapper.translate_scancode(0x4F, true, false).unwrap(), KEY_END);
546        assert_eq!(mapper.translate_scancode(0x48, true, false).unwrap(), KEY_UP);
547        assert_eq!(mapper.translate_scancode(0x50, true, false).unwrap(), KEY_DOWN);
548        assert_eq!(mapper.translate_scancode(0x4B, true, false).unwrap(), KEY_LEFT);
549        assert_eq!(mapper.translate_scancode(0x4D, true, false).unwrap(), KEY_RIGHT);
550
551        // Test media keys
552        assert_eq!(mapper.translate_scancode(0x22, true, false).unwrap(), KEY_PLAYPAUSE);
553        assert_eq!(mapper.translate_scancode(0x24, true, false).unwrap(), KEY_STOPCD);
554    }
555
556    #[test]
557    fn test_bidirectional_mapping() {
558        let mapper = ScancodeMapper::new();
559
560        // Test round-trip for common keys
561        let test_keys = vec![KEY_A, KEY_Z, KEY_ENTER, KEY_SPACE, KEY_F1, KEY_F12];
562
563        for keycode in test_keys {
564            let scancode = mapper.translate_keycode(keycode).unwrap();
565            let translated = mapper.translate_scancode(scancode as u32, false, false).unwrap();
566            assert_eq!(translated, keycode);
567        }
568    }
569
570    #[test]
571    fn test_layout_override() {
572        let mut mapper = ScancodeMapper::new();
573
574        // US layout: Y key
575        assert_eq!(mapper.translate_scancode(0x15, false, false).unwrap(), KEY_Y);
576
577        // German layout: Y → Z
578        mapper.set_layout("de");
579        assert_eq!(mapper.translate_scancode(0x15, false, false).unwrap(), KEY_Z);
580
581        // French layout
582        mapper.set_layout("fr");
583        assert_eq!(mapper.translate_scancode(0x10, false, false).unwrap(), KEY_A);
584    }
585
586    #[test]
587    fn test_unknown_scancode() {
588        let mapper = ScancodeMapper::new();
589
590        // Test unmapped scancode
591        let result = mapper.translate_scancode(0xFF, false, false);
592        assert!(result.is_err());
593        match result {
594            Err(InputError::UnknownScancode(_)) => {}
595            _ => panic!("Expected UnknownScancode error"),
596        }
597    }
598
599    #[test]
600    fn test_unknown_keycode() {
601        let mapper = ScancodeMapper::new();
602
603        // Test unmapped keycode
604        let result = mapper.translate_keycode(9999);
605        assert!(result.is_err());
606        match result {
607            Err(InputError::UnknownKeycode(_)) => {}
608            _ => panic!("Expected UnknownKeycode error"),
609        }
610    }
611
612    #[test]
613    fn test_is_mapped() {
614        let mapper = ScancodeMapper::new();
615
616        assert!(mapper.is_mapped(0x1E, false)); // A key
617        assert!(mapper.is_mapped(0x47, true)); // Home key (extended)
618        assert!(!mapper.is_mapped(0xFF, false)); // Unknown
619    }
620
621    #[test]
622    fn test_all_primary_keys_mapped() {
623        let mapper = ScancodeMapper::new();
624
625        // Test common primary scancodes
626        for scancode in 0x01..=0x58 {
627            if scancode == 0x00 || scancode == 0x55 {
628                continue; // Skip undefined
629            }
630            assert!(
631                mapper.is_mapped(scancode, false),
632                "Scancode 0x{:02X} not mapped",
633                scancode
634            );
635        }
636    }
637
638    #[test]
639    fn test_function_keys_f13_to_f24() {
640        let mapper = ScancodeMapper::new();
641
642        assert_eq!(mapper.translate_scancode(0x5A, false, false).unwrap(), KEY_F13);
643        assert_eq!(mapper.translate_scancode(0x65, false, false).unwrap(), KEY_F24);
644    }
645
646    #[test]
647    fn test_multimedia_keys() {
648        let mapper = ScancodeMapper::new();
649
650        assert_eq!(mapper.translate_scancode(0x20, true, false).unwrap(), KEY_MUTE);
651        assert_eq!(mapper.translate_scancode(0x2E, true, false).unwrap(), KEY_VOLUMEDOWN);
652        assert_eq!(mapper.translate_scancode(0x30, true, false).unwrap(), KEY_VOLUMEUP);
653    }
654
655    #[test]
656    fn test_japanese_keys() {
657        let mapper = ScancodeMapper::new();
658
659        assert_eq!(
660            mapper.translate_scancode(0x70, false, false).unwrap(),
661            KEY_KATAKANAHIRAGANA
662        );
663        assert_eq!(mapper.translate_scancode(0x71, false, false).unwrap(), KEY_MUHENKAN);
664        assert_eq!(mapper.translate_scancode(0x72, false, false).unwrap(), KEY_HENKAN);
665    }
666
667    #[test]
668    fn test_korean_keys() {
669        let mapper = ScancodeMapper::new();
670
671        assert_eq!(mapper.translate_scancode(0x75, false, false).unwrap(), KEY_HANGEUL);
672        assert_eq!(mapper.translate_scancode(0x76, false, false).unwrap(), KEY_HANJA);
673    }
674}