TwoFootBot-rust/src/command.rs

97 lines
2.8 KiB
Rust
Raw Normal View History

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() {
assert_eq!(state_to_vector(0x1 | 0x2), [0.2, 0.0, -0.5]);
}
#[test]
fn test_up_right() {
assert_eq!(state_to_vector(0x1 | 0x4), [0.2, 0.0, 0.5]);
}
}