feat(pointer): virtio tablet as 2nd input dev (driver per-instance VAs, abs/btn decode), input server serves 2 devices on one notif; display software cursor, bar click switches window, presses/releases to front window in its px; k-ui hit-tests (press focuses, release on same presses, field only focuses)
This commit is contained in:
@@ -34,9 +34,9 @@ impl Decode for InputRequest {
|
||||
|
||||
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_PTR_DOWN: usize = types::input::event::POINTER_DOWN;
|
||||
const EV_PTR_MOVE: usize = types::input::event::POINTER_MOVE;
|
||||
const EV_PTR_UP: usize = types::input::event::POINTER_UP;
|
||||
const EV_SCROLL: usize = 6;
|
||||
const EV_GAMEPAD_BTN: usize = 7;
|
||||
const EV_GAMEPAD_AXIS: usize = 8;
|
||||
|
||||
@@ -4,13 +4,39 @@ use port_input_device::{InputDevice, InputEvent};
|
||||
use types::bounded::CapSlot;
|
||||
use crate::protocol::{InputRequest, InputResponse};
|
||||
|
||||
/// Events captured on interrupts and not yet asked for.
|
||||
const BUFFERED: usize = 32;
|
||||
/// Events captured on interrupts and not yet asked for (a tablet sends
|
||||
/// many).
|
||||
pub const BUFFERED: usize = 64;
|
||||
/// Devices served at once (a keyboard and a tablet).
|
||||
pub const MAX_DEVICES: usize = 2;
|
||||
|
||||
/// Two devices as one: events from either, the first's first.
|
||||
pub struct Pair<A, B> {
|
||||
pub first: A,
|
||||
pub second: Option<B>,
|
||||
}
|
||||
|
||||
impl<A: InputDevice, B: InputDevice> InputDevice for Pair<A, B> {
|
||||
fn poll(&mut self) -> Option<InputEvent> {
|
||||
self.first.poll().or_else(|| self.second.as_mut()?.poll())
|
||||
}
|
||||
|
||||
fn has_event(&self) -> bool {
|
||||
self.first.has_event() || self.second.as_ref().is_some_and(|d| d.has_event())
|
||||
}
|
||||
|
||||
fn acknowledge(&mut self) {
|
||||
self.first.acknowledge();
|
||||
if let Some(d) = self.second.as_mut() {
|
||||
d.acknowledge();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct InputServer<D: InputDevice> {
|
||||
device: D,
|
||||
/// The IRQ to re-arm after each interrupt, if the device has one.
|
||||
irq: Option<CapSlot>,
|
||||
/// The IRQs to re-arm after each interrupt, those the devices have.
|
||||
irqs: [Option<CapSlot>; MAX_DEVICES],
|
||||
events: [Option<InputEvent>; BUFFERED],
|
||||
head: usize,
|
||||
len: usize,
|
||||
@@ -21,14 +47,14 @@ pub struct InputServer<D: InputDevice> {
|
||||
impl<D: InputDevice> InputServer<D> {
|
||||
/// A server that reads the device only when a client asks.
|
||||
pub fn new(device: D) -> Self {
|
||||
Self { device, irq: None, events: [None; BUFFERED], head: 0, len: 0, subscriber: None }
|
||||
Self { device, irqs: [None; MAX_DEVICES], events: [None; BUFFERED], head: 0, len: 0, subscriber: None }
|
||||
}
|
||||
|
||||
/// A server woken by `irq` (routed and bound by the caller): it drains
|
||||
/// the device into a buffer on every interrupt, so events that arrive
|
||||
/// between requests are kept.
|
||||
pub fn with_irq(device: D, irq: CapSlot) -> Self {
|
||||
Self { irq: Some(irq), ..Self::new(device) }
|
||||
/// A server woken by `irqs` (routed and bound by the caller): it
|
||||
/// drains the devices into a buffer on every interrupt, so events that
|
||||
/// arrive between requests are kept.
|
||||
pub fn with_irqs(device: D, irqs: [Option<CapSlot>; MAX_DEVICES]) -> Self {
|
||||
Self { irqs, ..Self::new(device) }
|
||||
}
|
||||
|
||||
fn push(&mut self, event: InputEvent) {
|
||||
@@ -109,7 +135,7 @@ impl<D: InputDevice> Server for InputServer<D> {
|
||||
let _ = libkos::syscall::signal(subscriber);
|
||||
}
|
||||
self.device.acknowledge();
|
||||
if let Some(irq) = self.irq {
|
||||
for irq in self.irqs.into_iter().flatten() {
|
||||
let _ = libkos::syscall::ack_interrupt(irq);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ fn an_interrupt_buffers_events_until_asked() {
|
||||
let mut device = MockInputDevice::new();
|
||||
device.push_event(InputEvent::KeyDown(Key::Up));
|
||||
device.push_event(InputEvent::KeyDown(Key::Down));
|
||||
let mut server = InputServer::with_irq(device, types::bounded::CapSlot::new(1).unwrap());
|
||||
let mut server = InputServer::with_irqs(device, [types::bounded::CapSlot::new(1), None]);
|
||||
server.signal(1);
|
||||
// The device itself is now drained; the events wait in the server.
|
||||
assert!(!port_input_device::InputDevice::has_event(server.device()));
|
||||
@@ -72,9 +72,10 @@ fn an_interrupt_buffers_events_until_asked() {
|
||||
|
||||
#[test]
|
||||
fn a_full_buffer_drops_the_oldest_event() {
|
||||
let mut server = InputServer::with_irq(MockInputDevice::new(), types::bounded::CapSlot::new(1).unwrap());
|
||||
// 40 interrupts, one key each; the buffer keeps the last 32.
|
||||
for i in 0..40u8 {
|
||||
let mut server = InputServer::with_irqs(MockInputDevice::new(), [types::bounded::CapSlot::new(1), None]);
|
||||
// More interrupts than the buffer holds, one key each: it keeps the last.
|
||||
let extra = 8;
|
||||
for i in 0..(crate::server::BUFFERED + extra) as u8 {
|
||||
let mut device = MockInputDevice::new();
|
||||
device.push_event(InputEvent::KeyDown(Key::Char(i)));
|
||||
server.replace_device_for_test(device);
|
||||
@@ -82,7 +83,7 @@ fn a_full_buffer_drops_the_oldest_event() {
|
||||
}
|
||||
assert_eq!(
|
||||
server.handle(InputRequest::PollEvent),
|
||||
InputResponse::Event(InputEvent::KeyDown(Key::Char(8)))
|
||||
InputResponse::Event(InputEvent::KeyDown(Key::Char(extra as u8)))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user