1use alloc::string::{String, ToString};
2use pc_keyboard::layouts::Us104Key;
3use pc_keyboard::KeyCode::{self, *};
4use pc_keyboard::{DecodedKey, Keyboard};
5use pc_keyboard::{HandleControl, ScancodeSet1};
6
7#[derive(Debug)]
8pub enum KeyboardEvent {
9 AnsiString(String),
10 SetColorScheme(usize),
11 ScrollUp,
12 ScrollDown,
13 ScrollPageUp,
14 ScrollPageDown,
15 None,
16}
17
18pub struct KeyboardManager {
19 app_cursor_mode: bool,
20 keyboard: Keyboard<Us104Key, ScancodeSet1>,
21}
22
23impl Default for KeyboardManager {
24 fn default() -> Self {
25 Self {
26 app_cursor_mode: false,
27 keyboard: Keyboard::new(
28 ScancodeSet1::new(),
29 Us104Key,
30 HandleControl::MapLettersToUnicode,
31 ),
32 }
33 }
34}
35
36impl KeyboardManager {
37 pub fn set_app_cursor(&mut self, mode: bool) {
38 self.app_cursor_mode = mode;
39 }
40
41 pub fn simulate_key(&mut self, key: KeyCode) -> Option<String> {
42 match self.key_to_event(DecodedKey::RawKey(key)) {
43 KeyboardEvent::AnsiString(s) => Some(s),
44 _ => None,
45 }
46 }
47
48 pub fn handle_keyboard(&mut self, scancode: u8) -> KeyboardEvent {
49 self.keyboard
50 .add_byte(scancode)
51 .ok()
52 .flatten()
53 .and_then(|event| self.keyboard.process_keyevent(event))
54 .map_or(KeyboardEvent::None, |key| self.key_to_event(key))
55 }
56}
57
58impl KeyboardManager {
59 fn key_to_event(&self, key: DecodedKey) -> KeyboardEvent {
60 let modifiers = self.keyboard.get_modifiers();
61
62 match key {
63 DecodedKey::RawKey(key) => {
64 if modifiers.is_ctrl() && modifiers.is_shifted() {
65 if let Some(event) = self
66 .handle_scroll(key)
67 .or_else(|| self.handle_color_scheme(key))
68 {
69 return event;
70 }
71 }
72
73 self.generate_ansi_sequence(key)
74 .map(|s| KeyboardEvent::AnsiString(s.to_string()))
75 .unwrap_or(KeyboardEvent::None)
76 }
77 DecodedKey::Unicode(c) => KeyboardEvent::AnsiString(c.to_string()),
78 }
79 }
80
81 fn handle_color_scheme(&self, key: KeyCode) -> Option<KeyboardEvent> {
82 let index = match key {
83 F1 => 0,
84 F2 => 1,
85 F3 => 2,
86 F4 => 3,
87 F5 => 4,
88 F6 => 5,
89 F7 => 6,
90 F8 => 7,
91 _ => return None,
92 };
93 Some(KeyboardEvent::SetColorScheme(index))
94 }
95
96 fn handle_scroll(&self, key: KeyCode) -> Option<KeyboardEvent> {
97 match key {
98 ArrowUp => Some(KeyboardEvent::ScrollUp),
99 ArrowDown => Some(KeyboardEvent::ScrollDown),
100 PageUp => Some(KeyboardEvent::ScrollPageUp),
101 PageDown => Some(KeyboardEvent::ScrollPageDown),
102 _ => None,
103 }
104 }
105
106 #[rustfmt::skip]
107 fn generate_ansi_sequence(&self, key: KeyCode) -> Option<&'static str>{
108 let sequence = match key {
109 F1 => "\x1bOP",
110 F2 => "\x1bOQ",
111 F3 => "\x1bOR",
112 F4 => "\x1bOS",
113 F5 => "\x1b[15~",
114 F6 => "\x1b[17~",
115 F7 => "\x1b[18~",
116 F8 => "\x1b[19~",
117 F9 => "\x1b[20~",
118 F10 => "\x1b[21~",
119 F11 => "\x1b[23~",
120 F12 => "\x1b[24~",
121 ArrowUp => if self.app_cursor_mode { "\x1bOA" } else { "\x1b[A" },
122 ArrowDown => if self.app_cursor_mode { "\x1bOB" } else { "\x1b[B" },
123 ArrowRight => if self.app_cursor_mode { "\x1bOC" } else { "\x1b[C" },
124 ArrowLeft => if self.app_cursor_mode { "\x1bOD" } else { "\x1b[D" },
125 Home => "\x1b[H",
126 End => "\x1b[F",
127 PageUp => "\x1b[5~",
128 PageDown => "\x1b[6~",
129 _ => return None,
130 };
131 Some(sequence)
132 }
133}