1use gilrs::{Event as GamepadEvent, EventType as GamepadEventType, Gilrs};
2#[cfg(not(target_arch = "wasm32"))]
3use glutin::event::{ElementState, MouseScrollDelta, TouchPhase, WindowEvent};
4use std::{
5 borrow::Cow,
6 cmp::Ordering,
7 collections::HashMap,
8 sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
9};
10#[cfg(target_arch = "wasm32")]
11use winit::event::{ElementState, MouseScrollDelta, TouchPhase, WindowEvent};
12
13pub use gilrs::{Axis as GamepadAxis, Button as GamepadButton, GamepadId};
14#[cfg(not(target_arch = "wasm32"))]
15pub use glutin::event::{MouseButton, VirtualKeyCode};
16#[cfg(target_arch = "wasm32")]
17pub use winit::event::{MouseButton, VirtualKeyCode};
18
19#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
20pub enum InputConsume {
21 #[default]
22 None,
23 Hit,
24 All,
25}
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
28pub enum VirtualAction {
29 KeyButton(VirtualKeyCode),
30 MouseButton(MouseButton),
31 Axis(u32),
32 GamepadButton(GamepadButton),
33 GamepadAxis(GamepadAxis),
34 Touch,
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
38pub enum VirtualAxis {
39 KeyButton(VirtualKeyCode),
40 MousePositionX,
41 MousePositionY,
42 MouseWheelX,
43 MouseWheelY,
44 MouseButton(MouseButton),
45 Axis(u32),
46 GamepadButton(GamepadButton),
47 GamepadAxis(GamepadAxis),
48 TouchX,
49 TouchY,
50}
51
52#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
53pub enum InputAction {
54 #[default]
55 Idle,
56 Pressed,
57 Hold,
58 Released,
59}
60
61impl InputAction {
62 pub fn change(self, hold: bool) -> Self {
63 match (self, hold) {
64 (Self::Idle, true) | (Self::Released, true) => Self::Pressed,
65 (Self::Pressed, false) | (Self::Hold, false) => Self::Released,
66 _ => self,
67 }
68 }
69
70 pub fn update(self) -> Self {
71 match self {
72 Self::Pressed => Self::Hold,
73 Self::Released => Self::Idle,
74 _ => self,
75 }
76 }
77
78 pub fn is_idle(self) -> bool {
79 matches!(self, Self::Idle)
80 }
81
82 pub fn is_pressed(self) -> bool {
83 matches!(self, Self::Pressed)
84 }
85
86 pub fn is_hold(self) -> bool {
87 matches!(self, Self::Hold)
88 }
89
90 pub fn is_released(self) -> bool {
91 matches!(self, Self::Released)
92 }
93
94 pub fn is_up(self) -> bool {
95 matches!(self, Self::Idle | Self::Released)
96 }
97
98 pub fn is_down(self) -> bool {
99 matches!(self, Self::Pressed | Self::Hold)
100 }
101
102 pub fn is_changing(self) -> bool {
103 matches!(self, Self::Pressed | Self::Released)
104 }
105
106 pub fn is_continuing(self) -> bool {
107 matches!(self, Self::Idle | Self::Hold)
108 }
109
110 pub fn to_scalar(self, falsy: f32, truthy: f32) -> f32 {
111 if self.is_down() { truthy } else { falsy }
112 }
113}
114
115#[derive(Debug, Default, Clone, Copy, PartialEq)]
116pub struct InputAxis(pub f32);
117
118impl InputAxis {
119 pub fn threshold(self, value: f32) -> bool {
120 self.0 >= value
121 }
122}
123
124#[derive(Debug, Default, Clone)]
125pub struct InputRef<T: Default>(Arc<RwLock<T>>);
126
127impl<T: Default> InputRef<T> {
128 pub fn new(data: T) -> Self {
129 Self(Arc::new(RwLock::new(data)))
130 }
131
132 pub fn read(&'_ self) -> Option<RwLockReadGuard<'_, T>> {
133 self.0.read().ok()
134 }
135
136 pub fn write(&'_ self) -> Option<RwLockWriteGuard<'_, T>> {
137 self.0.write().ok()
138 }
139
140 pub fn get(&self) -> T
141 where
142 T: Clone,
143 {
144 self.read().map(|value| value.clone()).unwrap_or_default()
145 }
146
147 pub fn set(&self, value: T) {
148 if let Some(mut data) = self.write() {
149 *data = value;
150 }
151 }
152
153 pub fn ptr_eq(&self, other: &Self) -> bool {
154 Arc::ptr_eq(&self.0, &other.0)
155 }
156}
157
158pub type InputActionRef = InputRef<InputAction>;
159pub type InputAxisRef = InputRef<InputAxis>;
160pub type InputCharactersRef = InputRef<InputCharacters>;
161pub type InputMappingRef = InputRef<InputMapping>;
162
163#[derive(Debug, Default, Clone)]
164pub enum InputActionOrAxisRef {
165 #[default]
166 None,
167 Action(InputActionRef),
168 Axis(InputAxisRef),
169}
170
171impl InputActionOrAxisRef {
172 pub fn is_none(&self) -> bool {
173 matches!(self, Self::None)
174 }
175
176 pub fn is_some(&self) -> bool {
177 !self.is_none()
178 }
179
180 pub fn get_scalar(&self, falsy: f32, truthy: f32) -> f32 {
181 match self {
182 Self::None => falsy,
183 Self::Action(action) => action.get().to_scalar(falsy, truthy),
184 Self::Axis(axis) => axis.get().0,
185 }
186 }
187
188 pub fn threshold(&self, value: f32) -> bool {
189 match self {
190 Self::None => false,
191 Self::Action(action) => action.get().is_down(),
192 Self::Axis(axis) => axis.get().threshold(value),
193 }
194 }
195}
196
197impl From<InputActionRef> for InputActionOrAxisRef {
198 fn from(value: InputActionRef) -> Self {
199 Self::Action(value)
200 }
201}
202
203impl From<InputAxisRef> for InputActionOrAxisRef {
204 fn from(value: InputAxisRef) -> Self {
205 Self::Axis(value)
206 }
207}
208
209pub struct InputCombinator<T> {
210 mapper: Box<dyn Fn() -> T + Send + Sync>,
211}
212
213impl<T: Default> Default for InputCombinator<T> {
214 fn default() -> Self {
215 Self::new(|| T::default())
216 }
217}
218
219impl<T> InputCombinator<T> {
220 pub fn new(mapper: impl Fn() -> T + Send + Sync + 'static) -> Self {
221 Self {
222 mapper: Box::new(mapper),
223 }
224 }
225
226 pub fn get(&self) -> T {
227 (self.mapper)()
228 }
229}
230
231#[derive(Default)]
232pub struct CardinalInputCombinator(pub InputCombinator<[f32; 2]>);
233
234impl CardinalInputCombinator {
235 pub fn new(
236 left: impl Into<InputActionOrAxisRef>,
237 right: impl Into<InputActionOrAxisRef>,
238 up: impl Into<InputActionOrAxisRef>,
239 down: impl Into<InputActionOrAxisRef>,
240 ) -> Self {
241 let left = left.into();
242 let right = right.into();
243 let up = up.into();
244 let down = down.into();
245 Self(InputCombinator::new(move || {
246 let left = left.get_scalar(0.0, -1.0);
247 let right = right.get_scalar(0.0, 1.0);
248 let up = up.get_scalar(0.0, -1.0);
249 let down = down.get_scalar(0.0, 1.0);
250 [left + right, up + down]
251 }))
252 }
253
254 pub fn get(&self) -> [f32; 2] {
255 self.0.get()
256 }
257}
258
259#[derive(Default)]
260pub struct DirectionInputCombinator(pub InputCombinator<[f32; 2]>);
261
262impl DirectionInputCombinator {
263 pub fn new(
264 left: InputActionRef,
265 right: InputActionRef,
266 up: InputActionRef,
267 down: InputActionRef,
268 horizontal: InputAxisRef,
269 vertical: InputAxisRef,
270 ) -> Self {
271 Self(InputCombinator::new(move || {
272 let left = left.get().to_scalar(0.0, -1.0);
273 let right = right.get().to_scalar(0.0, 1.0);
274 let up = up.get().to_scalar(0.0, -1.0);
275 let down = down.get().to_scalar(0.0, 1.0);
276 let horizontal = horizontal.get().0;
277 let vertical = vertical.get().0;
278 let x = left + right + horizontal;
279 let y = up + down + vertical;
280 let length = (x * x + y * y).sqrt();
281 if length > 1.0 {
282 [x / length, y / length]
283 } else {
284 [x, y]
285 }
286 }))
287 }
288
289 pub fn get(&self) -> [f32; 2] {
290 self.0.get()
291 }
292}
293
294#[derive(Default)]
295pub struct DualInputCombinator(pub InputCombinator<f32>);
296
297impl DualInputCombinator {
298 pub fn new(
299 negative: impl Into<InputActionOrAxisRef>,
300 positive: impl Into<InputActionOrAxisRef>,
301 ) -> Self {
302 let negative = negative.into();
303 let positive = positive.into();
304 Self(InputCombinator::new(move || {
305 let negative = negative.get_scalar(0.0, -1.0);
306 let positive = positive.get_scalar(0.0, 1.0);
307 negative + positive
308 }))
309 }
310
311 pub fn get(&self) -> f32 {
312 self.0.get()
313 }
314}
315
316pub struct ArrayInputCombinator<const N: usize>(pub InputCombinator<[f32; N]>);
317
318impl<const N: usize> Default for ArrayInputCombinator<N> {
319 fn default() -> Self {
320 Self(InputCombinator::new(|| [0.0; N]))
321 }
322}
323
324impl<const N: usize> ArrayInputCombinator<N> {
325 pub fn new(inputs: [impl Into<InputActionOrAxisRef>; N]) -> Self {
326 let items: [InputActionOrAxisRef; N] = inputs.map(|input| input.into());
327 Self(InputCombinator::new(move || {
328 std::array::from_fn(|index| items[index].get_scalar(0.0, 1.0))
329 }))
330 }
331
332 pub fn get(&self) -> [f32; N] {
333 self.0.get()
334 }
335}
336
337#[derive(Debug, Default, Clone)]
338pub struct InputCharacters {
339 characters: String,
340}
341
342impl InputCharacters {
343 pub fn read(&self) -> &str {
344 &self.characters
345 }
346
347 pub fn write(&mut self) -> &mut String {
348 &mut self.characters
349 }
350
351 pub fn take(&mut self) -> String {
352 std::mem::take(&mut self.characters)
353 }
354}
355
356#[derive(Default, Clone)]
357pub struct InputMapping {
358 pub actions: HashMap<VirtualAction, InputActionRef>,
359 pub axes: HashMap<VirtualAxis, InputAxisRef>,
360 pub consume: InputConsume,
361 pub layer: isize,
362 pub name: Cow<'static, str>,
363 pub gamepad: Option<GamepadId>,
364 pub validator: Option<Arc<dyn Fn() -> bool + Send + Sync>>,
365}
366
367impl InputMapping {
368 pub fn action(mut self, id: VirtualAction, action: InputActionRef) -> Self {
369 self.actions.insert(id, action);
370 self
371 }
372
373 pub fn axis(mut self, id: VirtualAxis, axis: InputAxisRef) -> Self {
374 self.axes.insert(id, axis);
375 self
376 }
377
378 pub fn consume(mut self, consume: InputConsume) -> Self {
379 self.consume = consume;
380 self
381 }
382
383 pub fn layer(mut self, value: isize) -> Self {
384 self.layer = value;
385 self
386 }
387
388 pub fn name(mut self, value: impl Into<Cow<'static, str>>) -> Self {
389 self.name = value.into();
390 self
391 }
392
393 pub fn gamepad(mut self, gamepad: GamepadId) -> Self {
394 self.gamepad = Some(gamepad);
395 self
396 }
397
398 pub fn validator(mut self, validator: impl Fn() -> bool + Send + Sync + 'static) -> Self {
399 self.validator = Some(Arc::new(validator));
400 self
401 }
402}
403
404impl From<InputMapping> for InputMappingRef {
405 fn from(value: InputMapping) -> Self {
406 Self::new(value)
407 }
408}
409
410impl std::fmt::Debug for InputMapping {
411 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
412 f.debug_struct("InputMapping")
413 .field("actions", &self.actions.keys().collect::<Vec<_>>())
414 .field("axes", &self.axes.keys().collect::<Vec<_>>())
415 .field("consume", &self.consume)
416 .field("layer", &self.layer)
417 .field("name", &self.name)
418 .field("gamepad", &self.gamepad)
419 .finish_non_exhaustive()
420 }
421}
422
423#[derive(Debug)]
424pub struct InputContext {
425 pub mouse_wheel_line_scale: f32,
426 pub touch_area_margin: [f64; 4],
428 mappings_stack: Vec<InputMappingRef>,
429 characters: InputCharactersRef,
430 gamepads: Option<Gilrs>,
431 active_touch: Option<u64>,
432 window_size: [f64; 2],
433}
434
435impl Default for InputContext {
436 fn default() -> Self {
437 Self {
438 mouse_wheel_line_scale: Self::default_mouse_wheel_line_scale(),
439 touch_area_margin: Self::default_touch_area_margin(),
440 mappings_stack: Default::default(),
441 characters: Default::default(),
442 gamepads: None,
443 active_touch: None,
444 window_size: Default::default(),
445 }
446 }
447}
448
449impl Clone for InputContext {
450 fn clone(&self) -> Self {
451 Self {
452 mouse_wheel_line_scale: self.mouse_wheel_line_scale,
453 touch_area_margin: self.touch_area_margin,
454 mappings_stack: self.mappings_stack.clone(),
455 characters: self.characters.clone(),
456 gamepads: None,
457 active_touch: self.active_touch,
458 window_size: self.window_size,
459 }
460 }
461}
462
463impl InputContext {
464 fn default_mouse_wheel_line_scale() -> f32 {
465 10.0
466 }
467
468 fn default_touch_area_margin() -> [f64; 4] {
469 [0.0, 0.0, 0.0, 0.0]
470 }
471
472 pub fn with_gamepads(mut self) -> Self {
473 self.gamepads = Gilrs::new().ok();
474 self
475 }
476
477 pub fn with_gamepads_custom(mut self, gamepads: Gilrs) -> Self {
478 self.gamepads = Some(gamepads);
479 self
480 }
481
482 pub fn gamepads(&self) -> Option<&Gilrs> {
483 self.gamepads.as_ref()
484 }
485
486 pub fn gamepads_mut(&mut self) -> Option<&mut Gilrs> {
487 self.gamepads.as_mut()
488 }
489
490 pub fn push_mapping(&mut self, mapping: impl Into<InputMappingRef>) -> InputMappingRef {
491 let mapping = mapping.into();
492 let layer = mapping.read().unwrap().layer;
493 let index = self
494 .mappings_stack
495 .binary_search_by(|mapping| {
496 mapping
497 .read()
498 .unwrap()
499 .layer
500 .cmp(&layer)
501 .then(Ordering::Less)
502 })
503 .unwrap_or_else(|index| index);
504 self.mappings_stack.insert(index, mapping.clone());
505 mapping
506 }
507
508 pub fn pop_mapping(&mut self) -> Option<InputMappingRef> {
509 self.mappings_stack.pop()
510 }
511
512 pub fn top_mapping(&self) -> Option<&InputMappingRef> {
513 self.mappings_stack.last()
514 }
515
516 pub fn remove_mapping(&mut self, mapping: &InputMappingRef) -> Option<InputMappingRef> {
517 self.mappings_stack
518 .iter()
519 .position(|m| mapping.ptr_eq(m))
520 .map(|index| self.mappings_stack.remove(index))
521 }
522
523 pub fn stack(&self) -> impl Iterator<Item = &InputMappingRef> {
524 self.mappings_stack.iter()
525 }
526
527 pub fn stack_mut(&mut self) -> impl Iterator<Item = &mut InputMappingRef> {
528 self.mappings_stack.iter_mut()
529 }
530
531 pub fn characters(&self) -> InputCharactersRef {
532 self.characters.clone()
533 }
534
535 pub fn maintain(&mut self) {
536 for mapping in &mut self.mappings_stack {
537 if let Some(mut mapping) = mapping.write() {
538 for action in mapping.actions.values_mut() {
539 if let Some(mut action) = action.write() {
540 *action = action.update();
541 }
542 }
543 for (id, axis) in &mut mapping.axes {
544 if let VirtualAxis::MouseWheelX | VirtualAxis::MouseWheelY = id
545 && let Some(mut axis) = axis.write()
546 {
547 axis.0 = 0.0;
548 }
549 }
550 }
551 }
552
553 let validity = self
554 .mappings_stack
555 .iter()
556 .filter(|mapping| {
557 mapping.read().is_some_and(|mapping| {
558 mapping
559 .validator
560 .as_ref()
561 .is_none_or(|validator| validator())
562 })
563 })
564 .cloned()
565 .collect::<Vec<_>>();
566
567 if let Some(gamepads) = self.gamepads.as_mut() {
568 while let Some(GamepadEvent { id, event, .. }) = gamepads.next_event() {
569 match event {
570 GamepadEventType::ButtonPressed(info, ..) => {
571 for mapping in self.mappings_stack.iter().rev() {
572 if !validity.iter().any(|m| m.ptr_eq(mapping)) {
573 continue;
574 }
575 if let Some(mapping) = mapping.read() {
576 if !mapping.gamepad.map(|gamepad| gamepad == id).unwrap_or(true) {
577 continue;
578 }
579 let mut consume = mapping.consume == InputConsume::All;
580 for (id, data) in &mapping.actions {
581 if let VirtualAction::GamepadButton(button) = id
582 && *button == info
583 && let Some(mut data) = data.write()
584 {
585 *data = data.change(true);
586 if mapping.consume == InputConsume::Hit {
587 consume = true;
588 }
589 }
590 }
591 for (id, data) in &mapping.axes {
592 if let VirtualAxis::GamepadButton(button) = id
593 && *button == info
594 && let Some(mut data) = data.write()
595 {
596 data.0 = 1.0;
597 if mapping.consume == InputConsume::Hit {
598 consume = true;
599 }
600 }
601 }
602 if consume {
603 break;
604 }
605 }
606 }
607 }
608 GamepadEventType::ButtonReleased(info, ..) => {
609 for mapping in self.mappings_stack.iter().rev() {
610 if !validity.iter().any(|m| m.ptr_eq(mapping)) {
611 continue;
612 }
613 if let Some(mapping) = mapping.read() {
614 if !mapping.gamepad.map(|gamepad| gamepad == id).unwrap_or(true) {
615 continue;
616 }
617 let mut consume = mapping.consume == InputConsume::All;
618 for (id, data) in &mapping.actions {
619 if let VirtualAction::GamepadButton(button) = id
620 && *button == info
621 && let Some(mut data) = data.write()
622 {
623 *data = data.change(false);
624 if mapping.consume == InputConsume::Hit {
625 consume = true;
626 }
627 }
628 }
629 for (id, data) in &mapping.axes {
630 if let VirtualAxis::GamepadButton(button) = id
631 && *button == info
632 && let Some(mut data) = data.write()
633 {
634 data.0 = 0.0;
635 if mapping.consume == InputConsume::Hit {
636 consume = true;
637 }
638 }
639 }
640 if consume {
641 break;
642 }
643 }
644 }
645 }
646 GamepadEventType::AxisChanged(info, value, ..) => {
647 for mapping in self.mappings_stack.iter().rev() {
648 if !validity.iter().any(|m| m.ptr_eq(mapping)) {
649 continue;
650 }
651 if let Some(mapping) = mapping.read() {
652 let mut consume = mapping.consume == InputConsume::All;
653 for (id, data) in &mapping.actions {
654 if let VirtualAction::GamepadAxis(axis) = id
655 && *axis == info
656 && let Some(mut data) = data.write()
657 {
658 *data = data.change(value > 0.5);
659 if mapping.consume == InputConsume::Hit {
660 consume = true;
661 }
662 }
663 }
664 for (id, data) in &mapping.axes {
665 if let VirtualAxis::GamepadAxis(axis) = id
666 && *axis == info
667 && let Some(mut data) = data.write()
668 {
669 data.0 = value;
670 if mapping.consume == InputConsume::Hit {
671 consume = true;
672 }
673 }
674 }
675 if consume {
676 break;
677 }
678 }
679 }
680 }
681 _ => {}
682 }
683 }
684 gamepads.inc();
685 }
686 }
687
688 pub fn on_event(&mut self, event: &WindowEvent) {
689 let validity = self
690 .mappings_stack
691 .iter()
692 .filter(|mapping| {
693 mapping.read().is_some_and(|mapping| {
694 mapping
695 .validator
696 .as_ref()
697 .is_none_or(|validator| validator())
698 })
699 })
700 .cloned()
701 .collect::<Vec<_>>();
702
703 match event {
704 WindowEvent::Resized(size) => {
705 self.window_size = [size.width as _, size.height as _];
706 }
707 WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
708 self.window_size = [new_inner_size.width as _, new_inner_size.height as _];
709 }
710 WindowEvent::ReceivedCharacter(character) => {
711 if let Some(mut characters) = self.characters.write() {
712 characters.characters.push(*character);
713 }
714 }
715 WindowEvent::KeyboardInput { input, .. } => {
716 if let Some(key) = input.virtual_keycode {
717 for mapping in self.mappings_stack.iter().rev() {
718 if !validity.iter().any(|m| m.ptr_eq(mapping)) {
719 continue;
720 }
721 if let Some(mapping) = mapping.read() {
722 let mut consume = mapping.consume == InputConsume::All;
723 for (id, data) in &mapping.actions {
724 if let VirtualAction::KeyButton(button) = id
725 && *button == key
726 && let Some(mut data) = data.write()
727 {
728 *data = data.change(input.state == ElementState::Pressed);
729 if mapping.consume == InputConsume::Hit {
730 consume = true;
731 }
732 }
733 }
734 for (id, data) in &mapping.axes {
735 if let VirtualAxis::KeyButton(button) = id
736 && *button == key
737 && let Some(mut data) = data.write()
738 {
739 data.0 = if input.state == ElementState::Pressed {
740 1.0
741 } else {
742 0.0
743 };
744 if mapping.consume == InputConsume::Hit {
745 consume = true;
746 }
747 }
748 }
749 if consume {
750 break;
751 }
752 }
753 }
754 }
755 }
756 WindowEvent::CursorMoved { position, .. } => {
757 for mapping in self.mappings_stack.iter().rev() {
758 if !validity.iter().any(|m| m.ptr_eq(mapping)) {
759 continue;
760 }
761 if let Some(mapping) = mapping.read() {
762 let mut consume = mapping.consume == InputConsume::All;
763 for (id, data) in &mapping.axes {
764 match id {
765 VirtualAxis::MousePositionX => {
766 if let Some(mut data) = data.write() {
767 data.0 = position.x as _;
768 if mapping.consume == InputConsume::Hit {
769 consume = true;
770 }
771 }
772 }
773 VirtualAxis::MousePositionY => {
774 if let Some(mut data) = data.write() {
775 data.0 = position.y as _;
776 if mapping.consume == InputConsume::Hit {
777 consume = true;
778 }
779 }
780 }
781 _ => {}
782 }
783 }
784 if consume {
785 break;
786 }
787 }
788 }
789 }
790 WindowEvent::MouseWheel { delta, .. } => {
791 for mapping in self.mappings_stack.iter().rev() {
792 if !validity.iter().any(|m| m.ptr_eq(mapping)) {
793 continue;
794 }
795 if let Some(mapping) = mapping.read() {
796 let mut consume = mapping.consume == InputConsume::All;
797 for (id, data) in &mapping.axes {
798 match id {
799 VirtualAxis::MouseWheelX => {
800 if let Some(mut data) = data.write() {
801 data.0 = match delta {
802 MouseScrollDelta::LineDelta(x, _) => *x,
803 MouseScrollDelta::PixelDelta(pos) => pos.x as _,
804 };
805 if mapping.consume == InputConsume::Hit {
806 consume = true;
807 }
808 }
809 }
810 VirtualAxis::MouseWheelY => {
811 if let Some(mut data) = data.write() {
812 data.0 = match delta {
813 MouseScrollDelta::LineDelta(_, y) => *y,
814 MouseScrollDelta::PixelDelta(pos) => pos.y as _,
815 };
816 if mapping.consume == InputConsume::Hit {
817 consume = true;
818 }
819 }
820 }
821 _ => {}
822 }
823 }
824 if consume {
825 break;
826 }
827 }
828 }
829 }
830 WindowEvent::MouseInput { state, button, .. } => {
831 for mapping in self.mappings_stack.iter().rev() {
832 if !validity.iter().any(|m| m.ptr_eq(mapping)) {
833 continue;
834 }
835 if let Some(mapping) = mapping.read() {
836 let mut consume = mapping.consume == InputConsume::All;
837 for (id, data) in &mapping.actions {
838 if let VirtualAction::MouseButton(btn) = id
839 && button == btn
840 && let Some(mut data) = data.write()
841 {
842 *data = data.change(*state == ElementState::Pressed);
843 if mapping.consume == InputConsume::Hit {
844 consume = true;
845 }
846 }
847 }
848 for (id, data) in &mapping.axes {
849 if let VirtualAxis::MouseButton(btn) = id
850 && button == btn
851 && let Some(mut data) = data.write()
852 {
853 data.0 = if *state == ElementState::Pressed {
854 1.0
855 } else {
856 0.0
857 };
858 if mapping.consume == InputConsume::Hit {
859 consume = true;
860 }
861 }
862 }
863 if consume {
864 break;
865 }
866 }
867 }
868 }
869 WindowEvent::AxisMotion { axis, value, .. } => {
870 for mapping in self.mappings_stack.iter().rev() {
871 if !validity.iter().any(|m| m.ptr_eq(mapping)) {
872 continue;
873 }
874 if let Some(mapping) = mapping.read() {
875 let mut consume = mapping.consume == InputConsume::All;
876 for (id, data) in &mapping.actions {
877 if let VirtualAction::Axis(index) = id
878 && axis == index
879 && let Some(mut data) = data.write()
880 {
881 *data = data.change(value.abs() > 0.5);
882 if mapping.consume == InputConsume::Hit {
883 consume = true;
884 }
885 }
886 }
887 for (id, data) in &mapping.axes {
888 if let VirtualAxis::Axis(index) = id
889 && axis == index
890 && let Some(mut data) = data.write()
891 {
892 data.0 = *value as _;
893 if mapping.consume == InputConsume::Hit {
894 consume = true;
895 }
896 }
897 }
898 if consume {
899 break;
900 }
901 }
902 }
903 }
904 WindowEvent::Touch(touch) => {
905 if matches!(touch.phase, TouchPhase::Started | TouchPhase::Moved)
906 && self.active_touch.is_none()
907 && touch.location.x >= self.touch_area_margin[0]
908 && touch.location.y >= self.touch_area_margin[1]
909 && touch.location.x < self.window_size[0] - self.touch_area_margin[2]
910 && touch.location.y < self.window_size[1] - self.touch_area_margin[3]
911 {
912 self.active_touch = Some(touch.id);
913 }
914 if let Some(active_touch) = self.active_touch
915 && touch.id == active_touch
916 {
917 for mapping in self.mappings_stack.iter().rev() {
918 if !validity.iter().any(|m| m.ptr_eq(mapping)) {
919 continue;
920 }
921 if let Some(mapping) = mapping.read() {
922 let mut consume = mapping.consume == InputConsume::All;
923 for (id, data) in &mapping.actions {
924 if let VirtualAction::Touch = id
925 && let Some(mut data) = data.write()
926 {
927 *data = data.change(matches!(
928 touch.phase,
929 TouchPhase::Started | TouchPhase::Moved
930 ));
931 if mapping.consume == InputConsume::Hit {
932 consume = true;
933 }
934 }
935 }
936 for (id, data) in &mapping.axes {
937 match id {
938 VirtualAxis::TouchX => {
939 if let Some(mut data) = data.write() {
940 data.0 = touch.location.x as _;
941 if mapping.consume == InputConsume::Hit {
942 consume = true;
943 }
944 }
945 }
946 VirtualAxis::TouchY => {
947 if let Some(mut data) = data.write() {
948 data.0 = touch.location.y as _;
949 if mapping.consume == InputConsume::Hit {
950 consume = true;
951 }
952 }
953 }
954 _ => {}
955 }
956 }
957 if consume {
958 break;
959 }
960 }
961 }
962 if matches!(touch.phase, TouchPhase::Ended | TouchPhase::Cancelled) {
963 self.active_touch = None;
964 }
965 }
966 }
967 _ => {}
968 }
969 }
970}
971
972#[derive(Default)]
973pub enum InputActionDetector {
974 #[default]
975 Listening,
976 Detected(VirtualAction),
977}
978
979impl InputActionDetector {
980 pub fn reset(&mut self) {
981 *self = Self::Listening;
982 }
983
984 pub fn try_consume(&mut self) -> Option<VirtualAction> {
985 if let Self::Detected(action) = self {
986 let action = *action;
987 *self = Self::Listening;
988 Some(action)
989 } else {
990 None
991 }
992 }
993
994 pub fn window_detect(&mut self, _context: &mut InputContext, event: &WindowEvent) {
995 if let Self::Listening = self {
996 match event {
997 WindowEvent::KeyboardInput { input, .. } => {
998 if let Some(action) = input.virtual_keycode.map(VirtualAction::KeyButton) {
999 *self = Self::Detected(action);
1000 }
1001 }
1002 WindowEvent::MouseInput { button, .. } => {
1003 *self = Self::Detected(VirtualAction::MouseButton(*button));
1004 }
1005 WindowEvent::AxisMotion { axis, .. } => {
1006 *self = Self::Detected(VirtualAction::Axis(*axis));
1007 }
1008 WindowEvent::Touch(_) => *self = Self::Detected(VirtualAction::Touch),
1009 _ => {}
1010 }
1011 }
1012 }
1013
1014 pub fn gamepad_detect(&mut self, context: &mut InputContext, gamepad_id: Option<GamepadId>) {
1015 if let Self::Listening = self
1016 && let Some(gamepads) = context.gamepads.as_mut()
1017 {
1018 while let Some(event) = gamepads.next_event() {
1019 if let Some(id) = gamepad_id
1020 && id != event.id
1021 {
1022 continue;
1023 }
1024 match event.event {
1025 GamepadEventType::ButtonPressed(info, ..) => {
1026 *self = Self::Detected(VirtualAction::GamepadButton(info));
1027 return;
1028 }
1029 GamepadEventType::AxisChanged(info, value, ..) if value.abs() > 0.5 => {
1030 *self = Self::Detected(VirtualAction::GamepadAxis(info));
1031 return;
1032 }
1033 _ => {}
1034 }
1035 }
1036 }
1037 }
1038}
1039
1040#[derive(Default)]
1041pub enum InputAxisDetector {
1042 #[default]
1043 Listening,
1044 TrackingMouse {
1045 x: f64,
1046 y: f64,
1047 },
1048 TrackingScroll {
1049 x: f64,
1050 y: f64,
1051 },
1052 TrackingTouch {
1053 x: f64,
1054 y: f64,
1055 },
1056 Detected(VirtualAxis),
1057}
1058
1059impl InputAxisDetector {
1060 pub fn reset(&mut self) {
1061 *self = Self::Listening;
1062 }
1063
1064 pub fn try_consume(&mut self) -> Option<VirtualAxis> {
1065 if let Self::Detected(axis) = self {
1066 let axis = *axis;
1067 *self = Self::Listening;
1068 Some(axis)
1069 } else {
1070 None
1071 }
1072 }
1073
1074 pub fn window_detect(&mut self, _context: &mut InputContext, event: &WindowEvent) {
1075 match self {
1076 Self::Listening => match event {
1077 WindowEvent::KeyboardInput { input, .. } => {
1078 if let Some(key) = input.virtual_keycode {
1079 *self = Self::Detected(VirtualAxis::KeyButton(key));
1080 }
1081 }
1082 WindowEvent::MouseInput { button, .. } => {
1083 *self = Self::Detected(VirtualAxis::MouseButton(*button));
1084 }
1085 WindowEvent::CursorMoved { position, .. } => {
1086 *self = Self::TrackingMouse {
1087 x: position.x,
1088 y: position.y,
1089 };
1090 }
1091 WindowEvent::MouseWheel { delta, .. } => match delta {
1092 MouseScrollDelta::LineDelta(x, y) => {
1093 if x.abs() > y.abs() {
1094 *self = Self::Detected(VirtualAxis::MouseWheelX);
1095 } else if y.abs() > 0.0 {
1096 *self = Self::Detected(VirtualAxis::MouseWheelY);
1097 }
1098 }
1099 MouseScrollDelta::PixelDelta(pos) => {
1100 *self = Self::TrackingScroll {
1101 x: pos.x as _,
1102 y: pos.y as _,
1103 };
1104 }
1105 },
1106 WindowEvent::AxisMotion { axis, .. } => {
1107 *self = Self::Detected(VirtualAxis::Axis(*axis));
1108 }
1109 WindowEvent::Touch(touch) => {
1110 *self = Self::TrackingTouch {
1111 x: touch.location.x,
1112 y: touch.location.y,
1113 };
1114 }
1115 _ => {}
1116 },
1117 Self::TrackingMouse { x, y } => {
1118 if let WindowEvent::CursorMoved { position, .. } = event {
1119 let delta_x = position.x - *x;
1120 let delta_y = position.y - *y;
1121 if delta_x.abs() > delta_y.abs() {
1122 *self = Self::Detected(VirtualAxis::MousePositionX);
1123 } else if delta_y.abs() > 0.0 {
1124 *self = Self::Detected(VirtualAxis::MousePositionY);
1125 }
1126 }
1127 }
1128 Self::TrackingScroll { x, y } => {
1129 if let WindowEvent::MouseWheel { delta, .. } = event
1130 && let MouseScrollDelta::PixelDelta(pos) = delta
1131 {
1132 let delta_x = pos.x - *x;
1133 let delta_y = pos.y - *y;
1134 if delta_x.abs() > delta_y.abs() {
1135 *self = Self::Detected(VirtualAxis::MouseWheelX);
1136 } else if delta_y.abs() > 0.0 {
1137 *self = Self::Detected(VirtualAxis::MouseWheelY);
1138 }
1139 }
1140 }
1141 Self::TrackingTouch { x, y } => {
1142 if let WindowEvent::Touch(touch) = event {
1143 let delta_x = touch.location.x - *x;
1144 let delta_y = touch.location.y - *y;
1145 if delta_x.abs() > delta_y.abs() {
1146 *self = Self::Detected(VirtualAxis::TouchX);
1147 } else if delta_y.abs() > 0.0 {
1148 *self = Self::Detected(VirtualAxis::TouchY);
1149 }
1150 }
1151 }
1152 _ => {}
1153 }
1154 }
1155
1156 pub fn gamepad_detect(&mut self, context: &mut InputContext, gamepad_id: Option<GamepadId>) {
1157 if let Some(gamepads) = context.gamepads.as_mut() {
1158 while let Some(event) = gamepads.next_event() {
1159 if let Some(id) = gamepad_id
1160 && id != event.id
1161 {
1162 continue;
1163 }
1164 match event.event {
1165 GamepadEventType::ButtonPressed(info, ..) => {
1166 *self = Self::Detected(VirtualAxis::GamepadButton(info));
1167 }
1168 GamepadEventType::AxisChanged(info, value, ..) if value.abs() > 0.5 => {
1169 *self = Self::Detected(VirtualAxis::GamepadAxis(info));
1170 }
1171 _ => {}
1172 }
1173 }
1174 }
1175 }
1176}
1177
1178#[cfg(test)]
1179mod tests {
1180 use super::*;
1181
1182 #[test]
1183 fn test_stack() {
1184 let mut context = InputContext::default();
1185 context.push_mapping(InputMapping::default().name("a").layer(0));
1186 context.push_mapping(InputMapping::default().name("b").layer(0));
1187 context.push_mapping(InputMapping::default().name("c").layer(0));
1188 context.push_mapping(InputMapping::default().name("d").layer(-1));
1189 context.push_mapping(InputMapping::default().name("e").layer(1));
1190 context.push_mapping(InputMapping::default().name("f").layer(-1));
1191 context.push_mapping(InputMapping::default().name("g").layer(1));
1192 context.push_mapping(InputMapping::default().name("h").layer(-2));
1193 context.push_mapping(InputMapping::default().name("i").layer(-2));
1194 context.push_mapping(InputMapping::default().name("j").layer(2));
1195 context.push_mapping(InputMapping::default().name("k").layer(2));
1196
1197 let provided = context
1198 .stack()
1199 .map(|mapping| {
1200 let mapping = mapping.read().unwrap();
1201 (mapping.name.as_ref().to_owned(), mapping.layer)
1202 })
1203 .collect::<Vec<_>>();
1204 assert_eq!(
1205 provided,
1206 vec![
1207 ("h".to_owned(), -2),
1208 ("i".to_owned(), -2),
1209 ("d".to_owned(), -1),
1210 ("f".to_owned(), -1),
1211 ("a".to_owned(), 0),
1212 ("b".to_owned(), 0),
1213 ("c".to_owned(), 0),
1214 ("e".to_owned(), 1),
1215 ("g".to_owned(), 1),
1216 ("j".to_owned(), 2),
1217 ("k".to_owned(), 2),
1218 ]
1219 );
1220 }
1221}