lesavka/client/src/input/keyboard.rs
2025-06-19 01:02:10 -05:00

78 lines
2.4 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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