2025-06-08 22:24:14 -05:00
|
|
|
// client/src/input/mouse.rs
|
|
|
|
|
|
2025-06-12 01:48:48 -05:00
|
|
|
use evdev::{Device, InputEvent, EventType, KeyCode, RelativeAxisCode};
|
2025-06-15 20:19:27 -05:00
|
|
|
use tokio::sync::broadcast::Sender;
|
2025-06-12 01:48:48 -05:00
|
|
|
use tracing::{error, debug};
|
|
|
|
|
use navka_common::navka::HidReport;
|
2025-06-08 22:24:14 -05:00
|
|
|
|
|
|
|
|
/// Aggregator for a single mouse device
|
|
|
|
|
pub struct MouseAggregator {
|
|
|
|
|
dev: Device,
|
2025-06-11 22:01:16 -05:00
|
|
|
tx: Sender<HidReport>,
|
|
|
|
|
buttons: u8,
|
|
|
|
|
dx: i8,
|
|
|
|
|
dy: i8,
|
|
|
|
|
wheel: i8,
|
2025-06-08 22:24:14 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl MouseAggregator {
|
2025-06-12 01:48:48 -05:00
|
|
|
pub fn new(dev: Device, tx: Sender<HidReport>) -> Self {
|
2025-06-08 22:24:14 -05:00
|
|
|
Self {
|
|
|
|
|
dev,
|
2025-06-12 01:48:48 -05:00
|
|
|
tx,
|
|
|
|
|
buttons: 0,
|
2025-06-08 22:24:14 -05:00
|
|
|
dx: 0,
|
|
|
|
|
dy: 0,
|
2025-06-12 01:48:48 -05:00
|
|
|
wheel: 0,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// helper to set or clear a mouse button bit
|
|
|
|
|
fn set_btn(&mut self, idx: usize, pressed: bool) {
|
|
|
|
|
if pressed {
|
|
|
|
|
self.buttons |= 1 << idx;
|
|
|
|
|
} else {
|
|
|
|
|
self.buttons &= !(1 << idx);
|
2025-06-08 22:24:14 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn process_events(&mut self) {
|
2025-06-11 00:37:01 -05:00
|
|
|
let events_vec: Vec<InputEvent> = match self.dev.fetch_events() {
|
|
|
|
|
Ok(it) => it.collect(),
|
|
|
|
|
Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {
|
|
|
|
|
return;
|
2025-06-08 22:24:14 -05:00
|
|
|
}
|
|
|
|
|
Err(e) => {
|
2025-06-11 00:37:01 -05:00
|
|
|
error!("Mouse device read error: {e}");
|
|
|
|
|
return;
|
2025-06-08 22:24:14 -05:00
|
|
|
}
|
2025-06-11 00:37:01 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for ev in events_vec {
|
|
|
|
|
self.handle_event(ev);
|
2025-06-08 22:24:14 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn handle_event(&mut self, ev: InputEvent) {
|
2025-06-11 22:01:16 -05:00
|
|
|
match ev.event_type() {
|
2025-06-15 20:19:27 -05:00
|
|
|
EventType::RELATIVE => {
|
|
|
|
|
match RelativeAxisCode::new(ev.code()) {
|
|
|
|
|
RelativeAxisCode::REL_X => self.dx = ev.value() as i8,
|
|
|
|
|
RelativeAxisCode::REL_Y => self.dy = ev.value() as i8,
|
|
|
|
|
RelativeAxisCode::REL_WHEEL => self.wheel = ev.value() as i8,
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
EventType::KEY => {
|
2025-06-11 22:01:16 -05:00
|
|
|
let pressed = ev.value() != 0;
|
|
|
|
|
match ev.code() {
|
2025-06-15 20:19:27 -05:00
|
|
|
c if c == KeyCode::BTN_LEFT.0 => self.set_btn(0, pressed),
|
|
|
|
|
c if c == KeyCode::BTN_RIGHT.0 => self.set_btn(1, pressed),
|
|
|
|
|
c if c == KeyCode::BTN_MIDDLE.0 => self.set_btn(2, pressed),
|
2025-06-11 22:01:16 -05:00
|
|
|
_ => {}
|
2025-06-08 22:24:14 -05:00
|
|
|
}
|
|
|
|
|
}
|
2025-06-11 22:01:16 -05:00
|
|
|
_ => {}
|
2025-06-08 22:24:14 -05:00
|
|
|
}
|
2025-06-11 22:01:16 -05:00
|
|
|
|
|
|
|
|
// whenever we changed something, emit:
|
2025-06-15 21:39:07 -05:00
|
|
|
let report = [self.buttons, self.dx as u8, self.dy as u8, self.wheel as u8];
|
|
|
|
|
self.send_report(report);
|
2025-06-15 20:19:27 -05:00
|
|
|
|
2025-06-11 22:01:16 -05:00
|
|
|
// reset deltas so we send *relative* movement
|
2025-06-15 20:19:27 -05:00
|
|
|
self.dx = 0;
|
|
|
|
|
self.dy = 0;
|
|
|
|
|
self.wheel = 0;
|
2025-06-08 22:24:14 -05:00
|
|
|
}
|
2025-06-11 22:01:16 -05:00
|
|
|
|
2025-06-15 21:39:07 -05:00
|
|
|
fn send_report(&self, report: [u8; 4]) {
|
|
|
|
|
let msg = HidReport {
|
|
|
|
|
kind: Some(hid_report::Kind::MouseReport(report.to_vec())),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
match self.tx.try_send(msg.clone()) {
|
|
|
|
|
Ok(n) => {
|
|
|
|
|
tracing::trace!("queued → {} receiver(s)", n);
|
|
|
|
|
}
|
|
|
|
|
Err(e) => {
|
|
|
|
|
tracing::warn!("try_send dropped report ({e}); falling back to send()");
|
|
|
|
|
let _ = self.tx.send(msg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-06-08 22:24:14 -05:00
|
|
|
}
|