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:
+66
-55
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user