diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 9171dae9..6dac60f5 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -61,6 +61,7 @@ set(SOURCES src/fs/devices/FramebufferDevice.cpp src/fs/devices/UARTDevice.cpp src/fs/devices/MouseDevice.cpp + src/fs/devices/KeyboardDevice.cpp src/fs/InitRD.cpp src/binfmt/ELF.cpp src/binfmt/BinaryFormat.cpp diff --git a/kernel/src/api/Keyboard.h b/kernel/src/api/Keyboard.h new file mode 100644 index 00000000..6222a7ec --- /dev/null +++ b/kernel/src/api/Keyboard.h @@ -0,0 +1,131 @@ +#pragma once +#include + +namespace moon +{ + enum KeyCode : u8 + { + // Function keys + K_F1, + K_F2, + K_F3, + K_F4, + K_F5, + K_F6, + K_F7, + K_F8, + K_F9, + K_F10, + K_F11, + K_F12, + // System keys + K_Esc, + K_PrtScr, + K_Pause, + K_Super, + K_Menu, + // Modifier keys + K_LeftShift, + K_RightShift, + K_LeftAlt, + K_RightAlt, // or AltGr on some keyboards + K_LeftControl, + K_RightControl, + // Navigation keys + K_Tab, + K_Home, + K_End, + K_PageUp, + K_PageDown, + K_RightArrow, + K_LeftArrow, + K_UpArrow, + K_DownArrow, + // Editing keys + K_Backspace, + K_Enter, + K_Insert, + K_Delete, + K_KeypadEnter, + // Lock keys + K_ScrollLock, + K_CapsLock, + K_NumLock, + // Keypad keys + K_Keypad0, + K_Keypad1, + K_Keypad2, + K_Keypad3, + K_Keypad4, + K_Keypad5, + K_Keypad6, + K_Keypad7, + K_Keypad8, + K_Keypad9, + K_KeypadDot, + K_KeypadPlus, + K_KeypadMinus, + K_KeypadMul, + K_KeypadDiv, + // Character keys (depending on keyboard layout), examples in US QWERTY + K_CH00, // ` + K_CH01, // 1 + K_CH02, // 2 + K_CH03, // 3 + K_CH04, // 4 + K_CH05, // 5 + K_CH06, // 6 + K_CH07, // 7 + K_CH08, // 8 + K_CH09, // 9 + K_CH10, // 0 + K_CH11, // - + K_CH12, // = + K_CH13, // Q + K_CH14, // W + K_CH15, // E + K_CH16, // R + K_CH17, // T + K_CH18, // Y + K_CH19, // U + K_CH20, // I + K_CH21, // O + K_CH22, // P + K_CH23, // [ + K_CH24, // ] + K_CH25, // A + K_CH26, // S + K_CH27, // D + K_CH28, // F + K_CH29, // G + K_CH30, // H + K_CH31, // J + K_CH32, // K + K_CH33, // L + K_CH34, // ; + K_CH35, // ' + K_CH36, // # + K_CH37, // Backslash + K_CH38, // Z + K_CH39, // X + K_CH40, // C + K_CH41, // V + K_CH42, // B + K_CH43, // N + K_CH44, // M + K_CH45, // , + K_CH46, // . + K_CH47, // / + K_CH48, // Space + // Unknown key + K_Unknown, + }; + + struct [[gnu::packed]] KeyboardPacket + { + u8 key; + bool released; + }; + + static_assert(sizeof(KeyboardPacket) == 2); +} diff --git a/kernel/src/arch/Keyboard.h b/kernel/src/arch/Keyboard.h index f91c4ff6..f705f514 100644 --- a/kernel/src/arch/Keyboard.h +++ b/kernel/src/arch/Keyboard.h @@ -1,9 +1,10 @@ #pragma once +#include "api/Keyboard.h" #include namespace Keyboard { - struct KeyboardState + struct TTYKeyboardState { bool ignore_next { false }; bool left_shift { false }; @@ -12,5 +13,12 @@ namespace Keyboard bool capslock { false }; }; - Option decode_scancode_tty(u8 scancode, KeyboardState& state); + struct KeyboardState + { + bool ignore_next { 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 f8fccacf..6eb071b6 100644 --- a/kernel/src/arch/x86_64/Keyboard.cpp +++ b/kernel/src/arch/x86_64/Keyboard.cpp @@ -113,7 +113,71 @@ constexpr char shifted_key_table[] = { '.', // keypad . }; -static bool is_shifted(const Keyboard::KeyboardState& state) +using namespace moon; + +constexpr KeyCode keycode_table[] = { + K_Unknown, K_Esc, + K_CH01, // 1 + K_CH02, // 2 + K_CH03, // 3 + K_CH04, // 4 + K_CH05, // 5 + K_CH06, // 6 + K_CH07, // 7 + K_CH08, // 8 + K_CH09, // 9 + K_CH10, // 0 + K_CH11, // - + K_CH12, // = + K_Backspace, K_Tab, + K_CH13, // Q + K_CH14, // W + K_CH15, // E + K_CH16, // R + K_CH17, // T + K_CH18, // Y + K_CH19, // U + K_CH20, // I + K_CH21, // O + K_CH22, // P + K_CH23, // [ + K_CH24, // ] + K_Enter, K_LeftControl, + K_CH25, // A + K_CH26, // S + K_CH27, // D + K_CH28, // F + K_CH29, // G + K_CH30, // H + K_CH31, // J + K_CH32, // K + K_CH33, // L + K_CH34, // ; + K_CH35, // ' + K_CH00, // ` + K_LeftShift, + K_CH36, // # + K_CH38, // Z + K_CH39, // X + K_CH40, // C + K_CH41, // V + K_CH42, // B + K_CH43, // N + K_CH44, // M + K_CH45, // , + K_CH46, // . + K_CH47, // / + K_RightShift, K_KeypadMul, K_LeftAlt, + K_CH48, // Space + K_CapsLock, K_F1, K_F2, K_F3, K_F4, K_F5, K_F6, + K_F7, K_F8, K_F9, K_F10, K_NumLock, K_ScrollLock, K_Keypad7, + K_Keypad8, K_Keypad9, K_KeypadMinus, K_Keypad4, K_Keypad5, K_Keypad6, K_KeypadPlus, + K_Keypad1, K_Keypad2, K_Keypad3, K_Keypad0, K_KeypadDot, K_Unknown, K_Unknown, + K_CH37, // Backslash + 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; @@ -121,7 +185,7 @@ static bool is_shifted(const Keyboard::KeyboardState& state) namespace Keyboard { - Option decode_scancode_tty(u8 scancode, KeyboardState& state) + Option decode_scancode_tty(u8 scancode, TTYKeyboardState& state) { if (state.ignore_next) { @@ -184,4 +248,24 @@ namespace Keyboard if (is_shifted(state)) return shifted_key_table[scancode]; return key_table[scancode]; } + + Option decode_scancode(u8 scancode, KeyboardState& 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); + + return KeyboardPacket { keycode_table[scancode], released }; + } } diff --git a/kernel/src/fs/devices/ConsoleDevice.cpp b/kernel/src/fs/devices/ConsoleDevice.cpp index 52cafa66..9e21cb86 100644 --- a/kernel/src/fs/devices/ConsoleDevice.cpp +++ b/kernel/src/fs/devices/ConsoleDevice.cpp @@ -1,6 +1,7 @@ #include "fs/devices/ConsoleDevice.h" #include "Log.h" #include "fs/devices/DeviceRegistry.h" +#include "fs/devices/KeyboardDevice.h" #include "memory/MemoryManager.h" #include "thread/Scheduler.h" #include "video/TextConsole.h" @@ -61,7 +62,7 @@ Result ConsoleDevice::write(const u8* buf, usize, usize length) { if (m_settings.c_lflag & TOSTOP) TRY(handle_background_process_group(true, SIGTTOU)); - if (s_is_in_graphical_mode) return length; + // if (s_is_in_graphical_mode) return length; TextConsole::write((const char*)buf, length); return length; @@ -74,7 +75,14 @@ bool ConsoleDevice::will_block_if_read() const void ConsoleDevice::did_press_or_release_key(u8 scancode) { - for (const auto& device : m_console_devices) { device->process_key_event(scancode); } + if (!s_is_in_graphical_mode) + for (const auto& device : m_console_devices) { device->process_key_event(scancode); } + else + { + static Keyboard::KeyboardState state = {}; + auto packet = Keyboard::decode_scancode(scancode, state); + if (packet.has_value()) KeyboardDevice::add_keyboard_event(packet.release_value()); + } } void ConsoleDevice::process_key_event(u8 scancode) diff --git a/kernel/src/fs/devices/ConsoleDevice.h b/kernel/src/fs/devices/ConsoleDevice.h index db457400..a301cdd9 100644 --- a/kernel/src/fs/devices/ConsoleDevice.h +++ b/kernel/src/fs/devices/ConsoleDevice.h @@ -37,7 +37,7 @@ class ConsoleDevice : public Device mutable Buffer m_input_buffer; Option m_foreground_process_group {}; Vector m_line_buffer; - mutable Keyboard::KeyboardState m_kb_state; + mutable Keyboard::TTYKeyboardState m_kb_state; static Vector> m_console_devices; static bool s_is_in_graphical_mode; diff --git a/kernel/src/fs/devices/DeviceRegistry.cpp b/kernel/src/fs/devices/DeviceRegistry.cpp index ca792e85..33d6a946 100644 --- a/kernel/src/fs/devices/DeviceRegistry.cpp +++ b/kernel/src/fs/devices/DeviceRegistry.cpp @@ -4,6 +4,7 @@ #include "fs/devices/ConsoleDevice.h" #include "fs/devices/FramebufferDevice.h" #include "fs/devices/FullDevice.h" +#include "fs/devices/KeyboardDevice.h" #include "fs/devices/MouseDevice.h" #include "fs/devices/NullDevice.h" #include "fs/devices/UARTDevice.h" @@ -72,6 +73,7 @@ namespace DeviceRegistry FramebufferDevice::create(); UARTDevice::create(); MouseDevice::create(); + KeyboardDevice::create(); return {}; } diff --git a/kernel/src/fs/devices/KeyboardDevice.cpp b/kernel/src/fs/devices/KeyboardDevice.cpp new file mode 100644 index 00000000..71718c99 --- /dev/null +++ b/kernel/src/fs/devices/KeyboardDevice.cpp @@ -0,0 +1,34 @@ +#include "fs/devices/KeyboardDevice.h" + +SharedPtr KeyboardDevice::s_keyboard_device = {}; + +Result KeyboardDevice::create() +{ + auto device = TRY(make_shared()); + s_keyboard_device = device; + return DeviceRegistry::register_special_device(DeviceRegistry::Input, 1, device, 0600); +} + +Result KeyboardDevice::read(u8* buf, usize, usize length) const +{ + length = m_packet_buffer.dequeue_data(buf, length); + + return length; +} + +Result KeyboardDevice::write(const u8* buf, usize, usize length) +{ + TRY(m_packet_buffer.append_data(buf, length)); + + return length; +} + +void KeyboardDevice::add_keyboard_event(const moon::KeyboardPacket& packet) +{ + if (s_keyboard_device) s_keyboard_device->write((const u8*)&packet, 0, sizeof(packet)); +} + +bool KeyboardDevice::will_block_if_read() const +{ + return !m_packet_buffer.size(); +} diff --git a/kernel/src/fs/devices/KeyboardDevice.h b/kernel/src/fs/devices/KeyboardDevice.h new file mode 100644 index 00000000..0c7170e2 --- /dev/null +++ b/kernel/src/fs/devices/KeyboardDevice.h @@ -0,0 +1,31 @@ +#pragma once +#include "api/Keyboard.h" +#include "fs/devices/DeviceRegistry.h" +#include + +class KeyboardDevice : public Device +{ + public: + // Initializer for DeviceRegistry. + static Result create(); + + Result read(u8*, usize, usize) const override; + + Result write(const u8*, usize, usize) override; + + static void add_keyboard_event(const moon::KeyboardPacket& packet); + + bool will_block_if_read() const override; + + StringView device_path() const override + { + return "kbd"; + } + + virtual ~KeyboardDevice() = default; + + private: + mutable Buffer m_packet_buffer; + + static SharedPtr s_keyboard_device; +};