1#[cfg(feature = "mice-keyboard")]
2use winit::{
3 dpi::PhysicalPosition,
4 event::*,
5};
6use crate::input_code::*;
7use std::collections::HashMap;
8use std::{cmp::Eq, hash::Hash};
9#[cfg(not(feature = "glium-types"))]
10type Vec2 = (f32, f32);
11#[cfg(feature = "glium-types")]
12type Vec2 = glium_types::vectors::Vec2;
13fn v(a: f32, b: f32) -> Vec2 {
14 #[cfg(not(feature = "glium-types"))]
15 { (a, b) }
16 #[cfg(feature = "glium-types")]
17 { Vec2::new(a, b) }
18}
19pub struct InputMap<F: Hash + Eq + Clone + Copy> {
50 pub binds: HashMap<InputCode, (f32, Vec<F>)>,
52 action_val: HashMap<F, (f32, bool, bool)>,
54 #[cfg(feature = "mice-keyboard")]
56 pub mouse_pos: Vec2,
57 pub recently_pressed: Option<InputCode>,
59 pub text_typed: Option<String>,
61 #[cfg(feature = "mice-keyboard")]
64 pub mouse_scale: f32,
65 #[cfg(feature = "mice-keyboard")]
68 pub scroll_scale: f32,
69 pub press_sensitivity: f32
72}
73impl<F: Hash + Eq + Copy> Default for InputMap<F> {
74 fn default() -> Self {
75 Self {
76 #[cfg(feature = "mice-keyboard")]
77 mouse_scale: 0.01,
78 press_sensitivity: 0.5,
79 #[cfg(feature = "mice-keyboard")]
80 scroll_scale: 1.0,
81 #[cfg(feature = "mice-keyboard")]
82 mouse_pos: v(0.0, 0.0),
83 recently_pressed: None,
84 text_typed: None,
85 binds: HashMap::<InputCode, (f32, Vec<F>)>::new(),
86 action_val: HashMap::<F, (f32, bool, bool)>::new()
87 }
88 }
89}
90impl<F: Hash + Eq + Copy> InputMap<F> {
91 pub fn new(binds: &[(F, Vec<InputCode>)]) -> Self {
113 let mut result = Self::default();
114 for (i, binds) in binds {
115 for bind in binds {
116 result.mut_bind(*bind).push(*i);
117 }
118 }
119 result.binds.shrink_to_fit();
120 result
121 }
122 pub fn empty() -> InputMap<()> {
124 InputMap::<()>::default()
125 }
126 pub fn mut_bind(&mut self, input_code: InputCode) -> &mut Vec<F> {
128 let has_val = self.binds.contains_key(&input_code);
129 &mut (if has_val { self.binds.get_mut(&input_code) } else {
130 self.binds.insert(input_code, (0.0, vec![]));
131 self.binds.get_mut(&input_code)
132 }).unwrap().1
133 }
134 #[cfg(feature = "mice-keyboard")]
156 #[deprecated = "use `update_with_window_event` and `update_with_device_event`"]
157 pub fn update_with_winit(&mut self, event: &Event<()>) {
158 match event {
159 Event::WindowEvent { event, .. } => self.update_with_window_event(event),
160 Event::DeviceEvent { event, device_id, .. } => self.update_with_device_event(*device_id, event),
161 _ => ()
162 }
163 }
164 #[cfg(feature = "mice-keyboard")]
165 pub fn update_with_device_event(&mut self, id: DeviceId, event: &DeviceEvent) {
166 use base_input_codes::*;
167 match event {
168 DeviceEvent::MouseMotion { delta } => {
169 let x = delta.0 as f32 * self.mouse_scale;
170 let y = delta.1 as f32 * self.mouse_scale;
171 self.modify_val(MouseMoveLeft.with_id(id), |v| v + x.max(0.0));
172 self.modify_val(MouseMoveRight.with_id(id), |v| v - x.min(0.0));
173 self.modify_val(MouseMoveUp.with_id(id), |v| v + y.max(0.0));
174 self.modify_val(MouseMoveDown.with_id(id), |v| v - y.min(0.0));
175 },
176 DeviceEvent::MouseWheel { delta } => self.update_scroll(*delta, id),
177 _ => (),
178 }
179 }
180 #[cfg(feature = "mice-keyboard")]
181 pub fn update_with_window_event(&mut self, event: &WindowEvent) {
182 match event {
183 WindowEvent::CursorMoved { position, .. } => self.update_mouse(*position),
184 WindowEvent::MouseWheel { delta, device_id, .. } => self.update_scroll(*delta, *device_id),
185 WindowEvent::MouseInput { state, button, device_id } => self.update_buttons(state, *device_id, *button),
186 WindowEvent::KeyboardInput { event, device_id, .. } => self.update_keys(*device_id, event),
187 _ => ()
188 }
189 }
190 #[cfg(feature = "gamepad")]
191 pub fn update_with_gilrs(&mut self, gilrs: &mut gilrs::Gilrs) {
192 while let Some(ev) = gilrs.next_event() {
193 self.update_gamepad(ev);
194 }
195 }
196 pub fn init(&mut self) {
198 #[cfg(feature = "mice-keyboard")]
199 {
200 use base_input_codes::*;
201 for i in [MouseMoveLeft, MouseMoveRight,
202 MouseMoveUp, MouseMoveDown, MouseScrollUp,
203 MouseScrollDown, MouseScrollLeft,
204 MouseScrollRight] {
205 self.update_val(i.into(), 0.0);
206 }
207 }
208 self.action_val.iter_mut().for_each(|(_, i)|
209 *i = (i.0, false, false)
210 );
211 self.recently_pressed = None;
212 self.text_typed = None;
213 }
214 #[cfg(feature = "mice-keyboard")]
215 fn update_scroll(&mut self, delta: MouseScrollDelta, id: DeviceId) {
216 use base_input_codes::*;
217 let (x, y) = match delta {
218 MouseScrollDelta::LineDelta(x, y) => (x, y),
219 MouseScrollDelta::PixelDelta(PhysicalPosition { x, y }) => (x as f32, y as f32)
220 };
221 let (x, y) = (x * self.scroll_scale, y * self.scroll_scale);
222
223 self.modify_val(MouseScrollUp.with_id(id), |v| v + y.max(0.0));
224 self.modify_val(MouseScrollDown.with_id(id), |v| v - y.min(0.0));
225 self.modify_val(MouseScrollLeft.with_id(id), |v| v + x.max(0.0));
226 self.modify_val(MouseScrollRight.with_id(id), |v| v - x.min(0.0));
227 }
228 #[cfg(feature = "mice-keyboard")]
229 fn update_mouse(&mut self, position: PhysicalPosition<f64>) {
230 self.mouse_pos = v(position.x as f32, position.y as f32);
231 }
232 #[cfg(feature = "mice-keyboard")]
233 fn update_keys(&mut self, id: DeviceId, event: &KeyEvent) {
234 let input_code: DeviceInput = event.physical_key.into();
235
236 if let (Some(string), Some(new)) = (&mut self.text_typed, &event.text) {
237 string.push_str(new);
238 } else { self.text_typed = event.text.as_ref().map(|i| i.to_string()) }
239
240 self.update_val(input_code.with_id(id), event.state.is_pressed().into());
241 }
242 #[cfg(feature = "mice-keyboard")]
243 fn update_buttons(&mut self, state: &ElementState, id: DeviceId, button: MouseButton) {
244 let input_code: DeviceInput = button.into();
245 self.update_val(input_code.with_id(id), state.is_pressed().into());
246 }
247 fn update_val(&mut self, input_code: InputCode, val: f32) {
249 let pressing = val >= self.press_sensitivity;
250 if pressing && !input_code.is_any() { self.recently_pressed = Some(input_code) }
251
252 let Some((bind_val, binds)) = self.binds.get(&input_code) else {
253 if !input_code.is_any() {
254 let any = input_code.set_any();
255 if self.binds.contains_key(&any) {
256 self.modify_any_val(any, |_| val);
257 }
258 }
259 return
260 };
261
262 let diff = val - bind_val; for &action in binds {
264 let pressed = self.pressing(action);
265 let jpressed = !pressed && pressing;
266 let released = pressed && !pressing;
267 let mut val = self.action_val(action) + diff;
269 if val <= f32::EPSILON { val = 0.0 }
270 self.action_val.insert(action, (val, jpressed, released));
271 }
272
273 self.binds.get_mut(&input_code).unwrap().0 = val;
274
275 if !input_code.is_any() {
276 let any = input_code.set_any();
277 if self.binds.contains_key(&any) {
278 self.modify_val(any, |v| v + diff);
279 }
280 }
281 }
282 fn modify_val<FN: Fn(f32) -> f32>(&mut self, input_code: InputCode, f: FN) {
283 let Some((bind_val, binds)) = self.binds.get(&input_code) else {
284 if f(0.0) >= self.press_sensitivity && !input_code.is_any() { self.recently_pressed = Some(input_code) }
285 if !input_code.is_any() {
286 let any = input_code.set_any();
287 if self.binds.contains_key(&any) {
288 self.modify_any_val(any, f);
289 }
290 }
291 return;
292 };
293
294 let val = f(*bind_val);
295 let diff = val - *bind_val;
296 for &action in binds {
297 let pressing = val >= self.press_sensitivity;
298 if pressing && !input_code.is_any() { self.recently_pressed = Some(input_code) }
299
300 let pressed = self.pressing(action);
301 let jpressed = pressing && !pressed;
302 let released = !pressing && pressed;
303
304 let val = self.action_val(action) + diff;
305 self.action_val.insert(action, (val, jpressed, released));
306 }
307
308 self.binds.get_mut(&input_code).unwrap().0 = val;
309
310 if !input_code.is_any() {
311 let any = input_code.set_any();
312 if self.binds.contains_key(&any) {
313 self.modify_any_val(any, |v| v + diff);
314 }
315 }
316 }
317 fn modify_any_val<FN: Fn(f32) -> f32>(&mut self, input_code: InputCode, f: FN) {
318 let Some((bind_val, binds)) = self.binds.get(&input_code) else {
319 if input_code.is_any() { return }
320 if f(0.0) >= self.press_sensitivity && !input_code.is_any() { self.recently_pressed = Some(input_code) }
321 return;
322 };
323
324 let val = f(*bind_val);
325 let diff = val - *bind_val;
326 for &action in binds {
327 let pressing = val >= self.press_sensitivity;
328 if pressing && !input_code.is_any() { self.recently_pressed = Some(input_code) }
329
330 let pressed = self.pressing(action);
331 let jpressed = pressing && !pressed;
332 let released = !pressing && pressed;
333
334 let val = self.action_val(action) + diff;
335 self.action_val.insert(action, (val, jpressed, released));
336 }
337
338 self.binds.get_mut(&input_code).unwrap().0 = val;
339 }
340 #[cfg(feature = "gamepad")]
341 fn update_gamepad(&mut self, event: gilrs::Event) {
342 let gilrs::Event { id, event, .. } = event;
343 use crate::input_code::{axis_pos, axis_neg};
344 use gilrs::ev::EventType;
345 match event {
346 EventType::ButtonChanged(b, v, _) => {
347 let a: GamepadInput = b.into();
348 self.update_val(a.with_id(id), v);
349 },
350 EventType::AxisChanged(b, v, _) => {
351 let dir_pos = v.max(0.0);
352 let dir_neg = (-v).max(0.0);
353 let input_pos = axis_pos(b);
354 let input_neg = axis_neg(b);
355
356 self.update_val(input_pos.with_id(id), dir_pos);
357 self.update_val(input_neg.with_id(id), dir_neg);
358 },
359 EventType::Disconnected => {
360 use GamepadInput::*;
363 for i in [LeftStickLeft, LeftStickRight, LeftStickUp, LeftStickDown, LeftStickPress,
364 RightStickLeft, RightStickRight, RightStickUp, RightStickDown,
365 RightStickPress, DPadLeft, DPadRight, DPadUp, DPadDown, LeftZ, RightZ,
366 South, East, North, West, LeftTrigger, LeftTrigger2, RightTrigger,
367 RightTrigger2, Select, Start, Mode, Other].iter() {
368 self.update_val(i.with_id(id), 0.0);
369 }
370 }
371 _ => ()
372 }
373 }
374 pub fn pressing(&self, action: F) -> bool {
377 self.action_val(action) >= self.press_sensitivity
378 }
379 pub fn action_val(&self, action: F) -> f32 {
382 if let Some(&(v, _, _)) = self.action_val.get(&action) { v } else { 0.0 }
383 }
384 pub fn pressed(&self, action: F) -> bool {
386 if let Some(&(_, v, _)) = self.action_val.get(&action) { v } else { false }
387 }
388 pub fn released(&self, action: F) -> bool {
390 if let Some(&(_, _, v)) = self.action_val.get(&action) { v } else { false }
391 }
392 pub fn axis(&self, pos: F, neg: F) -> f32 {
400 self.action_val(pos) - self.action_val(neg)
401 }
402 pub fn dir(&self, pos_x: F, neg_x: F, pos_y: F, neg_y: F) -> Vec2 {
404 v(self.axis(pos_x, neg_x), self.axis(pos_y, neg_y))
405 }
406 pub fn dir_max_len_1(&self, pos_x: F, neg_x: F, pos_y: F, neg_y: F) -> Vec2 {
409 let (x, y) = (self.axis(pos_x, neg_x), self.axis(pos_y, neg_y));
410 let length = (x*x + y*y).sqrt().max(1.0);
412 v(x/length, y/length)
413 }
414}