use crate::coordinator::{ApplicationEvent, MoveEvent}; use async_channel::Sender; use gilrs::{ev::filter::FilterFn, Axis, Button, Event, EventType, Filter, Gilrs, GilrsBuilder}; use log::{warn, info}; use std::{ panic::{self, AssertUnwindSafe}, sync::{atomic::AtomicBool, Arc}, time::Duration }; struct UnknownSlayer; impl FilterFn for UnknownSlayer { fn filter(&self, ev: Option, _gilrs: &mut Gilrs) -> Option { 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, is_alive: Arc ) { 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; 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 { past_x = curr_x; past_y = curr_y; 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); }