From fc37634a1891bfe9a796b45013e0f85dfd2ba04f Mon Sep 17 00:00:00 2001 From: apio Date: Wed, 6 Mar 2024 20:33:54 +0100 Subject: [PATCH] kernel: Add much-needed support for extended keyboard scancodes --- kernel/src/api/Keyboard.h | 24 +++ kernel/src/arch/Keyboard.h | 16 +- kernel/src/arch/x86_64/Keyboard.cpp | 269 ++++++++++------------------ 3 files changed, 124 insertions(+), 185 deletions(-) diff --git a/kernel/src/api/Keyboard.h b/kernel/src/api/Keyboard.h index 6222a7ec..ba868712 100644 --- a/kernel/src/api/Keyboard.h +++ b/kernel/src/api/Keyboard.h @@ -117,6 +117,30 @@ namespace moon K_CH46, // . K_CH47, // / K_CH48, // Space + // Multimedia keys + K_MediaPrev, + K_MediaNext, + K_MediaMute, + K_MediaCalc, + K_MediaPlay, + K_MediaStop, + K_MediaVolDown, + K_MediaVolUp, + // WWW keys + K_WWWHome, + K_WWWSearch, + K_WWWFavorites, + K_WWWRefresh, + K_WWWStop, + K_WWWForward, + K_WWWBack, + K_WWWMyComputer, + K_WWWEmail, + K_WWWSelect, + // Power keys + K_ACPIPower, + K_ACPISleep, + K_ACPIWake, // Unknown key K_Unknown, }; diff --git a/kernel/src/arch/Keyboard.h b/kernel/src/arch/Keyboard.h index f705f514..71a66ba2 100644 --- a/kernel/src/arch/Keyboard.h +++ b/kernel/src/arch/Keyboard.h @@ -1,24 +1,16 @@ #pragma once #include "api/Keyboard.h" #include +#include namespace Keyboard { - struct TTYKeyboardState - { - bool ignore_next { false }; - bool left_shift { false }; - bool right_shift { false }; - bool left_control { false }; - bool capslock { false }; - }; - struct KeyboardState { - bool ignore_next { false }; + Vector key_state; + bool parsing_ext { false }; + bool parsing_pause { false }; }; - Option decode_scancode_tty(u8 scancode, TTYKeyboardState& state); - Option decode_scancode(u8 scancode, KeyboardState& state); } diff --git a/kernel/src/arch/x86_64/Keyboard.cpp b/kernel/src/arch/x86_64/Keyboard.cpp index 9bc14272..30c45378 100644 --- a/kernel/src/arch/x86_64/Keyboard.cpp +++ b/kernel/src/arch/x86_64/Keyboard.cpp @@ -13,104 +13,9 @@ static bool is_key_released(u8& scancode) return false; } -constexpr u8 EXTENDED_KEY_CODE = 0xe0; -constexpr u8 LEFT_SHIFT = 0x2a; -constexpr u8 RIGHT_SHIFT = 0x36; -constexpr u8 CAPS_LOCK = 0x3a; - -constexpr u8 LEFT_CONTROL = 0x1D; -constexpr u8 LEFT_ALT = 0x38; -constexpr u8 F11 = 0x57; -constexpr u8 F12 = 0x58; - -static bool should_ignore_key(u8 scancode) -{ - return (scancode > 0x3A && scancode < 0x47) || scancode == F11 || scancode == F12; -} - -constexpr char key_table[] = { - '\0', - '\1', // escape - '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', - '\t', // tab - 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', - '\0', // left ctrl - 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', - '\0', // left shift - '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', - '\0', // right shift - '*', // keypad * - '\0', // left alt - ' ', - '\0', // caps lock - '\0', // f1 - '\0', // f2 - '\0', // f3 - '\0', // f4 - '\0', // f5 - '\0', // f6 - '\0', // f7 - '\0', // f8 - '\0', // f9 - '\0', // f10 - '\0', // num lock - '\0', // scroll lock - '7', // keypad 7 - '8', // keypad 8 - '9', // keypad 9 - '-', // keypad - - '4', // keypad 4 - '5', // keypad 5 - '6', // keypad 6 - '+', // keypad + - '1', // keypad 1 - '2', // keypad 2 - '3', // keypad 3 - '0', // keypad 0 - '.', // keypad . -}; - -constexpr char shifted_key_table[] = { - '\0', - '\1', // escape - '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b', - '\t', // tab - 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', - '\0', // left ctrl - 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', - '\0', // left shift - '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', - '\0', // right shift - '*', // keypad * - '\0', // left alt - ' ', - '\0', // caps lock - '\0', // f1 - '\0', // f2 - '\0', // f3 - '\0', // f4 - '\0', // f5 - '\0', // f6 - '\0', // f7 - '\0', // f8 - '\0', // f9 - '\0', // f10 - '\0', // num lock - '\0', // scroll lock - '7', // keypad 7 - '8', // keypad 8 - '9', // keypad 9 - '-', // keypad - - '4', // keypad 4 - '5', // keypad 5 - '6', // keypad 6 - '+', // keypad + - '1', // keypad 1 - '2', // keypad 2 - '3', // keypad 3 - '0', // keypad 0 - '.', // keypad . -}; +constexpr static u8 print_screen_pressed[] = { 0xe0, 0x2a, 0xe0, 0x37 }; +constexpr static u8 print_screen_released[] = { 0xe0, 0xb7, 0xe0, 0xaa }; +constexpr static u8 pause[] = { 0xe1, 0x1d, 0x45, 0xe1, 0x9d, 0xc5 }; using namespace moon; @@ -176,95 +81,113 @@ constexpr KeyCode keycode_table[] = { K_F11, K_F12, }; -static bool is_shifted(const Keyboard::TTYKeyboardState& state) -{ - if (state.capslock) return !(state.left_shift || state.right_shift); - return state.left_shift || state.right_shift; -} +constexpr KeyCode extended_keycode_table[] = { + K_MediaPrev, K_Unknown, K_Unknown, K_Unknown, K_Unknown, K_Unknown, K_Unknown, + K_Unknown, K_Unknown, K_MediaNext, K_Unknown, K_Unknown, K_KeypadEnter, K_RightControl, + K_Unknown, K_Unknown, K_MediaMute, K_MediaCalc, K_MediaPlay, K_Unknown, K_MediaStop, + K_Unknown, K_Unknown, K_Unknown, K_Unknown, K_Unknown, K_Unknown, K_Unknown, + K_Unknown, K_Unknown, K_MediaVolDown, K_Unknown, K_MediaVolUp, K_Unknown, K_WWWHome, + K_Unknown, K_Unknown, K_KeypadDiv, K_Unknown, K_Unknown, K_RightAlt, K_Unknown, + K_Unknown, K_Unknown, K_Unknown, K_Unknown, K_Unknown, K_Unknown, K_Unknown, + K_Unknown, K_Unknown, K_Unknown, K_Unknown, K_Unknown, K_Unknown, K_Home, + K_UpArrow, K_PageUp, K_Unknown, K_LeftArrow, K_Unknown, K_RightArrow, K_Unknown, + K_End, K_DownArrow, K_PageDown, K_Insert, K_Delete, K_Unknown, K_Unknown, + K_Unknown, K_Unknown, K_Unknown, K_Unknown, K_Unknown, K_Super, K_Super, + K_Menu, K_ACPIPower, K_ACPISleep, K_Unknown, K_Unknown, K_Unknown, K_ACPIWake, + K_Unknown, K_WWWSearch, K_WWWFavorites, K_WWWRefresh, K_WWWStop, K_WWWForward, K_WWWBack, + K_WWWMyComputer, K_WWWEmail, K_WWWSelect +}; namespace Keyboard { - Option decode_scancode_tty(u8 scancode, TTYKeyboardState& state) - { - if (state.ignore_next) - { - state.ignore_next = false; - return {}; - } - - // FIXME: Support extended scancodes. - if (scancode == EXTENDED_KEY_CODE) - { - state.ignore_next = true; - return {}; - } - - bool released = is_key_released(scancode); - - if (scancode == LEFT_SHIFT) - { - state.left_shift = !released; - return {}; - } - - if (scancode == RIGHT_SHIFT) - { - state.right_shift = !released; - return {}; - } - - if (scancode == CAPS_LOCK) - { - if (!released) state.capslock = !state.capslock; - return {}; - } - - if (scancode == LEFT_CONTROL) - { - if (released) state.left_control = false; - else - state.left_control = true; - return {}; - } - - if (should_ignore_key(scancode)) return {}; - - if (released) return {}; - - if (state.left_control) - { - char key; - if (is_shifted(state)) key = shifted_key_table[scancode]; - else - key = key_table[scancode]; - if (_islower(key)) key = (char)_toupper(key); - if (_isupper(key)) return key - 0x40; - if (key == '@') return key - 0x40; - if (key > 'Z' && key < '`') return key - 0x40; - if (key == '?') return 0x7f; - } - - if (is_shifted(state)) return shifted_key_table[scancode]; - return key_table[scancode]; - } - Option decode_scancode(u8 scancode, KeyboardState& state) { - if (state.ignore_next) + if (state.parsing_pause) { - state.ignore_next = false; + if (state.key_state.size() < 6) state.key_state.try_append(scancode).release_value(); + + if (state.key_state.size() == 6) + { + state.parsing_pause = state.parsing_ext = false; + if (!memcmp(state.key_state.data(), pause, 6)) + { + state.key_state.clear_data(); + return KeyboardPacket { K_Pause, false }; + } + + state.key_state.clear_data(); + return KeyboardPacket { K_Unknown, false }; + } + } + + if (state.parsing_ext) + { + if (scancode == 0xe0 && state.key_state.size() == 2) + { + state.key_state.try_append(scancode).release_value(); + return {}; + } + + if (state.key_state.size() == 3) + { + state.key_state.try_append(scancode).release_value(); + if (!memcmp(state.key_state.data(), print_screen_pressed, 4)) + { + state.parsing_ext = false; + state.key_state.clear_data(); + return KeyboardPacket { K_PrtScr, false }; + } + + if (!memcmp(state.key_state.data(), print_screen_released, 4)) + { + state.parsing_ext = false; + state.key_state.clear_data(); + return KeyboardPacket { K_PrtScr, true }; + } + + state.parsing_ext = false; + state.key_state.clear_data(); + return KeyboardPacket { K_Unknown, false }; + } + + if (scancode == 0x2a || scancode == 0xb7) + { + state.key_state.try_append(scancode).release_value(); + return {}; + } + + bool released = is_key_released(scancode); + + KeyCode key = KeyCode::K_Unknown; + + if (scancode <= 0x6d) key = extended_keycode_table[scancode - 0x10]; + + state.parsing_ext = false; + state.key_state.clear_data(); + + return KeyboardPacket { key, released }; + } + + if (scancode == 0xe0) + { + state.parsing_ext = true; + state.key_state.try_append(scancode).release_value(); return {}; } - // FIXME: Support extended scancodes. - if (scancode == EXTENDED_KEY_CODE) + if (scancode == 0xe1) { - state.ignore_next = true; + state.parsing_pause = true; + state.key_state.try_append(scancode).release_value(); return {}; } bool released = is_key_released(scancode); - return KeyboardPacket { keycode_table[scancode], released }; + KeyCode key = KeyCode::K_Unknown; + + if (scancode <= 0x58) key = keycode_table[scancode]; + + return KeyboardPacket { key, released }; } }