os_terminal/
keyboard.rs

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}