diff options
| author | salmonik <salmonik@tuta.io> | 2026-08-20 13:47:10 +0200 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-08-20 13:47:10 +0200 |
| commit | cb17c57452ccd2ccca77e99098402d4b9f61c0a5 (patch) | |
| tree | 6566e0ddaa764c6675e9a56f03772de345170992 /rsnix/src/tty.rs | |
| parent | wm: integrate home terminal as window 0 + fix console focus after close (diff) | |
| download | rs-dos-cb17c57452ccd2ccca77e99098402d4b9f61c0a5.tar.gz rs-dos-cb17c57452ccd2ccca77e99098402d4b9f61c0a5.zip | |
wm: F1 spawns a windowed shell — real shell, not a duplicate
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.
Diffstat (limited to 'rsnix/src/tty.rs')
| -rw-r--r-- | rsnix/src/tty.rs | 62 |
1 files changed, 62 insertions, 0 deletions
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 { | |||
| 135 | } | 135 | } |
| 136 | } | 136 | } |
| 137 | 137 | ||
| 138 | /// Read one line in canonical mode from the task's message queue (for | ||
| 139 | /// windowed shells). Same semantics as `read_line` but keys arrive as | ||
| 140 | /// `TaskMsg::Key` instead of from the global PS/2 queue. Returns `None` | ||
| 141 | /// on `TaskMsg::Close` (window was closed). | ||
| 142 | pub fn read_line_from_queue() -> Option<LineInput> { | ||
| 143 | crate::vt::sync_scroll(); | ||
| 144 | let mut buf = strbuf::String::<LINE_BUF_SIZE>::new(); | ||
| 145 | loop { | ||
| 146 | match crate::sched::recv_blocking() { | ||
| 147 | crate::sched::TaskMsg::Key(ev) => match ev { | ||
| 148 | KeyEvent::Enter => { | ||
| 149 | gop::put_char('\n'); | ||
| 150 | serial::write_str("\r\n"); | ||
| 151 | return Some(LineInput::Line(buf)); | ||
| 152 | } | ||
| 153 | KeyEvent::Ctrl('c') => { | ||
| 154 | buf.clear(); | ||
| 155 | gop::put_char('^'); | ||
| 156 | gop::put_char('C'); | ||
| 157 | gop::put_char('\n'); | ||
| 158 | serial::write_str("^C\r\n"); | ||
| 159 | return Some(LineInput::Interrupted); | ||
| 160 | } | ||
| 161 | KeyEvent::Ctrl('d') => { | ||
| 162 | if buf.is_empty() { | ||
| 163 | gop::put_char('^'); | ||
| 164 | gop::put_char('D'); | ||
| 165 | gop::put_char('\n'); | ||
| 166 | serial::write_str("^D\r\n"); | ||
| 167 | return Some(LineInput::Eof); | ||
| 168 | } | ||
| 169 | } | ||
| 170 | KeyEvent::Char(c) if c.is_ascii_graphic() || c == ' ' => { | ||
| 171 | if buf.push(c).is_ok() { | ||
| 172 | gop::put_char(c); | ||
| 173 | let mut s = [0u8; 4]; | ||
| 174 | let s = c.encode_utf8(&mut s); | ||
| 175 | serial::write_str(s); | ||
| 176 | } | ||
| 177 | } | ||
| 178 | KeyEvent::Backspace => { | ||
| 179 | if buf.pop().is_some() { | ||
| 180 | gop::put_char('\x08'); | ||
| 181 | serial::write_str("\x08 \x08"); | ||
| 182 | } | ||
| 183 | } | ||
| 184 | KeyEvent::Tab => { | ||
| 185 | for _ in 0..4 { | ||
| 186 | if buf.push(' ').is_ok() { | ||
| 187 | gop::put_char(' '); | ||
| 188 | serial::write_str(" "); | ||
| 189 | } | ||
| 190 | } | ||
| 191 | } | ||
| 192 | _ => {} | ||
| 193 | }, | ||
| 194 | crate::sched::TaskMsg::Close => return None, | ||
| 195 | _ => {} | ||
| 196 | } | ||
| 197 | } | ||
| 198 | } | ||
| 199 | |||
| 138 | /// Non-blocking drain of the keyboard: true if a ^C is pending. Used by | 200 | /// Non-blocking drain of the keyboard: true if a ^C is pending. Used by |
| 139 | /// streaming commands (cat/hexdump) so a long dump can be interrupted. | 201 | /// streaming commands (cat/hexdump) so a long dump can be interrupted. |
| 140 | pub fn interrupt_pressed() -> bool { | 202 | pub fn interrupt_pressed() -> bool { |
