1use std::collections::HashMap;
2
3use pawkit_interner::InternString;
4
5use crate::{
6 DeviceId,
7 binding::{
8 AnalogBinding, BindingKind, BindingList, DigitalBinding, VectorBinding,
9 map::{BindingMap, BindingMapModificaitonError},
10 },
11 length_squared,
12 state::InputState,
13};
14
15#[repr(C)]
16#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
17pub struct DigitalInputFrame {
18 pub pressed: bool,
19 pub just_pressed: bool,
20 pub just_released: bool,
21}
22
23#[repr(C)]
24#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
25pub struct AnalogInputFrame {
26 pub value: f32,
27 pub delta: f32,
28}
29
30#[repr(C)]
31#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
32pub struct VectorInputFrame {
33 pub value: [f32; 2],
34 pub delta: [f32; 2],
35}
36
37#[repr(C)]
38#[derive(Clone, Copy)]
39pub union RawInputFrame {
40 digital: DigitalInputFrame,
41 analog: AnalogInputFrame,
42 vector: VectorInputFrame,
43}
44
45#[repr(C, u8)]
46#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
47pub enum InputFrame {
48 Digital(DigitalInputFrame),
49 Analog(AnalogInputFrame),
50 Vector(VectorInputFrame),
51}
52
53pub struct InputManager {
54 bindings: BindingMap,
55 devices: Vec<DeviceId>,
56 frame_indices: im::HashMap<InternString, usize>,
57 frames: Box<[RawInputFrame]>,
58}
59
60impl InputManager {
61 pub fn new(bindings: BindingMap) -> Self {
62 let mut frame_indices = HashMap::new();
63 let mut frames = vec![];
64
65 for (key, value) in &bindings {
66 let index = frames.len();
67 frame_indices.insert(key.clone(), index);
68
69 match value {
70 BindingList::Digital(_) => {
71 frames.push(RawInputFrame {
72 digital: DigitalInputFrame {
73 pressed: false,
74 just_pressed: false,
75 just_released: false,
76 },
77 });
78 }
79
80 BindingList::Analog(_) => {
81 frames.push(RawInputFrame {
82 analog: AnalogInputFrame {
83 value: 0f32,
84 delta: 0f32,
85 },
86 });
87 }
88
89 BindingList::Vector(_) => {
90 frames.push(RawInputFrame {
91 vector: VectorInputFrame {
92 value: [0f32; 2],
93 delta: [0f32; 2],
94 },
95 });
96 }
97 }
98 }
99
100 return Self {
101 bindings,
102 devices: vec![],
103 frame_indices: frame_indices.into(),
104 frames: frames.into(),
105 };
106 }
107
108 pub fn connect_device(&mut self, device: DeviceId) {
109 if self.devices.contains(&device) {
110 return;
111 }
112
113 self.devices.push(device);
114 }
115
116 pub fn disconnect_device(&mut self, device: DeviceId) {
117 self.devices.retain(|it| *it != device);
118 }
119
120 pub fn update(&mut self, state: &InputState) {
121 for (name, index) in &self.frame_indices {
122 let frame = &mut self.frames[*index];
123
124 let Some(bindings) = self.bindings.get_bindings(name) else {
125 continue;
126 };
127
128 match bindings {
129 BindingList::Digital(bindings) => {
130 let frame = unsafe { &mut frame.digital };
132
133 let mut pressed = false;
134
135 for device in &self.devices {
136 let Some(true) = state.get_digital(&device, bindings) else {
137 continue;
138 };
139
140 pressed = true;
141 break;
142 }
143
144 let was_pressed = frame.pressed;
145
146 frame.pressed = pressed;
147 frame.just_pressed = !was_pressed && pressed;
148 frame.just_released = was_pressed && !pressed;
149 }
150
151 BindingList::Analog(bindings) => {
152 let frame = unsafe { &mut frame.analog };
154
155 let mut value = 0f32;
156
157 for device in &self.devices {
158 let Some(analog) = state.get_analog(&device, bindings) else {
159 continue;
160 };
161
162 value = value.max(analog);
163 }
164
165 let old_value = frame.value;
166
167 frame.value = value;
168 frame.delta = value - old_value;
169 }
170
171 BindingList::Vector(bindings) => {
172 let frame = unsafe { &mut frame.vector };
174
175 let mut value = [0f32; 2];
176 let mut value_len_sqr = 0f32;
177
178 for device in &self.devices {
179 let Some(analog) = state.get_vector(&device, bindings) else {
180 continue;
181 };
182
183 let analog_len_sqr = length_squared(analog);
184
185 if analog_len_sqr > value_len_sqr {
186 value = analog;
187 value_len_sqr = analog_len_sqr;
188 }
189 }
190
191 let old_value = frame.value;
192
193 frame.value = value;
194 frame.delta = [old_value[0] - value[0], old_value[1] - value[1]];
195 }
196 }
197 }
198 }
199
200 pub unsafe fn get_binding_raw(&self, name: &InternString) -> Option<RawInputFrame> {
201 let index = self.frame_indices.get(name)?;
202
203 return Some(self.frames[*index]);
204 }
205
206 pub fn get_binding(&self, name: &InternString) -> Option<InputFrame> {
207 let index = self.frame_indices.get(name)?;
208
209 let frame = &self.frames[*index];
210
211 match self.bindings.get_binding_kind(name)? {
212 BindingKind::Digital => return Some(InputFrame::Digital(unsafe { frame.digital })),
213 BindingKind::Analog => return Some(InputFrame::Analog(unsafe { frame.analog })),
214 BindingKind::Vector => return Some(InputFrame::Vector(unsafe { frame.vector })),
215 }
216 }
217
218 pub fn add_digital_binding(
219 &mut self,
220 name: InternString,
221 value: DigitalBinding,
222 ) -> Result<(), BindingMapModificaitonError> {
223 return self.bindings.add_digital_binding(name, value);
224 }
225
226 pub fn remove_digital_binding(
227 &mut self,
228 name: InternString,
229 value: DigitalBinding,
230 ) -> Result<(), BindingMapModificaitonError> {
231 return self.bindings.remove_digital_binding(name, value);
232 }
233
234 pub fn add_analog_binding(
235 &mut self,
236 name: InternString,
237 value: AnalogBinding,
238 ) -> Result<(), BindingMapModificaitonError> {
239 return self.bindings.add_analog_binding(name, value);
240 }
241
242 pub fn remove_analog_binding(
243 &mut self,
244 name: InternString,
245 value: AnalogBinding,
246 ) -> Result<(), BindingMapModificaitonError> {
247 return self.bindings.remove_analog_binding(name, value);
248 }
249
250 pub fn add_vector_binding(
251 &mut self,
252 name: InternString,
253 value: VectorBinding,
254 ) -> Result<(), BindingMapModificaitonError> {
255 return self.bindings.add_vector_binding(name, value);
256 }
257
258 pub fn remove_vector_binding(
259 &mut self,
260 name: InternString,
261 value: VectorBinding,
262 ) -> Result<(), BindingMapModificaitonError> {
263 return self.bindings.remove_vector_binding(name, value);
264 }
265}