feature(input): implement keyboard layouts and utf-8 input subsystem

* Adding keyboard layout (backend)

* Update settings.c with new keyboard tab

* Fixing keyboard icon && Fixing long loading time in settings.c

* Refactor of key handling for a larger compatibility with the keyboard layout

* Adding keyboard handler

* Udating ps2.c with the new logic

* Updating WM/kernel/userland with the new input system

* Fixing keycode range && Updating dead keys handling

* Add comments for explanation

* Update notepad & vm.c to parse utf-8

* Adding utf-8 parsing utils in libc && Update notepad.c

* Adding icon for icon settings

* Fixing a warning with double definition

* Adding new kb kayout: QWERTZ and DVORAK && Update new layout instrauction

* Add documentation for keyboard input subsystem

This document outlines the architecture and design of the input subsystem, focusing on keyboard input processing, driver responsibilities, keycode representation, and keymap functionality.

---------

Co-authored-by: boreddevnl <chris@boreddev.nl>
This commit is contained in:
Lluciocc
2026-04-23 21:31:52 +02:00
committed by GitHub
parent 228b5753d9
commit 915e33434e
22 changed files with 1624 additions and 275 deletions

View File

@@ -1414,7 +1414,12 @@ static void explorer_handle_click(Window *win, int x, int y) {
}
}
static void explorer_handle_key(Window *win, char c, bool pressed) {
static void explorer_handle_key(Window *win, int legacy, uint16_t keycode, uint32_t codepoint, uint32_t mods, bool pressed) {
(void)keycode;
(void)codepoint;
(void)mods;
char c = (char)legacy;
if (!pressed) return;
ExplorerState *state = (ExplorerState*)win->data;

View File

@@ -34,9 +34,10 @@
typedef struct {
int type;
int arg1; // For click: x
int arg2; // For click: y
int arg3; // For click: button state
int arg1; // CLICK: x / KEY: legacy char-or-compat key
int arg2; // CLICK: y / KEY: keycode
int arg3; // CLICK: button state / KEY: modifier mask
int arg4; // KEY: Unicode codepoint (0 if none)
} gui_event_t;
#endif

View File

@@ -22,6 +22,8 @@
#include "../sys/work_queue.h"
#include "../sys/smp.h"
#include "../core/kconsole.h"
#include "../input/keycodes.h"
#include "../input/keymap.h"
// Hello developer,
@@ -30,7 +32,7 @@
// TRUST ME.
// If you do decide to hate yourself for some dumb reason,
// add a few hours to the counter of despair:
// hours wasted: 57
// hours wasted: 61
// send help
#include "../sys/spinlock.h"
@@ -98,7 +100,7 @@ static char notif_text[256] = {0};
static int notif_timer = 0;
static int notif_x_offset = 420; // Starts offscreen
static bool notif_active = false;
extern bool ps2_ctrl_pressed;
static lumos_state_t lumos_state = {0};
static bool lumos_index_built = false;
@@ -3652,14 +3654,18 @@ void wm_handle_mouse(int dx, int dy, uint8_t buttons, int dz) {
// Input Queue
#define INPUT_QUEUE_SIZE 128
typedef struct {
char c;
int legacy;
uint16_t keycode;
uint32_t codepoint;
uint32_t mods;
bool pressed;
} key_event_t;
static key_event_t key_queue[INPUT_QUEUE_SIZE];
static volatile int key_head = 0;
static volatile int key_tail = 0;
static void wm_dispatch_key(char c, bool pressed) {
static void wm_dispatch_key(int legacy, uint16_t keycode, uint32_t codepoint, uint32_t mods, bool pressed) {
char c = (char)legacy;
if (desktop_dialog_state != 0) {
int len = 0; while(desktop_dialog_input[len]) len++;
if (c == '\n') {
@@ -3721,7 +3727,7 @@ static void wm_dispatch_key(char c, bool pressed) {
if (target->handle_key) {
target->handle_key(target, c, pressed);
target->handle_key(target, legacy, keycode, codepoint, mods, pressed);
}
// Mark window as needing redraw on next timer tick
@@ -3748,18 +3754,20 @@ static void build_file_index_async(void *arg) {
file_index_build();
}
void wm_handle_key(char c, bool pressed) {
if (pressed && c == 'p' && ps2_ctrl_pressed) {
// Called by keyboard interrupt handler
void wm_handle_key_event(uint16_t keycode, uint32_t codepoint, uint32_t mods, bool pressed) {
int legacy = keymap_legacy_key(keycode, codepoint);
char c = (char)legacy;
if (pressed && keycode == KEY_P && (mods & KB_MOD_CTRL)) {
process_create_elf("/bin/screenshot.elf", NULL, false, -1);
return;
}
if (pressed && c == ' ' && ps2_ctrl_pressed && ps2_shift_pressed()) {
if (pressed && keycode == KEY_SPACE && (mods & KB_MOD_CTRL) && (mods & KB_MOD_SHIFT)) {
lumos_state.visible = !lumos_state.visible;
if (lumos_state.visible) {
// Check current index status - it may still be building in background
lumos_index_built = file_index_is_valid();
// Clear search state when opening
lumos_state.search_len = 0;
lumos_state.search_query[0] = 0;
lumos_state.cursor_pos = 0;
@@ -3772,15 +3780,18 @@ void wm_handle_key(char c, bool pressed) {
force_redraw = true;
return;
}
if (lumos_state.visible && pressed) {
if (lumos_state.visible && pressed && legacy != 0) {
wm_lumos_handle_key(c);
return;
}
int next = (key_head + 1) % INPUT_QUEUE_SIZE;
if (next != key_tail) {
key_queue[key_head].c = c;
key_queue[key_head].legacy = legacy;
key_queue[key_head].keycode = keycode;
key_queue[key_head].codepoint = codepoint;
key_queue[key_head].mods = mods;
key_queue[key_head].pressed = pressed;
key_head = next;
}
@@ -3801,7 +3812,7 @@ void wm_process_input(void) {
while (key_head != key_tail) {
key_event_t ev = key_queue[key_tail];
key_tail = (key_tail + 1) % INPUT_QUEUE_SIZE;
wm_dispatch_key(ev.c, ev.pressed);
wm_dispatch_key(ev.legacy, ev.keycode, ev.codepoint, ev.mods, ev.pressed);
}
wm_lock_release(rflags);

View File

@@ -60,7 +60,7 @@ struct Window {
// Callbacks
void (*paint)(Window *win);
void (*handle_key)(Window *win, char c, bool pressed);
void (*handle_key)(Window *win, int legacy, uint16_t keycode, uint32_t codepoint, uint32_t mods, bool pressed);
void (*handle_click)(Window *win, int x, int y);
void (*handle_right_click)(Window *win, int x, int y);
void (*handle_mouse_down)(Window *win, int x, int y);
@@ -91,7 +91,7 @@ typedef struct {
void wm_init(void);
void wm_handle_mouse(int dx, int dy, uint8_t buttons, int dz);
void wm_handle_key(char c, bool pressed);
void wm_handle_key_event(uint16_t keycode, uint32_t codepoint, uint32_t mods, bool pressed);
void wm_handle_click(int x, int y);
void wm_handle_right_click(int x, int y);
void wm_process_input(void);