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