micro_games_kit/
gamepad.rs1use gilrs::{Axis, Button, GamepadId, Gilrs};
2use spitfire_input::{InputActionOrAxisRef, InputAxis};
3use std::{
4 cell::RefCell,
5 collections::{HashMap, HashSet},
6 rc::Rc,
7};
8
9#[derive(Debug, Clone)]
10pub enum GamepadInputAxis {
11 Single {
12 input: InputActionOrAxisRef,
13 deadzone: f32,
14 },
15 Double {
16 negative: InputActionOrAxisRef,
17 positive: InputActionOrAxisRef,
18 deadzone: f32,
19 },
20}
21
22impl GamepadInputAxis {
23 pub fn single(input: impl Into<InputActionOrAxisRef>, deadzone: f32) -> Self {
24 Self::Single {
25 input: input.into(),
26 deadzone,
27 }
28 }
29
30 pub fn double(
31 negative: impl Into<InputActionOrAxisRef>,
32 positive: impl Into<InputActionOrAxisRef>,
33 deadzone: f32,
34 ) -> Self {
35 Self::Double {
36 negative: negative.into(),
37 positive: positive.into(),
38 deadzone,
39 }
40 }
41}
42
43#[derive(Clone)]
44pub struct GamepadInput {
45 instance: Rc<RefCell<Gilrs>>,
46 used_gamepads: Rc<RefCell<HashSet<GamepadId>>>,
47 id: Option<GamepadId>,
48 pub buttons: HashMap<Button, InputActionOrAxisRef>,
49 pub axes: HashMap<Axis, GamepadInputAxis>,
50 pub auto_acquire: bool,
51}
52
53impl Drop for GamepadInput {
54 fn drop(&mut self) {
55 self.release();
56 }
57}
58
59impl GamepadInput {
60 pub fn acquire(&mut self) -> bool {
61 self.release();
62 let mut used_gamepads = self.used_gamepads.borrow_mut();
63 for (id, _) in self.instance.borrow().gamepads() {
64 if !used_gamepads.contains(&id) {
65 used_gamepads.insert(id);
66 self.id = Some(id);
67 return true;
68 }
69 }
70 false
71 }
72
73 pub fn release(&mut self) {
74 if let Some(id) = self.id.as_ref() {
75 self.used_gamepads.borrow_mut().remove(id);
76 }
77 self.id = None;
78 }
79
80 pub fn id(&self) -> Option<GamepadId> {
81 self.id
82 }
83
84 pub fn is_connected(&self) -> bool {
85 self.id.is_some()
86 }
87
88 pub fn button(mut self, id: Button, input: impl Into<InputActionOrAxisRef>) -> Self {
89 self.buttons.insert(id, input.into());
90 self
91 }
92
93 pub fn axis(mut self, id: Axis, input: impl Into<GamepadInputAxis>) -> Self {
94 self.axes.insert(id, input.into());
95 self
96 }
97
98 pub fn auto_acquire(mut self) -> Self {
99 self.auto_acquire = true;
100 self
101 }
102
103 pub fn apply(&mut self) {
104 if self.auto_acquire && !self.is_connected() {
105 self.acquire();
106 }
107 if let Some(id) = self.id {
108 let instance = self.instance.borrow();
109 let mut used_gamepads = self.used_gamepads.borrow_mut();
110 if let Some(gamepad) = instance.connected_gamepad(id) {
111 for (id, input) in &mut self.buttons {
112 if let Some(data) = gamepad.button_data(*id) {
113 match input {
114 InputActionOrAxisRef::Action(input) => {
115 input.set(input.get().change(data.is_pressed()));
116 }
117 InputActionOrAxisRef::Axis(input) => {
118 input.set(InputAxis(data.value()));
119 }
120 _ => {}
121 }
122 }
123 }
124 for (id, input) in &mut self.axes {
125 if let Some(data) = gamepad.axis_data(*id) {
126 match input {
127 GamepadInputAxis::Single { input, deadzone } => {
128 let mut value = data.value().abs();
129 if value < *deadzone {
130 value = 0.0;
131 }
132 match input {
133 InputActionOrAxisRef::Action(input) => {
134 input.set(input.get().change(value > 0.5));
135 }
136 InputActionOrAxisRef::Axis(input) => {
137 input.set(InputAxis(value));
138 }
139 _ => {}
140 }
141 }
142 GamepadInputAxis::Double {
143 negative,
144 positive,
145 deadzone,
146 } => {
147 let mut value = data.value();
148 if value.abs() < *deadzone {
149 value = 0.0;
150 }
151 match positive {
152 InputActionOrAxisRef::Action(input) => {
153 input.set(input.get().change(value > 0.5));
154 }
155 InputActionOrAxisRef::Axis(input) => {
156 input.set(InputAxis(value.max(0.0)));
157 }
158 _ => {}
159 }
160 match negative {
161 InputActionOrAxisRef::Action(input) => {
162 input.set(input.get().change(value < -0.5));
163 }
164 InputActionOrAxisRef::Axis(input) => {
165 input.set(InputAxis(-value.min(0.0)));
166 }
167 _ => {}
168 }
169 }
170 }
171 }
172 }
173 } else {
174 used_gamepads.remove(&id);
175 self.id = None;
176 }
177 }
178 }
179}
180
181pub struct GamepadManager {
182 instance: Option<Rc<RefCell<Gilrs>>>,
183 used_gamepads: Rc<RefCell<HashSet<GamepadId>>>,
184}
185
186impl Default for GamepadManager {
187 fn default() -> Self {
188 Self {
189 instance: Gilrs::new()
190 .ok()
191 .map(|instance| Rc::new(RefCell::new(instance))),
192 used_gamepads: Default::default(),
193 }
194 }
195}
196
197impl GamepadManager {
198 pub fn is_supported(&self) -> bool {
199 self.instance.is_some()
200 }
201
202 pub fn request_gamepad(&self) -> Option<GamepadInput> {
203 Some(GamepadInput {
204 instance: self.instance.as_ref()?.clone(),
205 used_gamepads: self.used_gamepads.clone(),
206 id: Default::default(),
207 buttons: Default::default(),
208 axes: Default::default(),
209 auto_acquire: Default::default(),
210 })
211 }
212
213 pub fn maintain(&mut self) {
214 if let Some(instance) = self.instance.as_mut() {
215 while instance.borrow_mut().next_event().is_some() {}
216 }
217 }
218}