ctrlassist 0.4.0

Controller Assist for gaming on Linux
use super::{DemuxMode, DemuxOutput, helpers};
use evdev::InputEvent;
use gilrs::{Event, EventType, GamepadId, Gilrs};

/// Multicast mode: Route primary to all virtual gamepads
pub struct MulticastMode;

impl MulticastMode {
    /// Convert a gilrs event to evdev 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 MulticastMode {
    fn handle_event(
        &mut self,
        event: &Event,
        primary_id: GamepadId,
        virtuals: usize,
        gilrs: &Gilrs,
    ) -> Option<DemuxOutput> {
        if event.id != primary_id {
            return None;
        }

        let primary = gilrs.gamepad(primary_id);

        Self::convert_event(event, primary).map(|events| {
            let distributed = (0..virtuals).map(|idx| (idx, events.clone())).collect();
            DemuxOutput::events(distributed)
        })
    }

    fn initial_active_virtuals(&self, virtuals: usize) -> Vec<usize> {
        (0..virtuals).collect()
    }
}