azul_layout/managers/
gamepad.rs1use alloc::vec::Vec;
22
23use azul_core::dom::DomNodeId;
24use azul_core::events::{
25 EventData, EventProvider, EventSource as CoreEventSource, EventType, SyntheticEvent,
26};
27use azul_core::task::Instant;
28pub use azul_core::gamepad::{GamepadAxis, GamepadButton, GamepadId, GamepadState};
29
30#[derive(Debug, Clone, PartialEq, Default)]
33pub struct GamepadManager {
34 pads: Vec<GamepadState>,
37 pending_event: bool,
40}
41
42impl GamepadManager {
43 pub fn new() -> Self {
44 Self::default()
45 }
46
47 pub fn state(&self, id: GamepadId) -> Option<GamepadState> {
49 self.pads.iter().find(|p| p.id == id).copied()
50 }
51
52 pub fn primary(&self) -> Option<GamepadState> {
55 self.pads.iter().find(|p| p.connected).copied()
56 }
57
58 pub fn gamepads(&self) -> &[GamepadState] {
60 &self.pads
61 }
62
63 pub fn set_state(&mut self, state: GamepadState) -> bool {
67 let changed = if let Some(slot) = self.pads.iter_mut().find(|p| p.id == state.id) {
68 let changed = !state_bitwise_eq(slot, &state);
69 *slot = state;
70 changed
71 } else {
72 self.pads.push(state);
73 true
74 };
75 if changed {
76 self.pending_event = true;
77 }
78 changed
79 }
80
81 pub fn clear_pending_event(&mut self) {
84 self.pending_event = false;
85 }
86}
87
88impl EventProvider for GamepadManager {
89 fn get_pending_events(&self, timestamp: Instant) -> Vec<SyntheticEvent> {
93 if self.pending_event {
94 alloc::vec![SyntheticEvent::new(
95 EventType::GamepadInput,
96 CoreEventSource::User,
97 DomNodeId::ROOT,
98 timestamp,
99 EventData::None,
100 )]
101 } else {
102 Vec::new()
103 }
104 }
105}
106
107fn state_bitwise_eq(a: &GamepadState, b: &GamepadState) -> bool {
108 a.id == b.id
109 && a.connected == b.connected
110 && a.buttons == b.buttons
111 && a.left_stick_x.to_bits() == b.left_stick_x.to_bits()
112 && a.left_stick_y.to_bits() == b.left_stick_y.to_bits()
113 && a.right_stick_x.to_bits() == b.right_stick_x.to_bits()
114 && a.right_stick_y.to_bits() == b.right_stick_y.to_bits()
115 && a.left_z.to_bits() == b.left_z.to_bits()
116 && a.right_z.to_bits() == b.right_z.to_bits()
117}
118
119static PENDING_STATES: std::sync::Mutex<Vec<GamepadState>> = std::sync::Mutex::new(Vec::new());
128
129pub fn push_gamepad_state(state: GamepadState) {
132 let mut q = PENDING_STATES.lock().unwrap_or_else(|e| e.into_inner());
133 q.push(state);
134}
135
136pub fn drain_gamepad_states() -> Vec<GamepadState> {
140 let mut q = PENDING_STATES.lock().unwrap_or_else(|e| e.into_inner());
141 core::mem::take(&mut *q)
142}
143
144#[cfg(test)]
145mod tests {
146 use super::*;
147
148 fn st(id: u32, connected: bool, buttons: u32) -> GamepadState {
149 let mut s = GamepadState::empty(GamepadId { id });
150 s.connected = connected;
151 s.buttons = buttons;
152 s
153 }
154
155 #[test]
156 fn manager_upserts_by_id_and_flags_change() {
157 let mut mgr = GamepadManager::new();
158 assert_eq!(mgr.state(GamepadId { id: 0 }), None);
159 assert!(mgr.set_state(st(0, true, 0b1)));
161 assert!(mgr.state(GamepadId { id: 0 }).is_some());
162 assert!(!mgr.set_state(st(0, true, 0b1)));
164 assert!(mgr.set_state(st(0, true, 0b11)));
166 assert_eq!(mgr.gamepads().len(), 1);
167 assert!(mgr.set_state(st(1, true, 0)));
169 assert_eq!(mgr.gamepads().len(), 2);
170 }
171
172 #[test]
173 fn primary_is_first_connected() {
174 let mut mgr = GamepadManager::new();
175 mgr.set_state(st(0, false, 0)); mgr.set_state(st(1, true, 0));
177 assert_eq!(mgr.primary().map(|p| p.id.id), Some(1));
178 }
179
180 #[test]
181 fn is_pressed_decodes_the_bitset() {
182 let s = st(0, true, GamepadButton::South.bit() | GamepadButton::Start.bit());
183 assert!(s.is_pressed(GamepadButton::South));
184 assert!(s.is_pressed(GamepadButton::Start));
185 assert!(!s.is_pressed(GamepadButton::East));
186 }
187
188 #[test]
189 fn states_round_trip_through_the_channel() {
190 let _ = drain_gamepad_states();
191 push_gamepad_state(st(0, true, 0b1));
192 push_gamepad_state(st(0, true, 0b10)); push_gamepad_state(st(1, true, 0));
194 let drained = drain_gamepad_states();
195 assert_eq!(drained.len(), 3);
196
197 let mut mgr = GamepadManager::new();
198 for s in &drained {
199 mgr.set_state(*s);
200 }
201 assert_eq!(mgr.state(GamepadId { id: 0 }).map(|p| p.buttons), Some(0b10));
202 assert_eq!(mgr.gamepads().len(), 2);
203 assert!(drain_gamepad_states().is_empty());
204 }
205}