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

@@ -8,6 +8,8 @@
#include "lapic.h"
#include "smp.h"
#include <stdbool.h>
#include "input/keyboard.h"
#include "input/keymap.h"
extern void serial_print(const char *s);
extern void serial_print_hex(uint64_t n);
@@ -20,28 +22,23 @@ uint64_t timer_handler(registers_t *regs) {
kernel_ticks++;
wm_timer_tick();
network_process_frames();
extern void k_beep_process(void);
k_beep_process();
}
outb(0x20, 0x20);
outb(0x20, 0x20);
extern uint64_t process_schedule(uint64_t current_rsp);
uint64_t new_rsp = process_schedule((uint64_t)regs);
if (smp_cpu_count() > 1) {
lapic_send_ipi_all();
}
return new_rsp;
}
// --- Keyboard ---
static bool shift_pressed = false;
static bool caps_lock_on = false;
bool ps2_ctrl_pressed = false;
static bool extended_scancode = false;
static void ps2_kbd_wait_write(void) {
uint32_t timeout = 100000;
while (timeout--) {
@@ -51,95 +48,29 @@ static void ps2_kbd_wait_write(void) {
static void ps2_update_leds(void) {
uint8_t led_status = 0;
if (caps_lock_on) led_status |= 4;
uint32_t mods = keyboard_get_modifiers();
if (mods & KB_MOD_CAPS) led_status |= 4;
if (mods & KB_MOD_NUM) led_status |= 2;
if (mods & KB_MOD_SCROLL) led_status |= 1;
ps2_kbd_wait_write();
outb(0x60, 0xED);
ps2_kbd_wait_write();
outb(0x60, led_status);
}
static char scancode_map[128] = {
0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
21, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0,
'\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, '*',
22, ' ', 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
static char scancode_map_shift[128] = {
0, 27, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b',
'\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n',
21, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', 0,
'|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 0, '*',
22, ' ', 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
uint64_t keyboard_handler(registers_t *regs) {
uint8_t scancode = inb(0x60);
if (scancode == 0xE0) {
extended_scancode = true;
outb(0x20, 0x20);
return (uint64_t)regs;
}
if (scancode == 0x1D) {
ps2_ctrl_pressed = true;
extended_scancode = false;
} else if (scancode == 0x9D) {
ps2_ctrl_pressed = false;
extended_scancode = false;
}
if (scancode == 0x2A || scancode == 0x36) { // Shift Down
shift_pressed = true;
} else if (scancode == 0xAA || scancode == 0xB6) { // Shift Up
shift_pressed = false;
} else if (scancode == 0x3A) { // Caps Lock Down
caps_lock_on = !caps_lock_on;
ps2_update_leds();
} else if (!(scancode & 0x80)) { // Key Press
if (extended_scancode) {
extended_scancode = false;
switch (scancode) {
case 0x48: wm_handle_key(17, true); break; // Up arrow
case 0x50: wm_handle_key(18, true); break; // Down arrow
case 0x4B: wm_handle_key(19, true); break; // Left arrow
case 0x4D: wm_handle_key(20, true); break; // Right arrow
}
} else {
char c = shift_pressed ? scancode_map_shift[scancode] : scancode_map[scancode];
if (c) {
if (caps_lock_on) {
if (c >= 'a' && c <= 'z') c -= 32;
else if (c >= 'A' && c <= 'Z') c += 32;
}
wm_handle_key(c, true);
}
}
} else if (scancode & 0x80) { // Key release
if (extended_scancode) {
extended_scancode = false;
switch (scancode & 0x7F) { // Strip the release bit
case 0x48: wm_handle_key(17, false); break; // Up arrow
case 0x50: wm_handle_key(18, false); break; // Down arrow
case 0x4B: wm_handle_key(19, false); break; // Left arrow
case 0x4D: wm_handle_key(20, false); break; // Right arrow
}
} else {
uint8_t base_scancode = scancode & 0x7F;
char c = shift_pressed ? scancode_map_shift[base_scancode] : scancode_map[base_scancode];
if (c) {
if (caps_lock_on) {
if (c >= 'a' && c <= 'z') c -= 32;
else if (c >= 'A' && c <= 'Z') c += 32;
}
wm_handle_key(c, false);
}
keyboard_event_t ev;
if (keyboard_handle_set1_scancode(scancode, &ev)) {
// Update LEDs if a lock key state changed
if (ev.keycode == KEY_CAPS_LOCK || ev.keycode == KEY_NUM_LOCK || ev.keycode == KEY_SCROLL_LOCK) {
if (ev.pressed) ps2_update_leds();
}
wm_handle_key_event(ev.keycode, ev.codepoint, ev.mods, ev.pressed);
}
outb(0x20, 0x20); // EOI
@@ -178,11 +109,11 @@ uint8_t mouse_read(void) {
void mouse_init(void) {
uint8_t status;
// Enable Aux Device
mouse_wait(0);
outb(0x64, 0xA8);
// Enable Interrupts
mouse_wait(0);
outb(0x64, 0x20);
@@ -192,7 +123,7 @@ void mouse_init(void) {
outb(0x64, 0x60);
mouse_wait(0);
outb(0x60, status);
// Set Defaults
mouse_write(0xF6);
mouse_read();
@@ -201,12 +132,12 @@ void mouse_init(void) {
mouse_write(0xF3); mouse_read(); mouse_write(200); mouse_read();
mouse_write(0xF3); mouse_read(); mouse_write(100); mouse_read();
mouse_write(0xF3); mouse_read(); mouse_write(80); mouse_read();
mouse_write(0xF2);
mouse_read();
uint8_t id = mouse_read();
if (id == 3) mouse_has_wheel = true;
// Enable Streaming
mouse_write(0xF4);
mouse_read();
@@ -217,11 +148,11 @@ uint64_t mouse_handler(registers_t *regs) {
if (!(status & 0x20)) {
outb(0x20, 0x20);
outb(0xA0, 0x20);
return (uint64_t)regs;
return (uint64_t)regs;
}
uint8_t b = inb(0x60);
if (mouse_cycle == 0) {
if ((b & 0x08) == 0) {
// Out of sync
@@ -257,9 +188,12 @@ uint64_t mouse_handler(registers_t *regs) {
}
void ps2_init(void) {
keymap_init();
keyboard_init();
mouse_init();
ps2_update_leds();
}
bool ps2_shift_pressed(void) {
return shift_pressed;
}
return keyboard_shift_pressed();
}