From cb17c57452ccd2ccca77e99098402d4b9f61c0a5 Mon Sep 17 00:00:00 2001 From: salmonik Date: Thu, 20 Aug 2026 13:47:10 +0200 Subject: wm: F1 spawns a windowed shell — real shell, not a duplicate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Architecture: - vt: ACTIVE terminal redirect — when set, all gop_print!/put_char/write_str go there instead of HOME. Terminal::from_buffer() renders into a WM-owned pixel buffer. - tty: read_line_from_queue() — canonical-mode line input from the task's own message queue (TaskMsg::Key). Returns None on Close. - shell: run_windowed() — same shell as the console but reads from the message queue. Returns on ^D or window close. - wm: F1 calls SPAWN_TERMINAL_CB (set by rsdos). No shell logic in the WM. - rsdos: terminal_task callback + terminal_entry task — creates a 640x400 chrome window, wires up Terminal::from_buffer, sets ACTIVE, runs shell::run_windowed(), cleans up on exit. - shell: 'term' debug command that invokes the callback directly and logs each step to serial. --- rsnix/src/tty.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'rsnix/src/tty.rs') diff --git a/rsnix/src/tty.rs b/rsnix/src/tty.rs index 6102fb5..918f6e0 100644 --- a/rsnix/src/tty.rs +++ b/rsnix/src/tty.rs @@ -135,6 +135,68 @@ pub fn read_line() -> LineInput { } } +/// Read one line in canonical mode from the task's message queue (for +/// windowed shells). Same semantics as `read_line` but keys arrive as +/// `TaskMsg::Key` instead of from the global PS/2 queue. Returns `None` +/// on `TaskMsg::Close` (window was closed). +pub fn read_line_from_queue() -> Option { + crate::vt::sync_scroll(); + let mut buf = strbuf::String::::new(); + loop { + match crate::sched::recv_blocking() { + crate::sched::TaskMsg::Key(ev) => match ev { + KeyEvent::Enter => { + gop::put_char('\n'); + serial::write_str("\r\n"); + return Some(LineInput::Line(buf)); + } + KeyEvent::Ctrl('c') => { + buf.clear(); + gop::put_char('^'); + gop::put_char('C'); + gop::put_char('\n'); + serial::write_str("^C\r\n"); + return Some(LineInput::Interrupted); + } + KeyEvent::Ctrl('d') => { + if buf.is_empty() { + gop::put_char('^'); + gop::put_char('D'); + gop::put_char('\n'); + serial::write_str("^D\r\n"); + return Some(LineInput::Eof); + } + } + KeyEvent::Char(c) if c.is_ascii_graphic() || c == ' ' => { + if buf.push(c).is_ok() { + gop::put_char(c); + let mut s = [0u8; 4]; + let s = c.encode_utf8(&mut s); + serial::write_str(s); + } + } + KeyEvent::Backspace => { + if buf.pop().is_some() { + gop::put_char('\x08'); + serial::write_str("\x08 \x08"); + } + } + KeyEvent::Tab => { + for _ in 0..4 { + if buf.push(' ').is_ok() { + gop::put_char(' '); + serial::write_str(" "); + } + } + } + _ => {} + }, + crate::sched::TaskMsg::Close => return None, + _ => {} + } + } +} + /// Non-blocking drain of the keyboard: true if a ^C is pending. Used by /// streaming commands (cat/hexdump) so a long dump can be interrupted. pub fn interrupt_pressed() -> bool { -- cgit v1.2.3