106 lines
3.5 KiB
Rust
106 lines
3.5 KiB
Rust
use crate::coordinator::{ApplicationEvent, MoveEvent};
|
|
|
|
use async_channel::Sender;
|
|
use gilrs::{ev::filter::FilterFn, Axis, Button, Event, EventType, Filter, Gilrs, GilrsBuilder};
|
|
use log::{info, warn};
|
|
use std::{
|
|
panic::{self, AssertUnwindSafe},
|
|
sync::{atomic::AtomicBool, Arc},
|
|
time::Duration,
|
|
};
|
|
|
|
static MAX_SENT_ZEROS: u32 = 10;
|
|
|
|
struct UnknownSlayer;
|
|
impl FilterFn for UnknownSlayer {
|
|
fn filter(&self, ev: Option<Event>, _gilrs: &mut Gilrs) -> Option<Event> {
|
|
match ev {
|
|
Some(Event {
|
|
event: EventType::ButtonPressed(Button::Unknown, ..),
|
|
id,
|
|
..
|
|
})
|
|
| Some(Event {
|
|
event: EventType::ButtonReleased(Button::Unknown, ..),
|
|
id,
|
|
..
|
|
})
|
|
| Some(Event {
|
|
event: EventType::AxisChanged(Axis::Unknown, ..),
|
|
id,
|
|
..
|
|
}) => Some(Event::new(id, EventType::Dropped)),
|
|
_ => ev,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub async fn joystick_loop(tx: Sender<ApplicationEvent>, is_alive: Arc<AtomicBool>) {
|
|
let mut gilrs = GilrsBuilder::new().set_update_state(false).build().unwrap();
|
|
|
|
is_alive.store(true, std::sync::atomic::Ordering::SeqCst);
|
|
|
|
let mut curr_x: i32 = 0;
|
|
let mut curr_y: i32 = 0;
|
|
let mut past_x: i32 = 0;
|
|
let mut past_y: i32 = 0;
|
|
let mut count_zeros: u32 = 0;
|
|
|
|
loop {
|
|
// catch unwind because some buttons on the joystick will panic the gilrs object
|
|
match panic::catch_unwind(AssertUnwindSafe(|| {
|
|
// get the next event, and if it is an axis we are interested in, update the
|
|
// corresponding variable
|
|
while let Some(evt) = gilrs.next_event().filter_ev(&UnknownSlayer {}, &mut gilrs) {
|
|
match evt.event {
|
|
gilrs::EventType::AxisChanged(gilrs::Axis::LeftStickY, val, _) => {
|
|
curr_y = (val * 100.0) as i32;
|
|
if curr_y > -10 && curr_y < 10 {
|
|
curr_y = 0;
|
|
}
|
|
}
|
|
gilrs::EventType::AxisChanged(gilrs::Axis::LeftStickX, val, _) => {
|
|
curr_x = (val * 100.0) as i32;
|
|
if curr_x > -10 && curr_x < 10 {
|
|
curr_x = 0;
|
|
}
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
})) {
|
|
Ok(_) => {}
|
|
Err(_) => {
|
|
info!("panic-causing event captured in gilrs event handler")
|
|
}
|
|
}
|
|
|
|
if (curr_x != past_x || curr_y != past_y) || (count_zeros < MAX_SENT_ZEROS) {
|
|
past_x = curr_x;
|
|
past_y = curr_y;
|
|
|
|
if curr_x == 0 && curr_y == 0 {
|
|
count_zeros += 1;
|
|
} else {
|
|
count_zeros = 0;
|
|
}
|
|
|
|
match tx.try_send(ApplicationEvent::MoveEvent(MoveEvent {
|
|
x: curr_x,
|
|
y: curr_y,
|
|
})) {
|
|
Ok(_) => {}
|
|
Err(async_channel::TrySendError::Closed(_)) => {
|
|
info!("MEC is closed, stopping Joystick loop");
|
|
break;
|
|
}
|
|
Err(async_channel::TrySendError::Full(_)) => {
|
|
warn!("[joystick loop] The MEC is full!")
|
|
}
|
|
}
|
|
}
|
|
|
|
tokio::time::sleep(Duration::from_millis(50)).await;
|
|
}
|
|
is_alive.store(false, std::sync::atomic::Ordering::SeqCst);
|
|
}
|