1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
use crate::converter::{convert_axis, convert_button, convert_gamepad_id};
use bevy_ecs::event::EventWriter;
use bevy_ecs::system::{NonSend, NonSendMut, Res, ResMut};
use bevy_input::gamepad::{
    GamepadAxisChangedEvent, GamepadButtonChangedEvent, GamepadConnection, GamepadConnectionEvent,
    GamepadSettings,
};
use bevy_input::gamepad::{GamepadEvent, GamepadInfo};
use bevy_input::prelude::{GamepadAxis, GamepadButton};
use bevy_input::Axis;
use gilrs::{ev::filter::axis_dpad_to_button, EventType, Filter, Gilrs};

pub fn gilrs_event_startup_system(
    gilrs: NonSend<Gilrs>,
    mut connection_events: EventWriter<GamepadConnectionEvent>,
) {
    for (id, gamepad) in gilrs.gamepads() {
        let info = GamepadInfo {
            name: gamepad.name().into(),
        };

        connection_events.send(GamepadConnectionEvent {
            gamepad: convert_gamepad_id(id),
            connection: GamepadConnection::Connected(info),
        });
    }
}

pub fn gilrs_event_system(
    mut gilrs: NonSendMut<Gilrs>,
    mut events: EventWriter<GamepadEvent>,
    mut gamepad_buttons: ResMut<Axis<GamepadButton>>,
    gamepad_axis: Res<Axis<GamepadAxis>>,
    gamepad_settings: Res<GamepadSettings>,
) {
    while let Some(gilrs_event) = gilrs
        .next_event()
        .filter_ev(&axis_dpad_to_button, &mut gilrs)
    {
        gilrs.update(&gilrs_event);

        let gamepad = convert_gamepad_id(gilrs_event.id);
        match gilrs_event.event {
            EventType::Connected => {
                let pad = gilrs.gamepad(gilrs_event.id);
                let info = GamepadInfo {
                    name: pad.name().into(),
                };

                events.send(
                    GamepadConnectionEvent::new(gamepad, GamepadConnection::Connected(info)).into(),
                );
            }
            EventType::Disconnected => {
                events.send(
                    GamepadConnectionEvent::new(gamepad, GamepadConnection::Disconnected).into(),
                );
            }
            EventType::ButtonChanged(gilrs_button, raw_value, _) => {
                if let Some(button_type) = convert_button(gilrs_button) {
                    let button = GamepadButton::new(gamepad, button_type);
                    let old_value = gamepad_buttons.get(button);
                    let button_settings = gamepad_settings.get_button_axis_settings(button);

                    // Only send events that pass the user-defined change threshold
                    if let Some(filtered_value) = button_settings.filter(raw_value, old_value) {
                        events.send(
                            GamepadButtonChangedEvent::new(gamepad, button_type, filtered_value)
                                .into(),
                        );
                        // Update the current value prematurely so that `old_value` is correct in
                        // future iterations of the loop.
                        gamepad_buttons.set(button, filtered_value);
                    }
                }
            }
            EventType::AxisChanged(gilrs_axis, raw_value, _) => {
                if let Some(axis_type) = convert_axis(gilrs_axis) {
                    let axis = GamepadAxis::new(gamepad, axis_type);
                    let old_value = gamepad_axis.get(axis);
                    let axis_settings = gamepad_settings.get_axis_settings(axis);

                    // Only send events that pass the user-defined change threshold
                    if let Some(filtered_value) = axis_settings.filter(raw_value, old_value) {
                        events.send(
                            GamepadAxisChangedEvent::new(gamepad, axis_type, filtered_value).into(),
                        );
                    }
                }
            }
            _ => (),
        };
    }
    gilrs.inc();
}