feat(userspace): programs in /bin w/o .elf; bin manifests (needs = display) so shell runs snake; Ctrl+C kills foreground via terminal interrupt notification; ctrl keys; sleep
This commit is contained in:
@@ -12,8 +12,10 @@ mod tests;
|
||||
use libkos::display::{self, CELL_HEIGHT, CELL_WIDTH};
|
||||
use libkos::input::{InputEvent, Key};
|
||||
use libkos::syscall;
|
||||
use types::badge::Badge;
|
||||
use types::bounded::CapSlot;
|
||||
use types::display::{Color, ScreenCoord};
|
||||
use types::terminal::{KEYS_BIT, TIMER_BIT};
|
||||
|
||||
/// Where init put them (its manifest: own endpoint, then `uses`).
|
||||
const EP: CapSlot = CapSlot::const_new(0);
|
||||
@@ -26,11 +28,23 @@ const BG: Color = Color::rgb(16, 16, 24);
|
||||
const FLUSH_DELAY: u64 = 20 * 10_000;
|
||||
|
||||
struct Screen {
|
||||
keys: CapSlot,
|
||||
/// Bound to the serving thread; the flush timer signals it.
|
||||
/// Bound to the serving thread: the display signals it with
|
||||
/// `KEYS_BIT`, the flush timer with `TIMER_BIT`.
|
||||
notify: CapSlot,
|
||||
timer: CapSlot,
|
||||
}
|
||||
|
||||
/// A key as the line editor wants it, if it is one.
|
||||
fn byte(event: InputEvent) -> Option<u8> {
|
||||
match event {
|
||||
InputEvent::KeyDown(Key::Char(c)) => Some(c),
|
||||
InputEvent::KeyDown(Key::Space | Key::Tab) => Some(b' '),
|
||||
InputEvent::KeyDown(Key::Enter) => Some(b'\n'),
|
||||
InputEvent::KeyDown(Key::Backspace) => Some(server::BACKSPACE),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn at(col: usize, row: usize) -> (ScreenCoord, ScreenCoord) {
|
||||
(ScreenCoord::new((col * CELL_WIDTH) as u16), ScreenCoord::new((row * CELL_HEIGHT) as u16))
|
||||
}
|
||||
@@ -57,34 +71,50 @@ impl server::Console for Screen {
|
||||
|
||||
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,
|
||||
_ => {}
|
||||
}
|
||||
if let Some(key) = self.poll_key() {
|
||||
return key;
|
||||
}
|
||||
let _ = syscall::wait(self.keys);
|
||||
let _ = syscall::wait(self.notify);
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_key(&mut self) -> Option<u8> {
|
||||
while let Some(event) = display::poll_input(DISPLAY) {
|
||||
if let Some(key) = byte(event) {
|
||||
return Some(key);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn take_focus(&mut self) {
|
||||
display::subscribe(DISPLAY, self.notify, Badge::new(KEYS_BIT));
|
||||
display::clear(DISPLAY, BG);
|
||||
}
|
||||
|
||||
fn interrupt(&mut self, notification: CapSlot) {
|
||||
let _ = syscall::signal(notification);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run() -> ! {
|
||||
let Some(keys) = display::subscribe_input(DISPLAY) else {
|
||||
let Some(notify) = syscall::create_notification().ok().filter(|n| syscall::bind_notification(*n).is_ok()) else {
|
||||
libkos::println!("terminal: no notification, exiting");
|
||||
syscall::exit();
|
||||
};
|
||||
let timer_perms = types::permission::PermissionSet::empty().with(types::permission::Permission::Write);
|
||||
let Ok(timer) = syscall::mint(notify, Badge::new(TIMER_BIT), timer_perms) else {
|
||||
libkos::println!("terminal: no timer, exiting");
|
||||
syscall::exit();
|
||||
};
|
||||
if !display::subscribe(DISPLAY, notify, Badge::new(KEYS_BIT)) {
|
||||
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);
|
||||
let mut srv = server::TerminalServer::new(Screen { notify, timer }, cols, rows);
|
||||
server_framework::serve(&mut srv, EP)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user