strat9_kernel/arch/x86_64/
keyboard.rs1use super::io::inb;
7use spin::Mutex;
8
9const KEYBOARD_BUFFER_SIZE: usize = 256;
11
12struct KeyboardBufferInner {
30 buf: [u8; KEYBOARD_BUFFER_SIZE],
31 head: usize,
32 tail: usize,
33}
34
35struct KeyboardBuffer {
36 inner: Mutex<KeyboardBufferInner>,
37}
38
39static KEYBOARD_BUFFER: KeyboardBuffer = KeyboardBuffer::new();
40
41impl KeyboardBuffer {
42 const fn new() -> Self {
44 Self {
45 inner: Mutex::new(KeyboardBufferInner {
46 buf: [0u8; KEYBOARD_BUFFER_SIZE],
47 head: 0,
48 tail: 0,
49 }),
50 }
51 }
52
53 pub fn push(&self, ch: u8) {
56 let mut g = self.inner.lock();
57 let tail = g.tail;
58 g.buf[tail] = ch;
59 g.tail = (tail + 1) % KEYBOARD_BUFFER_SIZE;
60 if g.head == g.tail {
62 g.head = (g.head + 1) % KEYBOARD_BUFFER_SIZE;
63 }
64 }
65
66 pub fn pop(&self) -> Option<u8> {
69 let saved = super::save_flags_and_cli();
70 let result = {
71 let mut g = self.inner.lock();
72 if g.head == g.tail {
73 None
74 } else {
75 let ch = g.buf[g.head];
76 g.head = (g.head + 1) % KEYBOARD_BUFFER_SIZE;
77 Some(ch)
78 }
79 };
80 super::restore_flags(saved);
81 result
82 }
83
84 pub fn has_data(&self) -> bool {
86 let saved = super::save_flags_and_cli();
87 let result = {
88 let g = self.inner.lock();
89 g.head != g.tail
90 };
91 super::restore_flags(saved);
92 result
93 }
94}
95
96pub fn add_to_buffer(ch: u8) {
102 if ch == 0x03 {
103 crate::shell::SHELL_INTERRUPTED.store(true, core::sync::atomic::Ordering::Relaxed);
104 }
105 KEYBOARD_BUFFER.push(ch);
106}
107
108pub fn read_char() -> Option<u8> {
110 KEYBOARD_BUFFER.pop()
111}
112
113pub fn has_input() -> bool {
115 KEYBOARD_BUFFER.has_data()
116}
117
118const KEYBOARD_DATA_PORT: u16 = 0x60;
120
121pub struct KeyboardState {
123 pub left_shift: bool,
125 pub right_shift: bool,
127 pub caps_lock: bool,
129 pub ctrl: bool,
131 pub alt: bool,
133}
134
135impl KeyboardState {
136 pub const fn new() -> Self {
138 Self {
139 left_shift: false,
140 right_shift: false,
141 caps_lock: false,
142 ctrl: false,
143 alt: false,
144 }
145 }
146
147 pub fn shift_active(&self) -> bool {
149 self.left_shift || self.right_shift
150 }
151}
152
153pub static KEYBOARD: Mutex<KeyboardState> = Mutex::new(KeyboardState::new());
155
156static SCANCODE_TO_ASCII: [u8; 128] = {
158 let mut table = [0u8; 128];
159 table[0x01] = 0x1B; table[0x02] = b'&'; table[0x03] = b'e'; table[0x04] = b'"'; table[0x05] = b'\''; table[0x06] = b'('; table[0x07] = b'-'; table[0x08] = b'e'; table[0x09] = b'_'; table[0x0A] = b'c'; table[0x0B] = b'a'; table[0x0C] = b')'; table[0x0D] = b'='; table[0x0E] = 0x08; table[0x0F] = b'\t';
176 table[0x10] = b'a'; table[0x11] = b'z'; table[0x12] = b'e'; table[0x13] = b'r'; table[0x14] = b't'; table[0x15] = b'y'; table[0x16] = b'u'; table[0x17] = b'i'; table[0x18] = b'o'; table[0x19] = b'p'; table[0x1A] = b'^'; table[0x1B] = b'$'; table[0x1C] = b'\n'; table[0x1E] = b'q'; table[0x1F] = b's'; table[0x20] = b'd'; table[0x21] = b'f'; table[0x22] = b'g'; table[0x23] = b'h'; table[0x24] = b'j'; table[0x25] = b'k'; table[0x26] = b'l'; table[0x27] = b'm'; table[0x28] = b'u'; table[0x29] = b'*'; table[0x2A] = 0x00; table[0x2B] = b'<'; table[0x2C] = b'w'; table[0x2D] = b'x'; table[0x2E] = b'c'; table[0x2F] = b'v'; table[0x30] = b'b'; table[0x31] = b'n'; table[0x32] = b','; table[0x33] = b';'; table[0x34] = b'.'; table[0x35] = b'/'; table[0x39] = b' ';
217 table
218};
219
220static SCANCODE_TO_ASCII_SHIFT: [u8; 128] = {
222 let mut table = [0u8; 128];
223 table[0x01] = 0x1B; table[0x02] = b'1'; table[0x03] = b'2'; table[0x04] = b'3'; table[0x05] = b'4'; table[0x06] = b'5'; table[0x07] = b'6'; table[0x08] = b'7'; table[0x09] = b'8'; table[0x0A] = b'9'; table[0x0B] = b'0'; table[0x0C] = b')'; table[0x0D] = b'+'; table[0x0E] = 0x08; table[0x0F] = b'\t'; table[0x10] = b'A'; table[0x11] = b'Z'; table[0x12] = b'E'; table[0x13] = b'R'; table[0x14] = b'T'; table[0x15] = b'Y'; table[0x16] = b'U'; table[0x17] = b'I'; table[0x18] = b'O'; table[0x19] = b'P'; table[0x1A] = b'^'; table[0x1B] = b'*'; table[0x1C] = b'\n'; table[0x1E] = b'Q'; table[0x1F] = b'S'; table[0x20] = b'D'; table[0x21] = b'F'; table[0x22] = b'G'; table[0x23] = b'H'; table[0x24] = b'J'; table[0x25] = b'K'; table[0x26] = b'L'; table[0x27] = b'M'; table[0x28] = b'%'; table[0x29] = b'm'; table[0x2B] = b'>'; table[0x2C] = b'W'; table[0x2D] = b'X'; table[0x2E] = b'C'; table[0x2F] = b'V'; table[0x30] = b'B'; table[0x31] = b'N'; table[0x32] = b'?'; table[0x33] = b'.'; table[0x34] = b','; table[0x35] = b'/'; table[0x39] = b' '; table
276};
277
278pub const KEY_UP: u8 = 0x80;
280pub const KEY_DOWN: u8 = 0x81;
281pub const KEY_LEFT: u8 = 0x82;
282pub const KEY_RIGHT: u8 = 0x83;
283pub const KEY_HOME: u8 = 0x84;
284pub const KEY_END: u8 = 0x85;
285
286pub fn handle_scancode() -> Option<u8> {
291 let scancode = unsafe { inb(KEYBOARD_DATA_PORT) };
292 handle_scancode_raw(scancode)
293}
294
295pub fn handle_scancode_raw(scancode: u8) -> Option<u8> {
297 let mut kbd = KEYBOARD.lock();
298
299 if scancode & 0x80 != 0 {
301 let released = scancode & 0x7F;
302 match released {
303 0x2A => kbd.left_shift = false,
304 0x36 => kbd.right_shift = false,
305 0x1D => kbd.ctrl = false,
306 0x38 => kbd.alt = false,
307 _ => {}
308 }
309 return None;
310 }
311
312 match scancode {
314 0x2A => {
315 kbd.left_shift = true;
316 return None;
317 }
318 0x36 => {
319 kbd.right_shift = true;
320 return None;
321 }
322 0x1D => {
323 kbd.ctrl = true;
324 return None;
325 }
326 0x38 => {
327 kbd.alt = true;
328 return None;
329 }
330 0x3A => {
331 kbd.caps_lock = !kbd.caps_lock;
332 return None;
333 }
334 0x48 => return Some(KEY_UP),
336 0x50 => return Some(KEY_DOWN),
337 0x4B => return Some(KEY_LEFT),
338 0x4D => return Some(KEY_RIGHT),
339 0x47 => return Some(KEY_HOME),
340 0x4F => return Some(KEY_END),
341 _ => {}
342 }
343
344 if scancode < 128 {
346 let shift = kbd.shift_active();
347 let ch = if shift {
348 SCANCODE_TO_ASCII_SHIFT[scancode as usize]
349 } else {
350 SCANCODE_TO_ASCII[scancode as usize]
351 };
352
353 if kbd.caps_lock && ch.is_ascii_alphabetic() {
355 let ch = if shift {
356 ch.to_ascii_lowercase()
357 } else {
358 ch.to_ascii_uppercase()
359 };
360 if ch != 0 {
361 return Some(ch);
362 }
363 }
364
365 if ch != 0 {
366 return Some(ch);
367 }
368 }
369
370 None
371}