os_terminal/
keyboard.rs

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}