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}
19type ActionValue = (f32, bool, bool, Vec<(f32, Vec<f32>)>);
22type BindHash<F> = Vec<(F, usize, usize)>;
24pub type Binds<F> = Vec<(F, Vec<Vec<InputCode>>)>;
26pub struct InputMap<F: Hash + Copy> {
57 bind_hash: HashMap<InputCode, BindHash<F>>,
60 action_val: HashMap<F, ActionValue>,
62 #[cfg(all(feature = "mice-keyboard", feature = "gamepad"))]
64 focus: bool,
65 #[cfg(feature = "mice-keyboard")]
67 pub mouse_pos: Vec2,
68 pub recently_pressed: Option<InputCode>,
70 pub text_typed: Option<String>,
72 #[cfg(feature = "mice-keyboard")]
75 pub mouse_scale: f32,
76 #[cfg(feature = "mice-keyboard")]
79 pub scroll_scale: f32,
80 pub press_sensitivity: f32
83}
84impl InputMap<()> {
85 pub fn empty() -> Self { Self::default() }
87}
88impl<F: Hash + Copy> Default for InputMap<F> {
89 fn default() -> Self {
90 Self {
91 press_sensitivity: 0.5,
92 #[cfg(feature = "mice-keyboard")]
93 mouse_scale: 0.02,
94 #[cfg(feature = "mice-keyboard")]
95 scroll_scale: 1.0,
96 #[cfg(feature = "mice-keyboard")]
97 mouse_pos: v(0.0, 0.0),
98 recently_pressed: None,
99 text_typed: None,
100 bind_hash: HashMap::<InputCode, BindHash<F>>::new(),
101 action_val: HashMap::<F, ActionValue>::new(),
102 #[cfg(all(feature = "mice-keyboard", feature = "gamepad"))]
103 focus: true,
104 }
105 }
106}
107impl<F: Hash + Copy + Eq> InputMap<F> {
108 pub fn new(binds: &Binds<F>) -> Self {
134 let mut result = Self::default();
135 result.add_binds(binds);
136 result
137 }
138 pub fn add_binds(&mut self, binds: &Binds<F>) {
141 for (action, binds) in binds {
142 for (bind_i, bind) in binds.iter().enumerate() {
143 self.action_val.entry(*action).or_default().3.push((0.0, vec![]));
144 for (code_i, code) in bind.iter().enumerate() {
145 self.action_val.entry(*action).or_default().3[bind_i].1.push(0.0);
146 self.bind_hash.entry(*code).or_default().push((*action, bind_i, code_i));
147 }
148 }
149 }
150 self.action_val.shrink_to_fit();
151 self.bind_hash.shrink_to_fit();
152 }
153 pub fn set_binds(&mut self, binds: &Binds<F>) {
156 self.bind_hash.clear();
157 self.add_binds(binds);
158 }
159 pub fn get_binds(&self) -> Binds<F> {
162 let mut results = Vec::new();
163
164 for (input_code, binds) in self.bind_hash.iter() {
165 for (action, binds_i, bind_i) in binds.iter() {
166 let action_i = if let Some(result) = results.iter().position(|(a, _)| a == action) { result }
167 else { results.push((*action, vec![])); results.len() - 1 };
168
169 let len = results[action_i].1.len();
170 if *binds_i >= len { results[action_i].1.append(&mut vec![vec![]; binds_i - len + 1]); }
171
172 let vec = &mut results[action_i].1[*binds_i];
173
174 let len = vec.len();
175 if *bind_i >= len { vec.append(&mut vec![*input_code; bind_i - len + 1]); }
176 }
177 }
178 results
179 }
180 #[cfg(feature = "mice-keyboard")]
202 #[deprecated = "use `update_with_window_event` and `update_with_device_event`"]
203 pub fn update_with_winit(&mut self, event: &Event<()>) {
204 match event {
205 Event::WindowEvent { event, .. } => self.update_with_window_event(event),
206 Event::DeviceEvent { event, device_id, .. } => self.update_with_device_event(*device_id, event),
207 _ => ()
208 }
209 }
210 #[cfg(feature = "mice-keyboard")]
211 pub fn update_with_device_event(&mut self, id: DeviceId, event: &DeviceEvent) {
212 use base_input_codes::*;
213 match event {
214 DeviceEvent::MouseMotion { delta } => {
215 let x = delta.0 as f32 * self.mouse_scale;
216 let y = delta.1 as f32 * self.mouse_scale;
217 self.modify_val(MouseMoveRight.with_id(id), |v| v + x.max(0.0));
218 self.modify_val(MouseMoveLeft .with_id(id), |v| v - x.min(0.0));
219 self.modify_val(MouseMoveDown .with_id(id), |v| v + y.max(0.0));
220 self.modify_val(MouseMoveUp .with_id(id), |v| v - y.min(0.0));
221 },
222 DeviceEvent::MouseWheel { delta } => self.update_scroll(*delta, id),
223 _ => (),
224 }
225 }
226 #[cfg(feature = "mice-keyboard")]
227 pub fn update_with_window_event(&mut self, event: &WindowEvent) {
228 match event {
229 WindowEvent::CursorMoved { position, .. } => self.update_mouse(*position),
230 WindowEvent::MouseWheel { delta, device_id, .. } => self.update_scroll(*delta, *device_id),
231 WindowEvent::MouseInput { state, button, device_id } => self.update_buttons(state, *device_id, *button),
232 WindowEvent::KeyboardInput { event, device_id, .. } => self.update_keys(*device_id, event),
233 WindowEvent::Focused(false) => {
234 for val in self.action_val.values_mut() {
235 val.3.iter_mut().for_each(|i| { i.0 = 0.0; i.1.iter_mut().for_each(|i| *i = 0.0) });
236 val.0 = 0.0;
237 }
238 #[cfg(feature = "gamepad")] { self.focus = false; }
239 },
240 #[cfg(feature = "gamepad")]
241 WindowEvent::Focused(true) => self.focus = true,
242 _ => ()
243 }
244 }
245 #[cfg(feature = "gamepad")]
246 pub fn update_with_gilrs(&mut self, gilrs: &mut gilrs::Gilrs) {
247 while let Some(ev) = gilrs.next_event() {
248 if self.focus { self.update_gamepad(ev); }
249 }
250 }
251 pub fn init(&mut self) {
253 #[cfg(feature = "mice-keyboard")]
254 {
255 use base_input_codes::*;
256 for i in [MouseMoveLeft, MouseMoveRight,
257 MouseMoveUp, MouseMoveDown, MouseScrollUp,
258 MouseScrollDown, MouseScrollLeft,
259 MouseScrollRight] {
260 self.update_val(i.into(), 0.0);
261 }
262 }
263 self.action_val.values_mut().for_each(|(_, p, r, _)| (*p, *r) = (false, false));
264 self.recently_pressed = None;
265 self.text_typed = None;
266 }
267 #[cfg(feature = "mice-keyboard")]
268 fn update_scroll(&mut self, delta: MouseScrollDelta, id: DeviceId) {
269 use base_input_codes::*;
270 let (x, y) = match delta {
271 MouseScrollDelta::LineDelta(x, y) => (x, y),
272 MouseScrollDelta::PixelDelta(PhysicalPosition { x, y }) => (x as f32, y as f32)
273 };
274 let (x, y) = (x * self.scroll_scale, y * self.scroll_scale);
275
276 self.modify_val(MouseScrollUp.with_id(id), |v| v + y.max(0.0));
277 self.modify_val(MouseScrollDown.with_id(id), |v| v - y.min(0.0));
278 self.modify_val(MouseScrollLeft.with_id(id), |v| v + x.max(0.0));
279 self.modify_val(MouseScrollRight.with_id(id), |v| v - x.min(0.0));
280 }
281 #[cfg(feature = "mice-keyboard")]
282 fn update_mouse(&mut self, position: PhysicalPosition<f64>) {
283 self.mouse_pos = v(position.x as f32, position.y as f32);
284 }
285 #[cfg(feature = "mice-keyboard")]
286 fn update_keys(&mut self, id: DeviceId, event: &KeyEvent) {
287 let input_code: DeviceInput = event.physical_key.into();
288
289 if let (Some(string), Some(new)) = (&mut self.text_typed, &event.text) {
290 string.push_str(new);
291 } else { self.text_typed = event.text.as_ref().map(|i| i.to_string()) }
292
293 self.update_val(input_code.with_id(id), event.state.is_pressed().into());
294 }
295 #[cfg(feature = "mice-keyboard")]
296 fn update_buttons(&mut self, state: &ElementState, id: DeviceId, button: MouseButton) {
297 let input_code: DeviceInput = button.into();
298 self.update_val(input_code.with_id(id), state.is_pressed().into());
299 }
300 fn update_val(&mut self, input_code: InputCode, val: f32) {
302 self.modify_val(input_code, |_| val);
303 }
304 fn modify_val<FN: Fn(f32) -> f32>(&mut self, input_code: InputCode, f: FN) {
305 self.modify_single_val(input_code, &f);
306 self.modify_single_val(input_code.set_any(), f);
307 }
308 fn modify_single_val<FN: Fn(f32) -> f32>(&mut self, input_code: InputCode, f: FN) {
310 let Some(binds) = self.bind_hash.get(&input_code) else {
311 if f(0.0) >= self.press_sensitivity && !input_code.is_any() { self.recently_pressed = Some(input_code) }
312 return;
313 };
314
315 for &(action, index, sub_index) in binds {
316 let (curr_val, pressing, releasing, sub_values) = &mut self.action_val.get_mut(&action).unwrap();
317
318 let old_sub_sub_val = sub_values[index].1[sub_index];
319 let new_sub_sub_val = f(old_sub_sub_val);
320 let change = new_sub_sub_val / old_sub_sub_val;
321 sub_values[index].1[sub_index] = new_sub_sub_val;
322
323 let sub_value = sub_values[index].0;
324 let new_sub_val = if change.is_finite() { sub_value * change }
325 else { sub_values[index].1.iter().fold(1.0, |a, b| a * b) };
326 sub_values[index].0 = new_sub_val;
327
328 *curr_val += new_sub_val - sub_value;
329
330 let now_pressing = *curr_val >= self.press_sensitivity;
331 if now_pressing && !input_code.is_any() { self.recently_pressed = Some(input_code) }
332
333 let jpressed = now_pressing && !*pressing;
334 let released = !now_pressing && *pressing;
335 *pressing = jpressed;
336 *releasing = released;
337 }
338 }
339 #[cfg(feature = "gamepad")]
340 fn update_gamepad(&mut self, event: gilrs::Event) {
341 let gilrs::Event { id, event, .. } = event;
342 use crate::input_code::{axis_pos, axis_neg};
343 use gilrs::ev::EventType;
344 match event {
345 EventType::ButtonChanged(b, v, _) => {
346 let a: GamepadInput = b.into();
347 self.update_val(a.with_id(id), v);
348 },
349 EventType::AxisChanged(b, v, _) => {
350 let dir_pos = v.max(0.0);
351 let dir_neg = (-v).max(0.0);
352 let input_pos = axis_pos(b);
353 let input_neg = axis_neg(b);
354
355 self.update_val(input_pos.with_id(id), dir_pos);
356 self.update_val(input_neg.with_id(id), dir_neg);
357 },
358 EventType::Disconnected => {
359 use GamepadInput::*;
362 for i in [LeftStickLeft, LeftStickRight, LeftStickUp, LeftStickDown, LeftStickPress,
363 RightStickLeft, RightStickRight, RightStickUp, RightStickDown,
364 RightStickPress, DPadLeft, DPadRight, DPadUp, DPadDown, LeftZ, RightZ,
365 South, East, North, West, LeftBumper, LeftTrigger, RightBumper,
366 RightTrigger, Select, Start, Mode, Other].iter() {
367 self.update_val(i.with_id(id), 0.0);
368 }
369 }
370 _ => ()
371 }
372 }
373 pub fn pressing(&self, action: F) -> bool {
376 self.value(action) >= self.press_sensitivity
377 }
378 pub fn value(&self, action: F) -> f32 {
381 if let Some(&(v, _, _, _)) = self.action_val.get(&action) { v } else { 0.0 }
382 }
383 pub fn pressed(&self, action: F) -> bool {
385 if let Some(&(_, v, _, _)) = self.action_val.get(&action) { v } else { false }
386 }
387 pub fn released(&self, action: F) -> bool {
389 if let Some(&(_, _, v, _)) = self.action_val.get(&action) { v } else { false }
390 }
391 pub fn axis(&self, pos: F, neg: F) -> f32 {
399 self.value(pos) - self.value(neg)
400 }
401 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}
415