fix(gui): isolate keyboard buffer between sh and gui, eliminate cursor desync with sign validation, and optimize event loop timing

This commit is contained in:
RarDog
2026-09-02 21:01:29 +03:00
parent 0b9e60d1c6
commit 9cf6758fd4
5 changed files with 133 additions and 78 deletions
+66 -55
View File
@@ -3,8 +3,8 @@
* Windows / KDE-inspired Desktop Environment powered by LVGL v8.3.
* Features:
* - Custom 16x24 high-contrast hardware arrow cursor on lv_layer_sys()
* - Window dragging by titlebar with smooth clamping
* - Full PS/2 keyboard integration for typing in terminal
* - Smooth window dragging with boundary clamping
* - Dedicated PS/2 keyboard integration for terminal
* - Bottom Taskbar with Start Menu, Running App tabs & System Tray
* - Interactive Terminal (Console) application with real system commands
* - Task Manager with real-time CPU chart & thread table
@@ -99,12 +99,13 @@ static void mouse_read_cb(lv_indev_drv_t *drv, lv_indev_data_t *data) {
data->state = (mouse.buttons & 1) ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
}
// Keyboard read callback: queries microkernel SYS_KEY_READ
// Keyboard read callback: queries microkernel SYS_KEY_READ in Mode 2 (exclusive PS/2)
static void keyboard_read_cb(lv_indev_drv_t *drv, lv_indev_data_t *data) {
(void)drv;
uint64_t ch = 0;
register uint64_t rax __asm__("rax") = SYS_KEY_READ;
__asm__ volatile("syscall" : "=a"(ch) : "a"(rax) : "rcx", "r11", "memory");
register uint64_t rdi __asm__("rdi") = 2; // Mode 2: PS/2 Keyboard buffer only
__asm__ volatile("syscall" : "=a"(ch) : "a"(rax), "r"(rdi) : "rcx", "r11", "memory");
if (ch != 0) {
data->state = LV_INDEV_STATE_PRESSED;
@@ -207,6 +208,9 @@ static void toggle_window(lv_obj_t *win) {
if (lv_obj_has_flag(win, LV_OBJ_FLAG_HIDDEN)) {
lv_obj_clear_flag(win, LV_OBJ_FLAG_HIDDEN);
lv_obj_move_foreground(win);
if (win == g_win_console && g_input_group && g_ta_term_input) {
lv_group_focus_obj(g_ta_term_input);
}
} else {
lv_obj_add_flag(win, LV_OBJ_FLAG_HIDDEN);
}
@@ -216,6 +220,9 @@ static void toggle_window(lv_obj_t *win) {
static void open_window(lv_obj_t *win) {
lv_obj_clear_flag(win, LV_OBJ_FLAG_HIDDEN);
lv_obj_move_foreground(win);
if (win == g_win_console && g_input_group && g_ta_term_input) {
lv_group_focus_obj(g_ta_term_input);
}
}
// Start menu toggle
@@ -248,6 +255,9 @@ static void win_focus_event_cb(lv_event_t *e) {
lv_obj_t *win = (lv_obj_t *)lv_event_get_user_data(e);
if (win) {
lv_obj_move_foreground(win);
if (win == g_win_console && g_input_group && g_ta_term_input) {
lv_group_focus_obj(g_ta_term_input);
}
}
}
@@ -262,7 +272,7 @@ static void poweroff_event_cb(lv_event_t *e) {
static void execute_console_command(const char *cmd) {
if (!cmd || !g_txt_term_output) return;
// Strip leading / trailing whitespace
// Strip leading whitespace
while (*cmd == ' ') cmd++;
if (!*cmd) return;
@@ -422,7 +432,7 @@ static lv_obj_t *create_styled_window(lv_obj_t *parent, const char *title, int32
lv_obj_set_style_border_width(header, 1, 0);
lv_win_add_title(win, title);
// Make titlebar draggable to move window!
// Make titlebar draggable to move window smoothly!
lv_obj_add_flag(header, LV_OBJ_FLAG_CLICKABLE);
lv_obj_add_event_cb(header, win_drag_event_cb, LV_EVENT_PRESSING, win);
@@ -520,6 +530,7 @@ static void create_desktop_environment() {
lv_obj_align(g_ta_term_input, LV_ALIGN_LEFT_MID, 160, 0);
lv_textarea_set_one_line(g_ta_term_input, true);
lv_textarea_set_placeholder_text(g_ta_term_input, "Enter command...");
lv_textarea_set_cursor_click_pos(g_ta_term_input, true);
lv_obj_set_style_bg_color(g_ta_term_input, lv_color_hex(0x1a2233), 0);
lv_obj_set_style_border_width(g_ta_term_input, 0, 0);
lv_obj_set_style_text_color(g_ta_term_input, lv_color_hex(0xffffff), 0);
@@ -846,7 +857,7 @@ static void create_desktop_environment() {
lv_indev_set_cursor(g_mouse_indev, cursor_obj);
}
// Background metrics updater (called every ~500ms)
// Background metrics updater (called once every ~1 second)
static void update_live_metrics() {
char buf[128];
@@ -886,51 +897,52 @@ static void update_live_metrics() {
lv_label_set_text(g_lbl_tray_clock, buf);
}
// 3. CPU Load History Chart
static uint32_t s_prev_ticks[16] = {0};
thread_info_t threads[16];
memset(threads, 0, sizeof(threads));
rax = SYS_PROC_LIST;
rdi = (uint64_t)threads;
register uint64_t rsi __asm__("rsi") = 16;
__asm__ volatile("syscall" : "+r"(rax) : "r"(rdi), "r"(rsi) : "rcx", "r11", "memory");
int count = (int)rax;
// 3. CPU Load History Chart & Process Table (ONLY when Task Manager is visible!)
if (g_win_taskmgr && !lv_obj_has_flag(g_win_taskmgr, LV_OBJ_FLAG_HIDDEN)) {
static uint32_t s_prev_ticks[16] = {0};
thread_info_t threads[16];
memset(threads, 0, sizeof(threads));
rax = SYS_PROC_LIST;
rdi = (uint64_t)threads;
register uint64_t rsi __asm__("rsi") = 16;
__asm__ volatile("syscall" : "+r"(rax) : "r"(rdi), "r"(rsi) : "rcx", "r11", "memory");
int count = (int)rax;
uint32_t total_delta = 0;
for (int i = 0; i < count; i++) {
uint32_t delta = (threads[i].cpu_ticks >= s_prev_ticks[i]) ?
(threads[i].cpu_ticks - s_prev_ticks[i]) : 0;
s_prev_ticks[i] = threads[i].cpu_ticks;
if (threads[i].tid != 0) { // Exclude idle thread
total_delta += delta;
}
}
uint32_t cpu_percent = total_delta * 4;
if (cpu_percent > 100) cpu_percent = 100;
if (cpu_percent < 5) cpu_percent = 5;
if (g_chart_cpu && g_ser_cpu) {
lv_chart_set_next_value(g_chart_cpu, g_ser_cpu, (lv_coord_t)cpu_percent);
}
// 4. Update Process Table
if (g_tbl_procs) {
lv_table_set_row_cnt(g_tbl_procs, count + 1);
uint32_t total_delta = 0;
for (int i = 0; i < count; i++) {
char tid_str[16];
snprintf(tid_str, sizeof(tid_str), "%u", threads[i].tid);
lv_table_set_cell_value(g_tbl_procs, i + 1, 0, tid_str);
lv_table_set_cell_value(g_tbl_procs, i + 1, 1, threads[i].name);
uint32_t delta = (threads[i].cpu_ticks >= s_prev_ticks[i]) ?
(threads[i].cpu_ticks - s_prev_ticks[i]) : 0;
s_prev_ticks[i] = threads[i].cpu_ticks;
if (threads[i].tid != 0) { // Exclude idle thread
total_delta += delta;
}
}
const char *st = (threads[i].state == 0) ? "READY" :
(threads[i].state == 1) ? "RUNNING" :
(threads[i].state == 2) ? "BLOCKED" : "DEAD";
lv_table_set_cell_value(g_tbl_procs, i + 1, 2, st);
uint32_t cpu_percent = total_delta * 4;
if (cpu_percent > 100) cpu_percent = 100;
if (cpu_percent < 5) cpu_percent = 5;
char tick_str[16];
snprintf(tick_str, sizeof(tick_str), "%u", (unsigned int)threads[i].cpu_ticks);
lv_table_set_cell_value(g_tbl_procs, i + 1, 3, tick_str);
if (g_chart_cpu && g_ser_cpu) {
lv_chart_set_next_value(g_chart_cpu, g_ser_cpu, (lv_coord_t)cpu_percent);
}
if (g_tbl_procs) {
lv_table_set_row_cnt(g_tbl_procs, count + 1);
for (int i = 0; i < count; i++) {
char tid_str[16];
snprintf(tid_str, sizeof(tid_str), "%u", threads[i].tid);
lv_table_set_cell_value(g_tbl_procs, i + 1, 0, tid_str);
lv_table_set_cell_value(g_tbl_procs, i + 1, 1, threads[i].name);
const char *st = (threads[i].state == 0) ? "READY" :
(threads[i].state == 1) ? "RUNNING" :
(threads[i].state == 2) ? "BLOCKED" : "DEAD";
lv_table_set_cell_value(g_tbl_procs, i + 1, 2, st);
char tick_str[16];
snprintf(tick_str, sizeof(tick_str), "%u", (unsigned int)threads[i].cpu_ticks);
lv_table_set_cell_value(g_tbl_procs, i + 1, 3, tick_str);
}
}
}
}
@@ -986,19 +998,18 @@ int main() {
printf("[GUI-SERVER] Windows/KDE Desktop UI Initialized. Entering Compositor Event Loop.\n");
// 7. Compositor Event Loop
uint32_t tick_counter = 0;
uint32_t loop_count = 0;
while (1) {
lv_task_handler();
lv_tick_inc(10);
lv_tick_inc(5);
tick_counter++;
if (tick_counter % 50 == 0) { // Every ~500ms
loop_count++;
if (loop_count % 200 == 0) { // Every ~1000ms
update_live_metrics();
}
// Cooperative yield to microkernel scheduler for snappy, silky smooth interaction
register uint64_t rax __asm__("rax") = SYS_THREAD_YIELD;
__asm__ volatile("syscall" : "+r"(rax) : : "rcx", "r11", "memory");
// Calibrated delay (~5ms) for smooth interaction without high CPU load
for (volatile int d = 0; d < 8000; d++);
}
return 0;