summaryrefslogtreecommitdiffstats
path: root/rsnix/src/tty.rs
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-08-20 13:47:10 +0200
committersalmonik <salmonik@tuta.io>2026-08-20 13:47:10 +0200
commitcb17c57452ccd2ccca77e99098402d4b9f61c0a5 (patch)
tree6566e0ddaa764c6675e9a56f03772de345170992 /rsnix/src/tty.rs
parentwm: integrate home terminal as window 0 + fix console focus after close (diff)
downloadrs-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 '')
-rw-r--r--rsnix/src/tty.rs62
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).
142pub 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.
140pub fn interrupt_pressed() -> bool { 202pub fn interrupt_pressed() -> bool {