use super::{DemuxMode, DemuxOutput, helpers};
use evdev::InputEvent;
use gilrs::{Button, Event, EventType, GamepadId, Gilrs};
const DEMUX_UNICAST_LATCHING: bool = false;
#[derive(Default)]
pub struct UnicastMode {
active_index: usize,
}
impl UnicastMode {
fn sync_controller_state(primary: gilrs::Gamepad) -> Vec<InputEvent> {
let state = primary.state();
let mut events = Vec::new();
for (code, button_data) in state.buttons() {
let Some(gilrs::ev::AxisOrBtn::Btn(btn)) = primary.axis_or_btn_name(code) else {
continue;
};
if 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, &primary, abs_axis));
}
}
for (code, axis_data) in state.axes() {
let Some(gilrs::ev::AxisOrBtn::Axis(axis)) = primary.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, primary: 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, &primary, abs_axis)])
}
EventType::AxisChanged(axis, raw_val, _) => {
helpers::create_stick_event(axis, raw_val).map(|e| vec![e])
}
_ => None,
}
}
}
impl DemuxMode for UnicastMode {
fn handle_event(
&mut self,
event: &Event,
primary_id: GamepadId,
virtuals: usize,
gilrs: &Gilrs,
) -> Option<DemuxOutput> {
if event.id != primary_id {
return None;
}
if matches!(event.event, EventType::ButtonPressed(Button::Mode, _)) {
let old_active = self.active_index;
self.active_index = (self.active_index + 1) % virtuals;
let primary = gilrs.gamepad(primary_id);
let sync_events = Self::sync_controller_state(primary);
let mut events = Vec::new();
if !DEMUX_UNICAST_LATCHING && old_active != self.active_index {
let neutral_events = crate::utils::evdev::generate_neutral_gamepad_events();
events.push((old_active, neutral_events));
}
events.push((self.active_index, sync_events));
return Some(DemuxOutput {
events,
set_active_virtuals: Some(vec![self.active_index]),
});
}
let primary = gilrs.gamepad(primary_id);
Self::convert_event(event, primary)
.map(|e| DemuxOutput::events(vec![(self.active_index, e)]))
}
fn initial_active_virtuals(&self, _virtuals: usize) -> Vec<usize> {
vec![0]
}
}