1use std::{collections::HashMap, fmt::Debug};
2
3use bitvec::{array::BitArray, slice::BitSlice};
4use pawkit_crockford::Ulid;
5use serde::Serialize;
6
7use crate::{
8 DeviceId,
9 binding::{
10 AnalogBinding, AnalogBindingKind, BoundAxis, BoundButton, DigitalBinding, VectorBinding,
11 VectorBindingKind,
12 axis::{GamepadAxis, MouseAxis},
13 button::{GamepadButton, KeyboardButton, MouseButton},
14 },
15 length_squared,
16};
17
18enum DeviceState {
19 Keyboard(BitArray<[u8; 15]>),
20 Mouse(BitArray<[u8; 1]>, [f32; 4]),
21 Gamepad(BitArray<[u8; 4]>, [f32; 6]),
22}
23
24#[repr(u8)]
25#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
26pub enum InputFamily {
27 Keyboard,
28 Mouse,
29 Gamepad,
30}
31
32pub struct InputState {
33 devices: HashMap<Ulid, DeviceState>,
34}
35
36impl DeviceState {
37 const EMPTY: [f32; 0] = [];
38
39 fn family(&self) -> InputFamily {
40 return match self {
41 Self::Keyboard(_) => InputFamily::Keyboard,
42 Self::Mouse(_, _) => InputFamily::Mouse,
43 Self::Gamepad(_, _) => InputFamily::Gamepad,
44 };
45 }
46
47 fn digital(&self) -> &BitSlice<u8> {
48 return match self {
49 Self::Keyboard(b) => b,
50 Self::Mouse(b, _) => b,
51 Self::Gamepad(b, _) => b,
52 };
53 }
54
55 fn analog(&self) -> &[f32] {
56 return match self {
57 Self::Keyboard(_) => &Self::EMPTY,
58 Self::Mouse(_, a) => a,
59 Self::Gamepad(_, a) => a,
60 };
61 }
62}
63
64impl InputState {
65 pub fn new() -> Self {
66 return Self {
67 devices: HashMap::new(),
68 };
69 }
70
71 #[inline(always)]
72 fn connect_device(&mut self, state: DeviceState) -> DeviceId {
73 let id = Ulid::new();
74
75 self.devices.insert(id, state);
76
77 return DeviceId(id);
78 }
79
80 pub fn device_family(&self, device: &DeviceId) -> Option<InputFamily> {
81 let device = self.devices.get(&device.0)?;
82
83 match device {
84 DeviceState::Keyboard(_) => return Some(InputFamily::Keyboard),
85 DeviceState::Mouse(_, _) => return Some(InputFamily::Mouse),
86 DeviceState::Gamepad(_, _) => return Some(InputFamily::Gamepad),
87 }
88 }
89
90 pub fn connect_keyboard(&mut self) -> DeviceId {
91 return self.connect_device(DeviceState::Keyboard(BitArray::new([0; 15])));
92 }
93
94 pub fn connect_mouse(&mut self) -> DeviceId {
95 return self.connect_device(DeviceState::Mouse(BitArray::new([0]), [0f32; 4]));
96 }
97
98 pub fn connect_gamepad(&mut self) -> DeviceId {
99 return self.connect_device(DeviceState::Gamepad(BitArray::new([0; 4]), [0f32; 6]));
100 }
101
102 pub fn disconnect_device(&mut self, device: &DeviceId) -> bool {
103 return self.devices.remove(&device.0).is_some();
104 }
105
106 pub fn set_keyboard_button(
107 &mut self,
108 device: &DeviceId,
109 button: KeyboardButton,
110 value: bool,
111 ) -> bool {
112 let Some(device) = self.devices.get_mut(&device.0) else {
113 return false;
114 };
115
116 let DeviceState::Keyboard(buttons) = device else {
117 return false;
118 };
119
120 buttons.set(button as usize, value);
121
122 return true;
123 }
124
125 pub fn set_mouse_button(
126 &mut self,
127 device: &DeviceId,
128 button: MouseButton,
129 value: bool,
130 ) -> bool {
131 let Some(device) = self.devices.get_mut(&device.0) else {
132 return false;
133 };
134
135 let DeviceState::Mouse(buttons, _) = device else {
136 return false;
137 };
138
139 buttons.set(button as usize, value);
140
141 return true;
142 }
143
144 pub fn set_gamepad_button(
145 &mut self,
146 device: &DeviceId,
147 button: GamepadButton,
148 value: bool,
149 ) -> bool {
150 let Some(device) = self.devices.get_mut(&device.0) else {
151 return false;
152 };
153
154 let DeviceState::Gamepad(buttons, _) = device else {
155 return false;
156 };
157
158 buttons.set(button as usize, value);
159
160 return true;
161 }
162
163 pub fn set_mouse_axis(&mut self, device: &DeviceId, axis: MouseAxis, value: f32) -> bool {
164 let Some(device) = self.devices.get_mut(&device.0) else {
165 return false;
166 };
167
168 let DeviceState::Mouse(_, axes) = device else {
169 return false;
170 };
171
172 axes[axis as usize] = value;
173
174 return true;
175 }
176
177 pub fn set_gamepad_axis(&mut self, device: &DeviceId, axis: GamepadAxis, value: f32) -> bool {
178 let Some(device) = self.devices.get_mut(&device.0) else {
179 return false;
180 };
181
182 let DeviceState::Gamepad(_, axes) = device else {
183 return false;
184 };
185
186 axes[axis as usize] = value;
187
188 return true;
189 }
190
191 fn get_digital_single<TButton, TAxis>(
192 &self,
193 digital: &BitSlice<u8>,
194 analog: &[f32],
195 button: BoundButton<TButton, TAxis>,
196 ) -> bool
197 where
198 TButton: Debug + Copy + PartialEq + Serialize + Into<usize>,
199 TAxis: Debug + Copy + PartialEq + Serialize + Into<usize>,
200 {
201 match button {
202 BoundButton::Digital { button } => return digital[button.into()],
203 BoundButton::Analog {
204 axis,
205 threshold,
206 scale,
207 } => return (analog[axis.into()] * scale) > threshold,
208 }
209 }
210
211 pub(crate) fn get_digital(
212 &self,
213 device: &DeviceId,
214 bindings: &[DigitalBinding],
215 ) -> Option<bool> {
216 let device = self.devices.get(&device.0)?;
217 let family = device.family();
218 let digital = device.digital();
219 let analog = device.analog();
220
221 for binding in bindings {
222 match binding {
223 DigitalBinding::Keyboard(button) if family == InputFamily::Keyboard => {
224 if self.get_digital_single(digital, analog, *button) {
225 return Some(true);
226 }
227 }
228
229 DigitalBinding::Mouse(button) if family == InputFamily::Mouse => {
230 if self.get_digital_single(digital, analog, *button) {
231 return Some(true);
232 }
233 }
234
235 DigitalBinding::Gamepad(button) if family == InputFamily::Gamepad => {
236 if self.get_digital_single(digital, analog, *button) {
237 return Some(true);
238 }
239 }
240
241 _ => continue,
242 }
243 }
244
245 return Some(false);
246 }
247
248 pub(crate) fn get_analog_single<TButton, TAxis>(
249 &self,
250 digital: &BitSlice<u8>,
251 analog: &[f32],
252 axis: BoundAxis<TButton, TAxis>,
253 ) -> f32
254 where
255 TButton: Debug + Copy + PartialEq + Serialize + Into<usize>,
256 TAxis: Debug + Copy + PartialEq + Serialize + Into<usize>,
257 {
258 match axis {
259 BoundAxis::Analog { axis } => return analog[axis.into()],
260 BoundAxis::Digital { button } => {
261 return if digital[button.into()] { 1f32 } else { 0f32 };
262 }
263 BoundAxis::MultiDigital { negative, positive } => {
264 let mut value = 0f32;
265
266 if digital[positive.into()] {
267 value += 1f32;
268 }
269
270 if digital[negative.into()] {
271 value -= 1f32;
272 }
273
274 return value;
275 }
276 }
277 }
278
279 pub(crate) fn get_analog(&self, device: &DeviceId, bindings: &[AnalogBinding]) -> Option<f32> {
280 let device = self.devices.get(&device.0)?;
281 let family = device.family();
282 let digital = device.digital();
283 let analog = device.analog();
284
285 let mut value = 0f32;
286
287 for binding in bindings {
288 match binding.axis {
289 AnalogBindingKind::Keyboard(axis) if family == InputFamily::Keyboard => {
290 let mut current = self.get_analog_single(digital, analog, axis);
291
292 if current.abs() < binding.deadzone {
293 current = 0.;
294 }
295
296 let scaled = current * binding.scale;
297
298 if scaled.abs() > value.abs() {
299 value = scaled;
300 }
301 }
302
303 AnalogBindingKind::Mouse(axis) if family == InputFamily::Mouse => {
304 let mut current = self.get_analog_single(digital, analog, axis);
305
306 if current.abs() < binding.deadzone {
307 current = 0.;
308 }
309
310 let scaled = current * binding.scale;
311
312 if scaled.abs() > value.abs() {
313 value = scaled;
314 }
315 }
316
317 AnalogBindingKind::Gamepad(axis) if family == InputFamily::Gamepad => {
318 let mut current = self.get_analog_single(digital, analog, axis);
319
320 if current.abs() < binding.deadzone {
321 current = 0.;
322 }
323
324 let scaled = current * binding.scale;
325
326 if scaled.abs() > value.abs() {
327 value = scaled;
328 }
329 }
330
331 _ => continue,
332 }
333 }
334
335 return Some(value);
336 }
337
338 pub(crate) fn get_vector(
339 &self,
340 device: &DeviceId,
341 bindings: &[VectorBinding],
342 ) -> Option<[f32; 2]> {
343 let device = self.devices.get(&device.0)?;
344 let family = device.family();
345 let digital = device.digital();
346 let analog = device.analog();
347
348 let mut value = [0f32; 2];
349 let mut value_len_sqr = 0f32;
350
351 for binding in bindings {
352 match binding.axes {
353 VectorBindingKind::Keyboard { x, y } if family == InputFamily::Keyboard => {
354 let mut current = [
355 self.get_analog_single(digital, analog, x) * binding.scale.0,
356 self.get_analog_single(digital, analog, y) * binding.scale.1,
357 ];
358
359 for i in 0..2 {
360 if current[i].abs() < binding.deadzone {
361 current[i] = 0.;
362 }
363 }
364
365 let current_len_sqr = length_squared(current);
366
367 if current_len_sqr > value_len_sqr {
368 value = current;
369 value_len_sqr = current_len_sqr;
370 }
371 }
372
373 VectorBindingKind::Mouse { x, y } if family == InputFamily::Mouse => {
374 let mut current = [
375 self.get_analog_single(digital, analog, x) * binding.scale.0,
376 self.get_analog_single(digital, analog, y) * binding.scale.1,
377 ];
378
379 for i in 0..2 {
380 if current[i].abs() < binding.deadzone {
381 current[i] = 0.;
382 }
383 }
384
385 let current_len_sqr = length_squared(current);
386
387 if current_len_sqr > value_len_sqr {
388 value = current;
389 value_len_sqr = current_len_sqr;
390 }
391 }
392
393 VectorBindingKind::Gamepad { x, y } if family == InputFamily::Gamepad => {
394 let mut current = [
395 self.get_analog_single(digital, analog, x) * binding.scale.0,
396 self.get_analog_single(digital, analog, y) * binding.scale.1,
397 ];
398
399 for i in 0..2 {
400 if current[i].abs() < binding.deadzone {
401 current[i] = 0.;
402 }
403 }
404
405 let current_len_sqr = length_squared(current);
406
407 if current_len_sqr > value_len_sqr {
408 value = current;
409 value_len_sqr = current_len_sqr;
410 }
411 }
412
413 _ => continue,
414 }
415 }
416
417 return Some(value);
418 }
419}