diff --git a/kernel/src/arch/syscall.rs b/kernel/src/arch/syscall.rs index 2ea9f42..73b0bc2 100644 --- a/kernel/src/arch/syscall.rs +++ b/kernel/src/arch/syscall.rs @@ -250,12 +250,41 @@ pub extern "C" fn kernel_syscall_dispatcher(regs: &mut SyscallRegisters) { // SYS_KEY_READ = 10 (Checks both Serial COM1 and PS/2 Keyboard buffer) 10 => { unsafe { - // 1. Check Serial Port (COM1) for direct terminal input in QEMU stdio + let sched = &*core::ptr::addr_of!(SCHEDULER); + let cur_tid = sched.current_tid; + let cur_name = sched.threads[cur_tid].name; + let is_gui = cur_name.starts_with("gui"); + let is_sh = cur_name.starts_with("sh"); + let gui_running = sched.threads.iter().any(|t| t.name.starts_with("gui") && t.state != crate::sched::thread::ThreadState::Unused); + + let mode = regs.rdi; // Optional explicit mode: 1 = Serial, 2 = Keyboard + + if mode == 2 || is_gui { + // GUI Server reads exclusively from PS/2 Keyboard buffer + let kbuf = &mut *core::ptr::addr_of_mut!(KEY_BUFFER); + if let Some(ch) = kbuf.pop() { + regs.rax = ch as u64; + return; + } + regs.rax = 0; + return; + } + + if mode == 1 || (is_sh && gui_running) { + // Shell reads exclusively from Serial COM1 when GUI is running + if let Some(ch) = SerialPort.read_byte() { + regs.rax = ch as u64; + return; + } + regs.rax = 0; + return; + } + + // Fallback (e.g. headless CLI mode): check Serial first, then Keyboard if let Some(ch) = SerialPort.read_byte() { regs.rax = ch as u64; return; } - // 2. Check PS/2 Keyboard buffer (Hardware / GUI) let kbuf = &mut *core::ptr::addr_of_mut!(KEY_BUFFER); if let Some(ch) = kbuf.pop() { regs.rax = ch as u64; diff --git a/kernel/src/drivers/mouse.rs b/kernel/src/drivers/mouse.rs index 8ca7763..3e9099e 100644 --- a/kernel/src/drivers/mouse.rs +++ b/kernel/src/drivers/mouse.rs @@ -74,8 +74,25 @@ impl MouseState { let raw_dx = self.packet[1]; let raw_dy = self.packet[2]; - // Discard invalid overflow packets (bit 6 = X overflow, bit 7 = Y overflow) - if (flags & 0xC0) != 0 { + // 1. Validate sync bit (bit 3 MUST be 1) and no overflow (bits 6, 7 MUST be 0) + if (flags & 0x08) == 0 || (flags & 0xC0) != 0 { + return; + } + + // 2. Reject reserved/error overflow values (0x80 = -128) + if raw_dx == 0x80 || raw_dy == 0x80 { + return; + } + + // 3. Verify sign bits in flags match bit 7 of raw_dx and raw_dy + // In standard PS/2: bit 4 is X sign, bit 5 is Y sign + let dx_neg_flag = (flags & 0x10) != 0; + let dy_neg_flag = (flags & 0x20) != 0; + let raw_dx_neg = (raw_dx & 0x80) != 0; + let raw_dy_neg = (raw_dy & 0x80) != 0; + + // If signs don't match, this is a corrupt/desynchronized packet! Discard! + if dx_neg_flag != raw_dx_neg || dy_neg_flag != raw_dy_neg { return; } @@ -87,19 +104,16 @@ impl MouseState { let mut dy = raw_dy as i8 as i32; // Strict delta clamping to prevent cursor jumps/teleportation at screen edges - if dx > 60 { dx = 60; } - if dx < -60 { dx = -60; } - if dy > 60 { dy = 60; } - if dy < -60 { dy = -60; } + if dx > 30 { dx = 30; } + if dx < -30 { dx = -30; } + if dy > 30 { dy = 30; } + if dy < -30 { dy = -30; } - // Smooth pointer scaling (responsive feel) - let step_x = if dx.abs() > 3 { dx * 3 / 2 } else { dx }; - let step_y = if dy.abs() > 3 { dy * 3 / 2 } else { dy }; + // Apply movement (Invert Y for screen coordinates: PS/2 +Y is up, screen +Y is down) + self.x += dx; + self.y -= dy; - self.x += step_x; - self.y -= step_y; // Invert Y for screen coordinates - - // Clamp strictly to screen boundaries + // Strict clamp to screen boundaries if self.x < 0 { self.x = 0; } if self.x >= self.max_x { self.x = self.max_x - 1; } if self.y < 0 { self.y = 0; } @@ -155,8 +169,8 @@ pub fn init(screen_w: i32, screen_h: i32) { #[no_mangle] pub extern "C" fn mouse_interrupt_handler() { unsafe { - let status = inb(PS2_COMMAND_PORT); - if (status & 0x01) != 0 { + while (inb(PS2_COMMAND_PORT) & 0x01) != 0 { + let status = inb(PS2_COMMAND_PORT); let data = inb(PS2_DATA_PORT); if (status & 0x20) != 0 { MOUSE_STATE.handle_byte(data); @@ -168,11 +182,13 @@ pub extern "C" fn mouse_interrupt_handler() { pub fn get_mouse_info() -> (i32, i32, u32) { unsafe { - // Drain any pending bytes in 8042 buffer + core::arch::asm!("cli"); while (inb(PS2_COMMAND_PORT) & 0x21) == 0x21 { let data = inb(PS2_DATA_PORT); MOUSE_STATE.handle_byte(data); } - (MOUSE_STATE.x, MOUSE_STATE.y, MOUSE_STATE.buttons) + let res = (MOUSE_STATE.x, MOUSE_STATE.y, MOUSE_STATE.buttons); + core::arch::asm!("sti"); + res } } diff --git a/kernel/src/sched/mod.rs b/kernel/src/sched/mod.rs index 6465329..8be395f 100644 --- a/kernel/src/sched/mod.rs +++ b/kernel/src/sched/mod.rs @@ -130,8 +130,7 @@ impl Scheduler { if self.threads[self.current_tid].state == ThreadState::Running { self.threads[self.current_tid].state = ThreadState::Ready; } - self.quantum_remaining = DEFAULT_QUANTUM_TICKS; - self.schedule(); + self.quantum_remaining = 0; } /// Preemptive tick called directly from timer ISR handler diff --git a/lib/lvgl/lv_conf.h b/lib/lvgl/lv_conf.h index 580f656..23692af 100644 --- a/lib/lvgl/lv_conf.h +++ b/lib/lvgl/lv_conf.h @@ -78,10 +78,10 @@ *====================*/ /*Default display refresh period. LVG will redraw changed areas with this period time*/ -#define LV_DISP_DEF_REFR_PERIOD 12 /*[ms] (~80 FPS)*/ +#define LV_DISP_DEF_REFR_PERIOD 16 /*[ms] (60 FPS)*/ /*Input device read period in milliseconds*/ -#define LV_INDEV_DEF_READ_PERIOD 10 /*[ms] (100 Hz polling)*/ +#define LV_INDEV_DEF_READ_PERIOD 16 /*[ms] (60 Hz polling)*/ /*Use a custom tick source that tells the elapsed time in milliseconds. *It removes the need to manually update the tick with `lv_tick_inc()`)*/ diff --git a/servers/gui_server/main.cpp b/servers/gui_server/main.cpp index 073a8b0..1089af4 100644 --- a/servers/gui_server/main.cpp +++ b/servers/gui_server/main.cpp @@ -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;