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

@@ -11,15 +11,8 @@
#include "ps2.h"
#include "kutils.h"
#include "io.h"
// --- Scancode Map (Set 1) ---
static char vm_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',
0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0,
'\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, '*',
0, ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
#include "input/keymap.h"
#include "input/keyboard.h"
// VM State
static int stack[VM_STACK_SIZE];
@@ -97,8 +90,22 @@ static void vm_syscall(int id) {
push(0);
break;
case VM_SYS_PRINT_CHAR: {
char c = (char)pop();
char s[2] = {c, 0};
uint32_t cp = (uint32_t)pop();
char s[5] = {0};
if (cp < 0x80) {
s[0] = cp;
} else if (cp < 0x800) {
s[0] = 0xC0 | (cp >> 6);
s[1] = 0x80 | (cp & 0x3F);
} else if (cp < 0x10000) {
s[0] = 0xE0 | (cp >> 12);
s[1] = 0x80 | ((cp >> 6) & 0x3F);
s[2] = 0x80 | (cp & 0x3F);
} else {
s[0] = '?';
}
cmd_write(s);
push(0);
break;
@@ -121,15 +128,32 @@ static void vm_syscall(int id) {
break;
case VM_SYS_GETCHAR: {
int c = 0;
// Blocking read for a valid key press
bool ext = false;
// Wait for a key press and return the ASCII code
while (1) {
if ((inb(0x64) & 1)) { // Data available
if ((inb(0x64) & 1)) { // Data available in keyboard controller
uint8_t sc = inb(0x60);
if (!(sc & 0x80)) { // Key press
if (sc < 128) {
c = vm_scancode_map[sc];
if (c) break;
if (sc == 0xE0) { // Extended scancode prefix
ext = true;
continue;
}
if (!(sc & 0x80)) { // Key press (not release)
uint16_t keycode = keyboard_keycode_from_set1((uint8_t)(sc & 0x7F), ext); // Get keycode and reset
ext = false;
if (keycode != KEY_NONE) {
uint32_t mods = keyboard_get_modifiers();
keymap_result_t r = keymap_translate_keycode(keycode, mods);
// Only return valid text characters, ignore modifiers and dead keys
if (r.is_text && !r.is_dead && r.codepoint >= 32 && r.codepoint != 127) {
c = (int)r.codepoint;
break;
}
}
} else {
ext = false;
}
}
}
@@ -545,7 +569,26 @@ int vm_exec(const uint8_t *code, int code_size) {
case OP_MUL: push(pop() * pop()); break;
case OP_DIV: { int b=pop(); int a=pop(); push(b==0?0:a/b); } break;
case OP_PRINT: cmd_write_int(pop()); cmd_write("\n"); break;
case OP_PRITC: { char c=(char)pop(); char s[2]={c,0}; cmd_write(s); } break;
case OP_PRITC: {
uint32_t cp = (uint32_t)pop();
char s[5] = {0};
if (cp < 0x80) {
s[0] = (char)cp;
} else if (cp < 0x800) {
s[0] = (char)(0xC0 | (cp >> 6));
s[1] = (char)(0x80 | (cp & 0x3F));
} else if (cp < 0x10000) {
s[0] = (char)(0xE0 | (cp >> 12));
s[1] = (char)(0x80 | ((cp >> 6) & 0x3F));
s[2] = (char)(0x80 | (cp & 0x3F));
} else {
s[0] = '?';
}
cmd_write(s);
break;
}
case OP_JMP: {
int addr = 0;
addr |= memory[pc++];
@@ -601,4 +644,4 @@ int vm_exec(const uint8_t *code, int code_size) {
}
wm_custom_paint_hook = NULL;
return 0;
}
}