kernel: Add a keyboard device for graphical session

This commit is contained in:
apio 2023-08-02 17:20:13 +02:00
parent 9c1e275f34
commit 4794d0dfef
Signed by: apio
GPG Key ID: B8A7D06E42258954
9 changed files with 306 additions and 7 deletions

View File

@ -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

131
kernel/src/api/Keyboard.h Normal file
View File

@ -0,0 +1,131 @@
#pragma once
#include <luna/Types.h>
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);
}

View File

@ -1,9 +1,10 @@
#pragma once
#include "api/Keyboard.h"
#include <luna/Option.h>
namespace Keyboard
{
struct KeyboardState
struct TTYKeyboardState
{
bool ignore_next { false };
bool left_shift { false };
@ -12,5 +13,12 @@ namespace Keyboard
bool capslock { false };
};
Option<char> decode_scancode_tty(u8 scancode, KeyboardState& state);
struct KeyboardState
{
bool ignore_next { false };
};
Option<char> decode_scancode_tty(u8 scancode, TTYKeyboardState& state);
Option<moon::KeyboardPacket> decode_scancode(u8 scancode, KeyboardState& state);
}

View File

@ -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<char> decode_scancode_tty(u8 scancode, KeyboardState& state)
Option<char> 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<KeyboardPacket> 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 };
}
}

View File

@ -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<usize> 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)

View File

@ -37,7 +37,7 @@ class ConsoleDevice : public Device
mutable Buffer m_input_buffer;
Option<pid_t> m_foreground_process_group {};
Vector<u8> m_line_buffer;
mutable Keyboard::KeyboardState m_kb_state;
mutable Keyboard::TTYKeyboardState m_kb_state;
static Vector<SharedPtr<ConsoleDevice>> m_console_devices;
static bool s_is_in_graphical_mode;

View File

@ -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 {};
}

View File

@ -0,0 +1,34 @@
#include "fs/devices/KeyboardDevice.h"
SharedPtr<KeyboardDevice> KeyboardDevice::s_keyboard_device = {};
Result<void> KeyboardDevice::create()
{
auto device = TRY(make_shared<KeyboardDevice>());
s_keyboard_device = device;
return DeviceRegistry::register_special_device(DeviceRegistry::Input, 1, device, 0600);
}
Result<usize> KeyboardDevice::read(u8* buf, usize, usize length) const
{
length = m_packet_buffer.dequeue_data(buf, length);
return length;
}
Result<usize> 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();
}

View File

@ -0,0 +1,31 @@
#pragma once
#include "api/Keyboard.h"
#include "fs/devices/DeviceRegistry.h"
#include <luna/Buffer.h>
class KeyboardDevice : public Device
{
public:
// Initializer for DeviceRegistry.
static Result<void> create();
Result<usize> read(u8*, usize, usize) const override;
Result<usize> 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<KeyboardDevice> s_keyboard_device;
};