2026-10-19 08:09:48 +00:00
|
|
|
use std::sync::{
|
|
|
|
|
Arc,
|
|
|
|
|
atomic::{AtomicU8, Ordering},
|
|
|
|
|
};
|
|
|
|
|
use std::thread::{self, JoinHandle};
|
|
|
|
|
|
|
|
|
|
/// 使用 rdev 监听系统级键盘事件。
|
|
|
|
|
/// bit0 = Up, bit1 = Left, bit2 = Right
|
|
|
|
|
pub fn spawn_listener() -> (JoinHandle<()>, Arc<AtomicU8>) {
|
|
|
|
|
let state = Arc::new(AtomicU8::new(0));
|
|
|
|
|
let state_cloned = Arc::clone(&state);
|
|
|
|
|
|
|
|
|
|
let handle = thread::spawn(move || {
|
|
|
|
|
if let Err(err) = rdev::listen(move |event| {
|
|
|
|
|
match event.event_type {
|
|
|
|
|
rdev::EventType::KeyPress(key) => {
|
|
|
|
|
let bit = match key {
|
|
|
|
|
rdev::Key::UpArrow => Some(0x1),
|
|
|
|
|
rdev::Key::LeftArrow => Some(0x2),
|
|
|
|
|
rdev::Key::RightArrow => Some(0x4),
|
|
|
|
|
_ => None,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if let Some(mask) = bit {
|
|
|
|
|
state_cloned.fetch_or(mask, Ordering::SeqCst);
|
|
|
|
|
let s = state_cloned.load(Ordering::SeqCst);
|
|
|
|
|
println!("[CMD] {:?} (state=0b{:03b})", state_to_vector(s), s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
rdev::EventType::KeyRelease(key) => {
|
|
|
|
|
let bit = match key {
|
|
|
|
|
rdev::Key::UpArrow => Some(0x1),
|
|
|
|
|
rdev::Key::LeftArrow => Some(0x2),
|
|
|
|
|
rdev::Key::RightArrow => Some(0x4),
|
|
|
|
|
_ => None,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if let Some(mask) = bit {
|
|
|
|
|
state_cloned.fetch_and(!mask, Ordering::SeqCst);
|
|
|
|
|
let s = state_cloned.load(Ordering::SeqCst);
|
|
|
|
|
println!("[CMD] {:?} (state=0b{:03b})", state_to_vector(s), s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}) {
|
|
|
|
|
eprintln!("rdev listen failed: {:?}", err);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
(handle, state)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn state_from_arc(state: &Arc<AtomicU8>) -> [f32; 3] {
|
|
|
|
|
state_to_vector(state.load(Ordering::SeqCst))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 状态位转成控制向量。
|
|
|
|
|
pub fn state_to_vector(state: u8) -> [f32; 3] {
|
|
|
|
|
if state & 0x1 != 0 {
|
|
|
|
|
if state & 0x2 != 0 {
|
|
|
|
|
[0.2, 0.0, -0.5]
|
|
|
|
|
} else if state & 0x4 != 0 {
|
|
|
|
|
[0.2, 0.0, 0.5]
|
|
|
|
|
} else {
|
|
|
|
|
[0.2, 0.0, 0.0]
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
[0.0, 0.0, 0.0]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_no_key() {
|
|
|
|
|
assert_eq!(state_to_vector(0), [0.0, 0.0, 0.0]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_up_only() {
|
|
|
|
|
assert_eq!(state_to_vector(0x1), [0.2, 0.0, 0.0]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_up_left() {
|
2026-10-20 08:58:50 +00:00
|
|
|
assert_eq!(state_to_vector(0x1 | 0x2), [0.2, 0.0, -0.05]);
|
2026-10-19 08:09:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_up_right() {
|
2026-10-20 08:58:50 +00:00
|
|
|
assert_eq!(state_to_vector(0x1 | 0x4), [0.2, 0.0, 0.05]);
|
2026-10-19 08:09:48 +00:00
|
|
|
}
|
|
|
|
|
}
|