feat(userspace): terminal server + shell desktop; US keymap w/ shift; libkos allocator multi-page fix; panics print

This commit is contained in:
2026-10-27 16:50:35 +01:00
parent 2845d190f0
commit b80303f553
26 changed files with 739 additions and 53 deletions

View File

@@ -0,0 +1,90 @@
#![no_std]
extern crate alloc;
pub mod grid;
pub mod server;
#[cfg(test)]
#[path = "tests/mod.rs"]
mod tests;
use libkos::display::{self, CELL_HEIGHT, CELL_WIDTH};
use libkos::input::{InputEvent, Key};
use libkos::syscall;
use types::bounded::CapSlot;
use types::display::{Color, ScreenCoord};
/// Where init put them (its manifest: own endpoint, then `uses`).
const EP: CapSlot = CapSlot::const_new(0);
const DISPLAY: CapSlot = CapSlot::const_new(1);
const FG: Color = Color::rgb(220, 220, 220);
const BG: Color = Color::rgb(16, 16, 24);
/// Output is shown at most this long after it is written. The timebase is
/// QEMU virt's 10 MHz.
const FLUSH_DELAY: u64 = 20 * 10_000;
struct Screen {
keys: CapSlot,
/// Bound to the serving thread; the flush timer signals it.
timer: CapSlot,
}
fn at(col: usize, row: usize) -> (ScreenCoord, ScreenCoord) {
(ScreenCoord::new((col * CELL_WIDTH) as u16), ScreenCoord::new((row * CELL_HEIGHT) as u16))
}
impl server::Console for Screen {
fn draw_row(&mut self, row: usize, text: &[u8]) {
let (x, y) = at(0, row);
display::draw_text(DISPLAY, x, y, FG, BG, text);
}
fn draw_cursor(&mut self, col: usize, row: usize, under: u8) {
let (x, y) = at(col, row);
display::draw_text(DISPLAY, x, y, BG, FG, &[under]);
}
fn flush(&mut self) {
display::flush(DISPLAY);
}
fn flush_later(&mut self) {
let at = syscall::get_time().raw() + FLUSH_DELAY;
let _ = syscall::set_timer(self.timer, types::time::Ticks::from_raw(at));
}
fn next_key(&mut self) -> u8 {
loop {
while let Some(event) = display::poll_input(DISPLAY) {
let InputEvent::KeyDown(key) = event else { continue };
match key {
Key::Char(c) => return c,
Key::Space | Key::Tab => return b' ',
Key::Enter => return b'\n',
Key::Backspace => return server::BACKSPACE,
_ => {}
}
}
let _ = syscall::wait(self.keys);
}
}
}
pub fn run() -> ! {
let Some(keys) = display::subscribe_input(DISPLAY) else {
libkos::println!("terminal: no input focus, exiting");
syscall::exit();
};
let Some(timer) = syscall::create_notification().ok().filter(|t| syscall::bind_notification(*t).is_ok()) else {
libkos::println!("terminal: no timer notification, exiting");
syscall::exit();
};
let (w, h) = display::get_dimensions(DISPLAY);
display::clear(DISPLAY, BG);
let cols = w.raw() as usize / CELL_WIDTH;
let rows = h.raw() as usize / CELL_HEIGHT;
let mut srv = server::TerminalServer::new(Screen { keys, timer }, cols, rows);
server_framework::serve(&mut srv, EP)
}