use super::{MuxMode, MuxOutput, helpers};
use evdev::InputEvent;
use gilrs::{Event, EventType, GamepadId, Gilrs};
#[derive(Default)]
pub struct ToggleMode {
active_id: Option<GamepadId>,
}
impl ToggleMode {
fn sync_controller_state(
active: gilrs::Gamepad,
active_id: GamepadId,
assist_id: GamepadId,
) -> Vec<InputEvent> {
let state = active.state();
let mut events = Vec::new();
for (code, button_data) in state.buttons() {
let Some(gilrs::ev::AxisOrBtn::Btn(btn)) = active.axis_or_btn_name(code) else {
continue;
};
if active_id == assist_id && btn == gilrs::Button::Mode {
continue;
}
if let Some(event) = helpers::create_button_key_event(btn, button_data.is_pressed()) {
events.push(event);
}
if let Some(abs_axis) = crate::utils::evdev::gilrs_button_to_evdev_axis(btn) {
events.push(helpers::process_button_axis(btn, &active, abs_axis));
}
}
for (code, axis_data) in state.axes() {
let Some(gilrs::ev::AxisOrBtn::Axis(axis)) = active.axis_or_btn_name(code) else {
continue;
};
if let Some(event) = helpers::create_stick_event(axis, axis_data.value()) {
events.push(event);
}
}
events
}
fn convert_event(event: &Event, active: gilrs::Gamepad) -> Option<Vec<InputEvent>> {
match event.event {
EventType::ButtonPressed(btn, _) | EventType::ButtonReleased(btn, _) => {
let is_pressed = matches!(event.event, EventType::ButtonPressed(..));
helpers::create_button_key_event(btn, is_pressed).map(|e| vec![e])
}
EventType::ButtonChanged(btn, _, _) => {
let abs_axis = crate::utils::evdev::gilrs_button_to_evdev_axis(btn)?;
Some(vec![helpers::process_button_axis(btn, &active, abs_axis)])
}
EventType::AxisChanged(axis, raw_val, _) => {
helpers::create_stick_event(axis, raw_val).map(|e| vec![e])
}
_ => None,
}
}
}
impl MuxMode for ToggleMode {
fn handle_event(
&mut self,
event: &Event,
primary_id: GamepadId,
assist_id: GamepadId,
gilrs: &Gilrs,
) -> Option<MuxOutput> {
let active_id = self.active_id.get_or_insert(primary_id);
if matches!(
(event.id, event.event),
(id, EventType::ButtonPressed(gilrs::Button::Mode, _)) if id == assist_id
) {
*active_id = if *active_id == primary_id {
assist_id
} else {
primary_id
};
let active = gilrs.gamepad(*active_id);
let sync_events = Self::sync_controller_state(active, *active_id, assist_id);
return Some(MuxOutput::with_active(sync_events, vec![*active_id]));
}
if event.id != *active_id {
return None;
}
let active = gilrs.gamepad(*active_id);
Self::convert_event(event, active).map(MuxOutput::events)
}
fn initial_active_controllers(
&self,
primary_id: GamepadId,
_assist_id: GamepadId,
) -> Vec<GamepadId> {
vec![primary_id]
}
}