kernel/devices/keyboard_mouse/
keyboard.rs

1use core::sync::atomic::{AtomicU8, Ordering};
2
3use blinkcast::alloc::{Receiver as BlinkcastReceiver, Sender as BlinkcastSender};
4use kernel_user_link::keyboard::{modifier, Key, KeyType};
5
6use super::ps2::Ps2;
7
8/// Number of key events that can be buffered before being overwritten
9/// We are expecting interested readers to be fast, so we don't need a very large buffer
10const KEYBOARD_BUFFER_SIZE: usize = 256;
11
12const KEY_PRESSED: u8 = 1 << 7;
13
14// PS/2 keyboard interrupt
15pub const KEYBOARD_INT_NUM: u8 = 1;
16
17pub type KeyboardReader = BlinkcastReceiver<Key>;
18
19pub struct Keyboard {
20    active_modifiers: AtomicU8,
21    active_toggles: AtomicU8,
22    ps2: Ps2,
23
24    sender: BlinkcastSender<Key>,
25}
26
27impl Keyboard {
28    pub fn new(ps2: Ps2) -> Keyboard {
29        let sender = BlinkcastSender::new(KEYBOARD_BUFFER_SIZE);
30        Keyboard {
31            active_modifiers: AtomicU8::new(0),
32            active_toggles: AtomicU8::new(0),
33            ps2,
34            sender,
35        }
36    }
37
38    pub fn new_receiver(&self) -> KeyboardReader {
39        self.sender.new_receiver()
40    }
41
42    fn modifiers(&self) -> u8 {
43        // remove the saved toggles (this is used for safe-keeping which toggle are we still pressing)
44        let modifiers_only = self.active_modifiers.load(Ordering::Relaxed)
45            & !(modifier::CAPS_LOCK | modifier::NUM_LOCK | modifier::SCROLL_LOCK);
46
47        modifiers_only | self.active_toggles.load(Ordering::Relaxed)
48    }
49
50    pub fn handle_keyboard_data(&self) {
51        if !self.ps2.has_data() {
52            return;
53        }
54
55        let data = self.ps2.read_data();
56
57        if data == 0xE0 {
58            // this is an extended key
59            let data = self.ps2.read_data();
60            let pressed = data & KEY_PRESSED == 0;
61            let Some(key) = key_type_from_device(data | 0x80) else {
62                // not a valid key
63                return;
64            };
65
66            self.sender.send(Key {
67                pressed,
68                modifiers: self.modifiers(),
69                key_type: key,
70            });
71        }
72
73        let pressed = data & KEY_PRESSED == 0;
74        let data = data & !KEY_PRESSED; // strip the pressed bit
75        if let Some(modifier_key) = get_modifier(data) {
76            if pressed {
77                self.active_modifiers
78                    .fetch_or(modifier_key, Ordering::Relaxed);
79            } else {
80                self.active_modifiers
81                    .fetch_and(!modifier_key, Ordering::Relaxed);
82            }
83        } else if let Some(toggle_key) = get_toggle(data) {
84            // keep a copy in the modifier so that we only toggle on a press
85            let should_toggle =
86                pressed && self.active_modifiers.load(Ordering::Relaxed) & toggle_key == 0;
87            if should_toggle {
88                self.active_toggles.fetch_xor(toggle_key, Ordering::Relaxed);
89            }
90
91            // add to the modifier
92            if pressed {
93                self.active_modifiers
94                    .fetch_or(toggle_key, Ordering::Relaxed);
95            } else {
96                self.active_modifiers
97                    .fetch_and(!toggle_key, Ordering::Relaxed);
98            }
99        }
100        // this is a normal key
101        let Some(key_type) = key_type_from_device(data) else {
102            // not a valid key
103            return;
104        };
105
106        self.sender.send(Key {
107            pressed,
108            modifiers: self.modifiers(),
109            key_type,
110        })
111    }
112}
113
114// 0x80 means extended key
115fn key_type_from_device(value: u8) -> Option<KeyType> {
116    if value & 0x80 == 0 {
117        if value <= KeyType::F12 as u8 {
118            // not extended.
119            // we know that we are mapping the not extended keys directly
120            // so we can just cast it
121            let k = unsafe { core::mem::transmute::<u8, KeyType>(value) };
122            if k == KeyType::_None1
123                || k == KeyType::_None2
124                || k == KeyType::_None3
125                || k == KeyType::_None4
126            {
127                return None;
128            }
129
130            Some(k)
131        } else {
132            // not a valid key
133            None
134        }
135    } else {
136        // first, strip the extension
137        let key = value & !0x80;
138
139        // use match normally
140        match key {
141            0x10 => Some(KeyType::MultimediaPreviousTrack),
142            0x19 => Some(KeyType::MultimediaNextTrack),
143            0x1C => Some(KeyType::KeypadEnter),
144            0x1D => Some(KeyType::RightCtrl),
145            0x20 => Some(KeyType::MultimediaMute),
146            0x21 => Some(KeyType::Calculator),
147            0x22 => Some(KeyType::MultimediaPlayPause),
148            0x24 => Some(KeyType::MultimediaStop),
149            0x2E => Some(KeyType::VolumeDown),
150            0x30 => Some(KeyType::VolumeUp),
151            0x32 => Some(KeyType::WWWHome),
152            0x35 => Some(KeyType::KeypadSlash),
153            0x38 => Some(KeyType::RightAlt),
154            0x47 => Some(KeyType::Home),
155            0x48 => Some(KeyType::UpArrow),
156            0x49 => Some(KeyType::PageUp),
157            0x4B => Some(KeyType::LeftArrow),
158            0x4D => Some(KeyType::RightArrow),
159            0x4F => Some(KeyType::End),
160            0x50 => Some(KeyType::DownArrow),
161            0x51 => Some(KeyType::PageDown),
162            0x52 => Some(KeyType::Insert),
163            0x53 => Some(KeyType::Delete),
164            0x5B => Some(KeyType::LeftGUI),
165            0x5C => Some(KeyType::RightGUI),
166            0x5D => Some(KeyType::Application),
167            0x5E => Some(KeyType::Power),
168            0x5F => Some(KeyType::Sleep),
169            0x63 => Some(KeyType::Wake),
170            0x65 => Some(KeyType::WWWSearch),
171            0x66 => Some(KeyType::WWWFavorites),
172            0x67 => Some(KeyType::WWWRefresh),
173            0x68 => Some(KeyType::WWWStop),
174            0x69 => Some(KeyType::WWWForward),
175            0x6A => Some(KeyType::WWWBack),
176            0x6B => Some(KeyType::MyComputer),
177            0x6C => Some(KeyType::Email),
178            0x6D => Some(KeyType::MultimediaSelect),
179            _ => None,
180        }
181    }
182}
183
184const fn get_modifier(key: u8) -> Option<u8> {
185    match key {
186        0x2A => Some(modifier::SHIFT),
187        0x36 => Some(modifier::SHIFT),
188        0x1D => Some(modifier::CTRL),
189        0x38 => Some(modifier::ALT),
190        _ => None,
191    }
192}
193
194const fn get_toggle(key: u8) -> Option<u8> {
195    match key {
196        0x3A => Some(modifier::CAPS_LOCK),
197        0x45 => Some(modifier::NUM_LOCK),
198        0x46 => Some(modifier::SCROLL_LOCK),
199        _ => None,
200    }
201}