bones_framework/input/
gilrs.rs

1//! Gilrs integration.
2use crate::prelude::*;
3use gilrs::{ev::filter::axis_dpad_to_button, EventType, Filter, Gilrs as GilrsContext};
4use once_cell::sync::Lazy;
5use std::sync::{Arc, Mutex};
6
7#[cfg(target_arch = "wasm32")]
8use send_wrapper::SendWrapper;
9
10/// Lazy-initialized GilrsContext
11#[cfg(not(target_arch = "wasm32"))]
12static GILRS_CONTEXT: Lazy<Arc<Mutex<GilrsContext>>> = Lazy::new(|| {
13    Arc::new(Mutex::new(
14        GilrsContext::new().expect("Failed to initialize GilrsContext"),
15    ))
16});
17
18// Use SendWrapper when on wasm - GilrsContext is not Sync/Send on wasm,
19// this is ok because bevy is single threaded on wasm, it will only be
20// accessed from one thread.
21/// Lazy-initialized GilrsContext
22#[cfg(target_arch = "wasm32")]
23static GILRS_CONTEXT: Lazy<Arc<Mutex<SendWrapper<GilrsContext>>>> = Lazy::new(|| {
24    Arc::new(Mutex::new(SendWrapper::new(
25        GilrsContext::new().expect("Failed to initialize GilrsContext"),
26    )))
27});
28
29/// Processes gilrs gamepad events into Bones-native GamepadInputs
30pub fn process_gamepad_events() -> GamepadInputs {
31    let mut gamepad_inputs = GamepadInputs::default();
32    let mut gilrs = GILRS_CONTEXT.lock().unwrap();
33    while let Some(gilrs_event) = gilrs
34        .next_event()
35        .filter_ev(&axis_dpad_to_button, &mut gilrs)
36    {
37        gilrs.update(&gilrs_event);
38
39        let gamepad = usize::from(gilrs_event.id) as u32;
40        match gilrs_event.event {
41            EventType::Connected => {
42                let _pad = gilrs.gamepad(gilrs_event.id);
43                gamepad_inputs.gamepad_events.push(GamepadEvent::Connection(
44                    GamepadConnectionEvent {
45                        gamepad,
46                        event: GamepadConnectionEventKind::Connected,
47                    },
48                ));
49            }
50            EventType::Disconnected => {
51                gamepad_inputs.gamepad_events.push(GamepadEvent::Connection(
52                    GamepadConnectionEvent {
53                        gamepad,
54                        event: GamepadConnectionEventKind::Disconnected,
55                    },
56                ));
57            }
58            EventType::ButtonPressed(gilrs_button, _) => {
59                if let Some(button) = convert_button(gilrs_button) {
60                    gamepad_inputs
61                        .gamepad_events
62                        .push(GamepadEvent::Button(GamepadButtonEvent {
63                            gamepad,
64                            button,
65                            value: 1.0,
66                        }));
67                }
68            }
69            EventType::ButtonReleased(gilrs_button, _) => {
70                if let Some(button) = convert_button(gilrs_button) {
71                    gamepad_inputs
72                        .gamepad_events
73                        .push(GamepadEvent::Button(GamepadButtonEvent {
74                            gamepad,
75                            button,
76                            value: 0.0,
77                        }));
78                }
79            }
80            EventType::ButtonChanged(gilrs_button, value, _) => {
81                if let Some(button) = convert_button(gilrs_button) {
82                    gamepad_inputs
83                        .gamepad_events
84                        .push(GamepadEvent::Button(GamepadButtonEvent {
85                            gamepad,
86                            button,
87                            value,
88                        }));
89                }
90            }
91            EventType::AxisChanged(gilrs_axis, value, _) => {
92                if let Some(axis) = convert_axis(gilrs_axis) {
93                    gamepad_inputs
94                        .gamepad_events
95                        .push(GamepadEvent::Axis(GamepadAxisEvent {
96                            gamepad,
97                            axis,
98                            value,
99                        }));
100                }
101            }
102            _ => (),
103        };
104    }
105    gamepad_inputs
106}
107
108/// Converts a gilrs button to a bones-native button
109fn convert_button(button: gilrs::Button) -> Option<GamepadButton> {
110    match button {
111        gilrs::Button::South => Some(GamepadButton::South),
112        gilrs::Button::East => Some(GamepadButton::East),
113        gilrs::Button::North => Some(GamepadButton::North),
114        gilrs::Button::West => Some(GamepadButton::West),
115        gilrs::Button::C => Some(GamepadButton::C),
116        gilrs::Button::Z => Some(GamepadButton::Z),
117        gilrs::Button::LeftTrigger => Some(GamepadButton::LeftTrigger),
118        gilrs::Button::LeftTrigger2 => Some(GamepadButton::LeftTrigger2),
119        gilrs::Button::RightTrigger => Some(GamepadButton::RightTrigger),
120        gilrs::Button::RightTrigger2 => Some(GamepadButton::RightTrigger2),
121        gilrs::Button::Select => Some(GamepadButton::Select),
122        gilrs::Button::Start => Some(GamepadButton::Start),
123        gilrs::Button::Mode => Some(GamepadButton::Mode),
124        gilrs::Button::LeftThumb => Some(GamepadButton::LeftThumb),
125        gilrs::Button::RightThumb => Some(GamepadButton::RightThumb),
126        gilrs::Button::DPadUp => Some(GamepadButton::DPadUp),
127        gilrs::Button::DPadDown => Some(GamepadButton::DPadDown),
128        gilrs::Button::DPadLeft => Some(GamepadButton::DPadLeft),
129        gilrs::Button::DPadRight => Some(GamepadButton::DPadRight),
130        gilrs::Button::Unknown => None,
131    }
132}
133
134/// Converts a gilrs axis to a bones-native axis
135fn convert_axis(axis: gilrs::Axis) -> Option<GamepadAxis> {
136    match axis {
137        gilrs::Axis::LeftStickX => Some(GamepadAxis::LeftStickX),
138        gilrs::Axis::LeftStickY => Some(GamepadAxis::LeftStickY),
139        gilrs::Axis::LeftZ => Some(GamepadAxis::LeftZ),
140        gilrs::Axis::RightStickX => Some(GamepadAxis::RightStickX),
141        gilrs::Axis::RightStickY => Some(GamepadAxis::RightStickY),
142        gilrs::Axis::RightZ => Some(GamepadAxis::RightZ),
143        gilrs::Axis::Unknown | gilrs::Axis::DPadX | gilrs::Axis::DPadY => None,
144    }
145}