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,13 +12,17 @@ use libkos::syscall;
|
||||
use server_framework::Encode;
|
||||
use display_server::protocol::DisplayRequest;
|
||||
|
||||
/// Input comes through the display server too, while this app has focus.
|
||||
const DISPLAY_EP: CapSlot = CapSlot::const_new(0);
|
||||
const TICK_DELAY: u64 = 5_000_000;
|
||||
const MAX_RENDER_CMDS: usize = 140;
|
||||
|
||||
/// The display server, which the shell hands over because snake's manifest
|
||||
/// asks for it. Input comes through it too, while snake has focus.
|
||||
fn display_ep() -> CapSlot {
|
||||
libkos::start::display().unwrap_or(CapSlot::const_new(0))
|
||||
}
|
||||
|
||||
fn display_send(req: &DisplayRequest) {
|
||||
let _ = syscall::request(DISPLAY_EP, req.encode());
|
||||
let _ = syscall::request(display_ep(), req.encode());
|
||||
}
|
||||
|
||||
fn draw_rect(x: u16, y: u16, w: u16, h: u16, color: u32) {
|
||||
@@ -37,8 +41,12 @@ fn flush() {
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
extern "C" fn main() {
|
||||
if libkos::start::display().is_none() {
|
||||
libkos::println!("snake: needs the display (see /bin/snake.manifest)");
|
||||
return;
|
||||
}
|
||||
// Takes focus; the game polls every tick, so it never waits on the signal.
|
||||
let _ = libkos::display::subscribe_input(DISPLAY_EP);
|
||||
let _ = libkos::display::subscribe_input(display_ep());
|
||||
let mut snake = Snake::new();
|
||||
let mut commands = [RenderCommand { x: 0, y: 0, w: 0, h: 0, color: 0 }; MAX_RENDER_CMDS];
|
||||
|
||||
@@ -55,31 +63,59 @@ extern "C" fn main() {
|
||||
let gh = renderer::grid_pixel_height();
|
||||
draw_rect(gw / 2 - 60, gh / 2 - 12, 120, 24, 0xFFCC0000);
|
||||
flush();
|
||||
loop { syscall::yield_now(); }
|
||||
// Any key leaves.
|
||||
while next_input() == Input::None {
|
||||
wait_tick();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
wait_tick();
|
||||
handle_input(&mut snake);
|
||||
if handle_input(&mut snake) == Input::Quit {
|
||||
return;
|
||||
}
|
||||
snake.tick();
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_input(snake: &mut Snake) {
|
||||
// Drain all pending events, apply the latest direction
|
||||
#[derive(PartialEq)]
|
||||
enum Input {
|
||||
None,
|
||||
Quit,
|
||||
Turn(Direction),
|
||||
Other,
|
||||
}
|
||||
|
||||
/// The next key, if one is waiting: q or Escape quits.
|
||||
fn next_input() -> Input {
|
||||
let Ok([tag, kind, ch, _]) = syscall::request(display_ep(), [types::display::input::POLL, 0, 0, 0]) else {
|
||||
return Input::None;
|
||||
};
|
||||
if tag == 0 {
|
||||
return Input::None; // NoEvent: queue drained
|
||||
}
|
||||
if tag != 1 {
|
||||
return Input::Other; // a key let go
|
||||
}
|
||||
// Arrows, or WASD (kind 9 is a character).
|
||||
match (kind, ch as u8) {
|
||||
(5, _) | (9, b'q') => Input::Quit,
|
||||
(0, _) | (9, b'w') => Input::Turn(Direction::Up),
|
||||
(1, _) | (9, b's') => Input::Turn(Direction::Down),
|
||||
(2, _) | (9, b'a') => Input::Turn(Direction::Left),
|
||||
(3, _) | (9, b'd') => Input::Turn(Direction::Right),
|
||||
_ => Input::Other,
|
||||
}
|
||||
}
|
||||
|
||||
/// Drains the pending keys, applying each turn; reports a quit.
|
||||
fn handle_input(snake: &mut Snake) -> Input {
|
||||
loop {
|
||||
let Ok([tag, kind, ch, _]) = syscall::request(DISPLAY_EP, [types::display::input::POLL, 0, 0, 0]) else {
|
||||
break;
|
||||
};
|
||||
if tag == 0 { break; } // NoEvent — queue drained
|
||||
if tag == 1 {
|
||||
// Arrows, or WASD (kind 9 is a character).
|
||||
match (kind, ch as u8) {
|
||||
(0, _) | (9, b'w') => snake.set_direction(Direction::Up),
|
||||
(1, _) | (9, b's') => snake.set_direction(Direction::Down),
|
||||
(2, _) | (9, b'a') => snake.set_direction(Direction::Left),
|
||||
(3, _) | (9, b'd') => snake.set_direction(Direction::Right),
|
||||
_ => {}
|
||||
}
|
||||
match next_input() {
|
||||
Input::None => return Input::None,
|
||||
Input::Quit => return Input::Quit,
|
||||
Input::Turn(d) => snake.set_direction(d),
|
||||
Input::Other => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user