feat(userspace): terminal server + shell desktop; US keymap w/ shift; libkos allocator multi-page fix; panics print
This commit is contained in:
90
crates/servers/terminal-server/src/lib.rs
Normal file
90
crates/servers/terminal-server/src/lib.rs
Normal 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)
|
||||
}
|
||||
Reference in New Issue
Block a user