Files
k-os/crates/servers/input-server/src/protocol.rs
Gabriel Kaszewski 5766c6f7f7 refactor: extract ports/drivers/bins layers — clean dependency inversion
Separate abstractions from implementations following DIP:

  servers/              drivers/
      │                     │
      ▼                     ▼
    ports/  (trait-only crates, zero deps)

New crates:

ports/ (abstractions):
  - port-framebuffer: Framebuffer trait
  - port-block-device: BlockDevice trait + SectorId
  - port-input-device: InputDevice trait + InputEvent types

drivers/ (implementations depend on ports/):
  - driver-framebuffer-virtio: VirtIO GPU framebuffer
  - driver-framebuffer-mock: test double
  - driver-block-virtio: VirtIO block device

bins/ (composition roots wire server + driver):
  - display-qemu: DisplayServer<VirtioFramebuffer>
  - storage-qemu: storage server with VirtIO block

Servers no longer own their hardware traits or driver code.
Neither server nor driver depends on the other — both point
inward to the port abstraction.
2026-10-18 13:13:53 +02:00

220 lines
6.6 KiB
Rust

use server_framework::{Decode, Encode};
pub use port_input_device::{Key, GamepadButton, Axis, InputEvent};
#[derive(Debug, PartialEq)]
pub enum InputRequest {
PollEvent,
WaitEvent,
}
#[derive(Debug, PartialEq)]
pub enum InputResponse {
Event(InputEvent),
NoEvent,
}
impl Encode for InputRequest {
fn encode(&self) -> [usize; 4] {
match self {
InputRequest::PollEvent => [0, 0, 0, 0],
InputRequest::WaitEvent => [1, 0, 0, 0],
}
}
}
impl Decode for InputRequest {
fn decode(words: [usize; 4]) -> Option<Self> {
match words[0] {
0 => Some(InputRequest::PollEvent),
1 => Some(InputRequest::WaitEvent),
_ => None,
}
}
}
const EV_KEY_DOWN: usize = 1;
const EV_KEY_UP: usize = 2;
const EV_PTR_DOWN: usize = 3;
const EV_PTR_MOVE: usize = 4;
const EV_PTR_UP: usize = 5;
const EV_SCROLL: usize = 6;
const EV_GAMEPAD_BTN: usize = 7;
const EV_GAMEPAD_AXIS: usize = 8;
fn encode_key(key: Key) -> (usize, usize) {
match key {
Key::Up => (0, 0),
Key::Down => (1, 0),
Key::Left => (2, 0),
Key::Right => (3, 0),
Key::Enter => (4, 0),
Key::Escape => (5, 0),
Key::Space => (6, 0),
Key::Backspace => (7, 0),
Key::Tab => (8, 0),
Key::Char(c) => (9, c as usize),
}
}
fn decode_key(kind: usize, data: usize) -> Option<Key> {
match kind {
0 => Some(Key::Up),
1 => Some(Key::Down),
2 => Some(Key::Left),
3 => Some(Key::Right),
4 => Some(Key::Enter),
5 => Some(Key::Escape),
6 => Some(Key::Space),
7 => Some(Key::Backspace),
8 => Some(Key::Tab),
9 => Some(Key::Char(data as u8)),
_ => None,
}
}
fn encode_pointer(id: u8, x: u16, y: u16) -> (usize, usize) {
(id as usize, (x as usize) | ((y as usize) << 16))
}
fn decode_pointer(w1: usize, w2: usize) -> (u8, u16, u16) {
(w1 as u8, (w2 & 0xFFFF) as u16, ((w2 >> 16) & 0xFFFF) as u16)
}
fn encode_gamepad_button(button: GamepadButton) -> usize {
match button {
GamepadButton::South => 0,
GamepadButton::East => 1,
GamepadButton::North => 2,
GamepadButton::West => 3,
GamepadButton::DpadUp => 4,
GamepadButton::DpadDown => 5,
GamepadButton::DpadLeft => 6,
GamepadButton::DpadRight => 7,
GamepadButton::Start => 8,
GamepadButton::Select => 9,
}
}
fn decode_gamepad_button(v: usize) -> Option<GamepadButton> {
match v {
0 => Some(GamepadButton::South),
1 => Some(GamepadButton::East),
2 => Some(GamepadButton::North),
3 => Some(GamepadButton::West),
4 => Some(GamepadButton::DpadUp),
5 => Some(GamepadButton::DpadDown),
6 => Some(GamepadButton::DpadLeft),
7 => Some(GamepadButton::DpadRight),
8 => Some(GamepadButton::Start),
9 => Some(GamepadButton::Select),
_ => None,
}
}
fn encode_axis(axis: Axis) -> usize {
match axis {
Axis::LeftX => 0,
Axis::LeftY => 1,
Axis::RightX => 2,
Axis::RightY => 3,
}
}
fn decode_axis(v: usize) -> Option<Axis> {
match v {
0 => Some(Axis::LeftX),
1 => Some(Axis::LeftY),
2 => Some(Axis::RightX),
3 => Some(Axis::RightY),
_ => None,
}
}
impl Encode for InputResponse {
fn encode(&self) -> [usize; 4] {
match self {
InputResponse::NoEvent => [0, 0, 0, 0],
InputResponse::Event(event) => match event {
InputEvent::KeyDown(key) => {
let (k, d) = encode_key(*key);
[EV_KEY_DOWN, k, d, 0]
}
InputEvent::KeyUp(key) => {
let (k, d) = encode_key(*key);
[EV_KEY_UP, k, d, 0]
}
InputEvent::PointerDown { id, x, y } => {
let (w1, w2) = encode_pointer(*id, *x, *y);
[EV_PTR_DOWN, w1, w2, 0]
}
InputEvent::PointerMove { id, x, y } => {
let (w1, w2) = encode_pointer(*id, *x, *y);
[EV_PTR_MOVE, w1, w2, 0]
}
InputEvent::PointerUp { id, x, y } => {
let (w1, w2) = encode_pointer(*id, *x, *y);
[EV_PTR_UP, w1, w2, 0]
}
InputEvent::Scroll { dx, dy } => {
[EV_SCROLL, *dx as usize, *dy as usize, 0]
}
InputEvent::GamepadButton { button, pressed } => {
[EV_GAMEPAD_BTN, encode_gamepad_button(*button), *pressed as usize, 0]
}
InputEvent::GamepadAxis { axis, value } => {
[EV_GAMEPAD_AXIS, encode_axis(*axis), *value as usize, 0]
}
},
}
}
}
impl Decode for InputResponse {
fn decode(words: [usize; 4]) -> Option<Self> {
match words[0] {
0 => Some(InputResponse::NoEvent),
EV_KEY_DOWN => {
let key = decode_key(words[1], words[2])?;
Some(InputResponse::Event(InputEvent::KeyDown(key)))
}
EV_KEY_UP => {
let key = decode_key(words[1], words[2])?;
Some(InputResponse::Event(InputEvent::KeyUp(key)))
}
EV_PTR_DOWN => {
let (id, x, y) = decode_pointer(words[1], words[2]);
Some(InputResponse::Event(InputEvent::PointerDown { id, x, y }))
}
EV_PTR_MOVE => {
let (id, x, y) = decode_pointer(words[1], words[2]);
Some(InputResponse::Event(InputEvent::PointerMove { id, x, y }))
}
EV_PTR_UP => {
let (id, x, y) = decode_pointer(words[1], words[2]);
Some(InputResponse::Event(InputEvent::PointerUp { id, x, y }))
}
EV_SCROLL => {
Some(InputResponse::Event(InputEvent::Scroll {
dx: words[1] as i16,
dy: words[2] as i16,
}))
}
EV_GAMEPAD_BTN => {
let button = decode_gamepad_button(words[1])?;
Some(InputResponse::Event(InputEvent::GamepadButton {
button,
pressed: words[2] != 0,
}))
}
EV_GAMEPAD_AXIS => {
let axis = decode_axis(words[1])?;
Some(InputResponse::Event(InputEvent::GamepadAxis {
axis,
value: words[2] as i16,
}))
}
_ => None,
}
}
}