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