os_terminal/
keyboard.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use alloc::string::{String, ToString};
use pc_keyboard::layouts::Us104Key;
use pc_keyboard::KeyCode::{self, *};
use pc_keyboard::{DecodedKey, Keyboard};
use pc_keyboard::{HandleControl, ScancodeSet1};

pub enum KeyboardEvent {
    AnsiString(String),
    SetColorScheme(usize),
    ScrollUp,
    ScrollDown,
    ScrollPageUp,
    ScrollPageDown,
    None,
}

pub struct KeyboardManager {
    app_cursor_mode: bool,
    natural_scroll: bool,
    keyboard: Keyboard<Us104Key, ScancodeSet1>,
}

impl Default for KeyboardManager {
    fn default() -> Self {
        Self {
            app_cursor_mode: false,
            natural_scroll: true,
            keyboard: Keyboard::new(
                ScancodeSet1::new(),
                Us104Key,
                HandleControl::MapLettersToUnicode,
            ),
        }
    }
}

impl KeyboardManager {
    pub fn set_app_cursor(&mut self, mode: bool) {
        self.app_cursor_mode = mode;
    }

    pub fn set_natural_scroll(&mut self, mode: bool) {
        self.natural_scroll = mode;
    }

    pub fn handle_keyboard(&mut self, scancode: u8) -> KeyboardEvent {
        if let Some(key_event) = self.keyboard.add_byte(scancode).ok().flatten() {
            if let Some(decoded_key) = self.keyboard.process_keyevent(key_event) {
                return self.key_to_ansi_string(decoded_key);
            }
        }
        KeyboardEvent::None
    }
}

impl KeyboardManager {
    #[rustfmt::skip]
    fn key_to_ansi_string(&self, key: DecodedKey) -> KeyboardEvent {
        let modifiers = self.keyboard.get_modifiers();

        match key {
            DecodedKey::Unicode(c) => {
                KeyboardEvent::AnsiString(c.to_string())
            }
            DecodedKey::RawKey(key) => {
                if modifiers.is_ctrl() && modifiers.is_shifted() {
                    match (key, self.natural_scroll) {
                        (ArrowUp, true) | (ArrowDown, false) => return KeyboardEvent::ScrollUp,
                        (ArrowUp, false) | (ArrowDown, true) => return KeyboardEvent::ScrollDown,
                        (PageUp, _) => return KeyboardEvent::ScrollPageUp,
                        (PageDown, _) => return KeyboardEvent::ScrollPageDown,
                        _ => {},
                    };

                    let palette_index = match key {
                        KeyCode::F1 => Some(0),
                        KeyCode::F2 => Some(1),
                        KeyCode::F3 => Some(2),
                        KeyCode::F4 => Some(3),
                        KeyCode::F5 => Some(4),
                        KeyCode::F6 => Some(5),
                        KeyCode::F7 => Some(6),
                        KeyCode::F8 => Some(7),
                        _ => None,
                    };
                    if let Some(palette_index) = palette_index {
                        return KeyboardEvent::SetColorScheme(palette_index as usize);
                    }
                }

                let sequence = match key {
                    F1 => "\x1bOP",
                    F2 => "\x1bOQ",
                    F3 => "\x1bOR",
                    F4 => "\x1bOS",
                    F5 => "\x1b[15~",
                    F6 => "\x1b[17~",
                    F7 => "\x1b[18~",
                    F8 => "\x1b[19~",
                    F9 => "\x1b[20~",
                    F10 => "\x1b[21~",
                    F11 => "\x1b[23~",
                    F12 => "\x1b[24~",
                    ArrowUp => if self.app_cursor_mode { "\x1bOA" } else { "\x1b[A" },
                    ArrowDown => if self.app_cursor_mode { "\x1bOB" } else { "\x1b[B" },
                    ArrowRight => if self.app_cursor_mode { "\x1bOC" } else { "\x1b[C" },
                    ArrowLeft => if self.app_cursor_mode { "\x1bOD" } else { "\x1b[D" },
                    Home => "\x1b[H",
                    End => "\x1b[F",
                    PageUp => "\x1b[5~",
                    PageDown => "\x1b[6~",
                    _ => "",
                };

                match sequence {
                    "" => KeyboardEvent::None,
                    _ => KeyboardEvent::AnsiString(sequence.to_string()),
                }
            }
        }
    }
}