lesavka/client/src/input/keyboard.rs

78 lines
2.4 KiB
Rust
Raw Normal View History

2025-06-08 22:24:14 -05:00
// client/src/input/keyboard.rs
2025-06-08 04:11:58 -05:00
use std::collections::HashSet;
2025-06-17 20:54:31 -05:00
use evdev::{Device, EventType, InputEvent, KeyCode};
2025-06-15 20:19:27 -05:00
use tokio::sync::broadcast::Sender;
2025-06-17 20:54:31 -05:00
use tracing::{debug, error, info, warn};
2025-06-15 20:19:27 -05:00
2025-06-17 08:17:23 -05:00
use navka_common::navka::KeyboardReport;
2025-06-08 04:11:58 -05:00
2025-06-17 20:54:31 -05:00
use super::keymap::{is_modifier, keycode_to_usage};
2025-06-08 04:11:58 -05:00
pub struct KeyboardAggregator {
2025-06-08 22:24:14 -05:00
dev: Device,
2025-06-17 20:54:31 -05:00
tx: Sender<KeyboardReport>,
2025-06-11 00:37:01 -05:00
dev_mode: bool,
2025-06-08 04:11:58 -05:00
pressed_keys: HashSet<KeyCode>,
}
impl KeyboardAggregator {
2025-06-17 08:17:23 -05:00
pub fn new(dev: Device, dev_mode: bool, tx: Sender<KeyboardReport>) -> Self {
2025-06-17 20:54:31 -05:00
let _ = dev.set_nonblocking(true);
Self { dev, tx, dev_mode, pressed_keys: HashSet::new() }
}
2025-06-08 22:24:14 -05:00
pub fn process_events(&mut self) {
2025-06-17 20:54:31 -05:00
// --- first fetch, then log (avoids aliasing borrow) ---
2025-06-17 22:02:33 -05:00
let events: Vec<InputEvent> = match self.dev.fetch_events() {
2025-06-17 08:17:23 -05:00
Ok(it) => it.collect(),
Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => return,
2025-06-17 20:54:31 -05:00
Err(e) => { if self.dev_mode { error!("read error: {e}"); } return }
2025-06-11 00:37:01 -05:00
};
2025-06-17 08:17:23 -05:00
2025-06-11 00:37:01 -05:00
if self.dev_mode && !events.is_empty() {
2025-06-19 01:02:10 -05:00
debug!("{} kbd evts from {}", events.len(), self.dev.name().unwrap_or("?"));
2025-06-11 00:37:01 -05:00
}
2025-06-08 04:11:58 -05:00
2025-06-17 08:17:23 -05:00
for ev in events {
if ev.event_type() != EventType::KEY { continue }
2025-06-08 04:11:58 -05:00
let code = KeyCode::new(ev.code());
2025-06-17 08:17:23 -05:00
match ev.value() {
2025-06-17 20:54:31 -05:00
1 => { self.pressed_keys.insert(code); } // press
0 => { self.pressed_keys.remove(&code); } // release
2025-06-08 04:11:58 -05:00
_ => {}
}
2025-06-17 20:54:31 -05:00
2025-06-08 22:24:14 -05:00
let report = self.build_report();
2025-06-17 20:57:58 -05:00
if self.dev_mode { debug!(?report, "kbd"); }
2025-06-17 20:54:31 -05:00
let _ = self.tx.send(KeyboardReport { data: report.to_vec() });
if self.is_magic() {
warn!("🧙 magic chord exiting 🪄 AVADA KEDAVRA!!! 💥💀");
std::process::exit(0);
}
2025-06-08 04:11:58 -05:00
}
2025-06-17 20:54:31 -05:00
}
2025-06-08 04:11:58 -05:00
2025-06-08 22:24:14 -05:00
fn build_report(&self) -> [u8; 8] {
2025-06-17 08:17:23 -05:00
let mut out = [0u8; 8];
let mut mods = 0u8;
let mut keys = Vec::new();
2025-06-08 22:24:14 -05:00
2025-06-17 20:54:31 -05:00
for &kc in &self.pressed_keys {
if let Some(m) = is_modifier(kc) { mods |= m }
2025-06-17 08:17:23 -05:00
else if let Some(u) = keycode_to_usage(kc) { keys.push(u) }
2025-06-08 04:11:58 -05:00
}
2025-06-17 20:54:31 -05:00
2025-06-17 08:17:23 -05:00
out[0] = mods;
for (i, k) in keys.into_iter().take(6).enumerate() { out[2+i] = k }
out
2025-06-08 04:11:58 -05:00
}
2025-06-17 08:17:23 -05:00
#[inline]
2025-06-17 20:54:31 -05:00
fn is_magic(&self) -> bool {
self.pressed_keys.contains(&KeyCode::KEY_LEFTCTRL)
&& self.pressed_keys.contains(&KeyCode::KEY_ESC)
2025-06-08 04:11:58 -05:00
}
}