From 2f4cf666c0c7bd224932fa48973e7334360c1de3 Mon Sep 17 00:00:00 2001 From: salmonik Date: Fri, 21 Aug 2026 20:13:59 +0200 Subject: input: total keyboard routing + per-terminal discipline (ADR 0006 ph1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit wm: FOCUSED is now a plain window id — window 0 (home terminal) is an ordinary focusable window in the z-order. The CONSOLE sentinel (usize::MAX) and the focused()==0 special cases are gone; focus_console() is an alias for focus(0). Desktop clicks focus window 0. The WM input pump routes every key unconditionally: IRQ ring -> pump -> focused window's owner; nothing polls the scancode rings directly any more. tty: read_line() reads from the calling task's message queue (the old global-ring read_line and the duplicate read_line_from_queue are merged); raw mode (read_byte/try_read_byte) consumes the same queue; interrupt_pressed drains the queue instead of the ring. shell: task 0 owns home terminal window 0 and blocks on its queue like a windowed shell; cat/hexdump stdin paths pass the home terminal handle. sched: watchdog comments updated (shell parks on recv_blocking). Verified in QEMU: F1 spawns terminals, F2 cycles focus home->term1-> term2, keystrokes land only in the focused window, ^C cancels a line, edit runs raw over the queue and exits to a working prompt; test-disk regression PASS. --- shell/src/lib.rs | 58 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 20 deletions(-) (limited to 'shell/src/lib.rs') diff --git a/shell/src/lib.rs b/shell/src/lib.rs index f2a0e6e..d1710cc 100644 --- a/shell/src/lib.rs +++ b/shell/src/lib.rs @@ -30,7 +30,9 @@ use alloc::vec::Vec; use rsnix::tty::{self, LineInput}; use rsnix::{gop_print, gop_println}; -/// Run the shell forever. +/// Run the home-terminal shell (task 0). The home terminal is an +/// ordinary WM window (id 0) owned by this task, so input flows through +/// the same pumped queue as any windowed shell. pub fn run() -> ! { // Row 0 is the boot-marker status line (white-on-black, the last boot // stage drawn during init). Real hardware has no serial console, so @@ -64,6 +66,7 @@ pub fn run() -> ! { } term_println("!!! end of crash report"); } + let term = rsnix::vt::home_terminal(); loop { // Push any deferred scrolls so the prompt renders on a current @@ -77,12 +80,18 @@ pub fn run() -> ! { } // Print prompt term_print("> "); - - // Read one line from keyboard (tty canonical mode) - match tty::read_line() { - LineInput::Interrupted => continue, // ^C - fresh prompt - LineInput::Eof => continue, // ^D on an empty line - fresh prompt (no poweroff) - LineInput::Line(line) => { + // Read one line (tty canonical mode over the pumped queue). + match tty::read_line(term) { + None => { + // Window 0 is never closed; a Close message here means + // shutdown. Park forever (the idle task takes over). + loop { + rsnix::sched::sleep_ms(1000); + } + } + Some(LineInput::Interrupted) => continue, // ^C - fresh prompt + Some(LineInput::Eof) => continue, // ^D - fresh prompt (no poweroff) + Some(LineInput::Line(line)) => { let trimmed = line.trim(); if trimmed.is_empty() { continue; @@ -94,15 +103,14 @@ pub fn run() -> ! { } /// Run a shell instance inside a windowed terminal. Same as `run()` but -/// reads from the task's message queue (Fed by the WM input pump) and -/// writes to the active terminal (set by the caller via `vt::set_active`). +/// for a spawned F1 terminal (own task + window). /// Returns when the window is closed (Close message or ^D on empty line). pub fn run_windowed(term: &mut rsnix::vt::Terminal) { term_println(&alloc::format!("rs-dos v{}", env!("CARGO_PKG_VERSION"))); loop { rsnix::vt::sync_scroll(); term_print("> "); - match tty::read_line_from_queue(term) { + match tty::read_line(term) { None => return, // window closed Some(LineInput::Interrupted) => continue, Some(LineInput::Eof) => return, // ^D in windowed mode = close @@ -1033,9 +1041,11 @@ fn cmd_cat(p: &Parsed) { /// Read lines from the tty until ^C/^D (or an exact marker line, when /// `marker` is Some - the marker itself is not part of the input). fn cat_stdin(pipe: &mut Pipeline, marker: Option<&str>) -> bool { + let term = rsnix::vt::home_terminal(); loop { - match tty::read_line() { - LineInput::Line(l) => { + match tty::read_line(term) { + None => return true, // window closed = EOF + Some(LineInput::Line(l)) => { if marker.is_some() && l.as_str() == marker.unwrap() { return true; } @@ -1043,8 +1053,8 @@ fn cat_stdin(pipe: &mut Pipeline, marker: Option<&str>) -> bool { return false; } } - LineInput::Interrupted => return false, // ^C aborts the stream - LineInput::Eof => return true, // ^D = EOF + Some(LineInput::Interrupted) => return false, // ^C aborts the stream + Some(LineInput::Eof) => return true, // ^D = EOF } } } @@ -1280,9 +1290,11 @@ fn hexdump_stdin(pipe: &mut Pipeline, marker: Option<&str>) { row_len: 0, alive: true, }; + let term = rsnix::vt::home_terminal(); loop { - match tty::read_line() { - LineInput::Line(l) => { + match tty::read_line(term) { + None => break, + Some(LineInput::Line(l)) => { if marker.is_some() && l.as_str() == marker.unwrap() { break; } @@ -1295,8 +1307,8 @@ fn hexdump_stdin(pipe: &mut Pipeline, marker: Option<&str>) { break; } } - LineInput::Interrupted => break, - LineInput::Eof => break, + Some(LineInput::Interrupted) => break, + Some(LineInput::Eof) => break, } } ctx.flush(); @@ -1429,7 +1441,11 @@ fn cmd_draw(_p: &Parsed) { fn cmd_term(_p: &Parsed) { // Debug: check if the callback is registered. - let cb_set = unsafe { core::ptr::addr_of!(rsnix::wm::SPAWN_TERMINAL_CB).read().is_some() }; + let cb_set = unsafe { + core::ptr::addr_of!(rsnix::wm::SPAWN_TERMINAL_CB) + .read() + .is_some() + }; term_println(&alloc::format!("term: SPAWN_TERMINAL_CB set = {}", cb_set)); if !cb_set { term_err("term: callback not registered — cannot spawn"); @@ -1441,7 +1457,9 @@ fn cmd_term(_p: &Parsed) { let h = 400usize.min(ch); term_println(&alloc::format!("term: requesting window {}x{}", w, h)); unsafe { - let cb = core::ptr::addr_of!(rsnix::wm::SPAWN_TERMINAL_CB).read().unwrap(); + let cb = core::ptr::addr_of!(rsnix::wm::SPAWN_TERMINAL_CB) + .read() + .unwrap(); cb("term dbg", w, h); } term_println("term: callback returned (task should be spawning)"); -- cgit v1.2.3