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};
10use typid::ID;
11#[cfg(target_arch = "wasm32")]
12use winit::event::{ElementState, MouseScrollDelta, TouchPhase, WindowEvent};
13
14pub use gilrs::{Axis as GamepadAxis, Button as GamepadButton, GamepadId};
15#[cfg(not(target_arch = "wasm32"))]
16pub use glutin::event::{MouseButton, VirtualKeyCode};
17#[cfg(target_arch = "wasm32")]
18pub use winit::event::{MouseButton, VirtualKeyCode};
19
20#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
21pub enum InputConsume {
22 #[default]
23 None,
24 Hit,
25 All,
26}
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
29pub enum VirtualAction {
30 KeyButton(VirtualKeyCode),
31 MouseButton(MouseButton),
32 Axis(u32),
33 GamepadButton(GamepadButton),
34 GamepadAxis(GamepadAxis),
35 Touch,
36}
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
39pub enum VirtualAxis {
40 KeyButton(VirtualKeyCode),
41 MousePositionX,
42 MousePositionY,
43 MouseWheelX,
44 MouseWheelY,
45 MouseButton(MouseButton),
46 Axis(u32),
47 GamepadButton(GamepadButton),
48 GamepadAxis(GamepadAxis),
49 TouchX,
50 TouchY,
51}
52
53#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
54pub enum InputAction {
55 #[default]
56 Idle,
57 Pressed,
58 Hold,
59 Released,
60}
61
62impl InputAction {
63 pub fn change(self, hold: bool) -> Self {
64 match (self, hold) {
65 (Self::Idle, true) | (Self::Released, true) => Self::Pressed,
66 (Self::Pressed, false) | (Self::Hold, false) => Self::Released,
67 _ => self,
68 }
69 }
70
71 pub fn update(self) -> Self {
72 match self {
73 Self::Pressed => Self::Hold,
74 Self::Released => Self::Idle,
75 _ => self,
76 }
77 }
78
79 pub fn is_idle(self) -> bool {
80 matches!(self, Self::Idle)
81 }
82
83 pub fn is_pressed(self) -> bool {
84 matches!(self, Self::Pressed)
85 }
86
87 pub fn is_hold(self) -> bool {
88 matches!(self, Self::Hold)
89 }
90
91 pub fn is_released(self) -> bool {
92 matches!(self, Self::Released)
93 }
94
95 pub fn is_up(self) -> bool {
96 matches!(self, Self::Idle | Self::Released)
97 }
98
99 pub fn is_down(self) -> bool {
100 matches!(self, Self::Pressed | Self::Hold)
101 }
102
103 pub fn is_changing(self) -> bool {
104 matches!(self, Self::Pressed | Self::Released)
105 }
106
107 pub fn is_continuing(self) -> bool {
108 matches!(self, Self::Idle | Self::Hold)
109 }
110
111 pub fn to_scalar(self, falsy: f32, truthy: f32) -> f32 {
112 if self.is_down() { truthy } else { falsy }
113 }
114}
115
116#[derive(Debug, Default, Clone, Copy, PartialEq)]
117pub struct InputAxis(pub f32);
118
119impl InputAxis {
120 pub fn threshold(self, value: f32) -> bool {
121 self.0 >= value
122 }
123}
124
125#[derive(Debug, Default, Clone)]
126pub struct InputRef<T: Default>(Arc<RwLock<T>>);
127
128impl<T: Default> InputRef<T> {
129 pub fn new(data: T) -> Self {
130 Self(Arc::new(RwLock::new(data)))
131 }
132
133 pub fn read(&'_ self) -> Option<RwLockReadGuard<'_, T>> {
134 self.0.read().ok()
135 }
136
137 pub fn write(&'_ self) -> Option<RwLockWriteGuard<'_, T>> {
138 self.0.write().ok()
139 }
140
141 pub fn get(&self) -> T
142 where
143 T: Clone,
144 {
145 self.read().map(|value| value.clone()).unwrap_or_default()
146 }
147
148 pub fn set(&self, value: T) {
149 if let Some(mut data) = self.write() {
150 *data = value;
151 }
152 }
153}
154
155pub type InputActionRef = InputRef<InputAction>;
156pub type InputAxisRef = InputRef<InputAxis>;
157pub type InputCharactersRef = InputRef<InputCharacters>;
158pub type InputMappingRef = InputRef<InputMapping>;
159
160#[derive(Debug, Default, Clone)]
161pub enum InputActionOrAxisRef {
162 #[default]
163 None,
164 Action(InputActionRef),
165 Axis(InputAxisRef),
166}
167
168impl InputActionOrAxisRef {
169 pub fn is_none(&self) -> bool {
170 matches!(self, Self::None)
171 }
172
173 pub fn is_some(&self) -> bool {
174 !self.is_none()
175 }
176
177 pub fn get_scalar(&self, falsy: f32, truthy: f32) -> f32 {
178 match self {
179 Self::None => falsy,
180 Self::Action(action) => action.get().to_scalar(falsy, truthy),
181 Self::Axis(axis) => axis.get().0,
182 }
183 }
184
185 pub fn threshold(&self, value: f32) -> bool {
186 match self {
187 Self::None => false,
188 Self::Action(action) => action.get().is_down(),
189 Self::Axis(axis) => axis.get().threshold(value),
190 }
191 }
192}
193
194impl From<InputActionRef> for InputActionOrAxisRef {
195 fn from(value: InputActionRef) -> Self {
196 Self::Action(value)
197 }
198}
199
200impl From<InputAxisRef> for InputActionOrAxisRef {
201 fn from(value: InputAxisRef) -> Self {
202 Self::Axis(value)
203 }
204}
205
206pub struct InputCombinator<T> {
207 mapper: Box<dyn Fn() -> T + Send + Sync>,
208}
209
210impl<T: Default> Default for InputCombinator<T> {
211 fn default() -> Self {
212 Self::new(|| T::default())
213 }
214}
215
216impl<T> InputCombinator<T> {
217 pub fn new(mapper: impl Fn() -> T + Send + Sync + 'static) -> Self {
218 Self {
219 mapper: Box::new(mapper),
220 }
221 }
222
223 pub fn get(&self) -> T {
224 (self.mapper)()
225 }
226}
227
228#[derive(Default)]
229pub struct CardinalInputCombinator(InputCombinator<[f32; 2]>);
230
231impl CardinalInputCombinator {
232 pub fn new(
233 left: impl Into<InputActionOrAxisRef>,
234 right: impl Into<InputActionOrAxisRef>,
235 up: impl Into<InputActionOrAxisRef>,
236 down: impl Into<InputActionOrAxisRef>,
237 ) -> Self {
238 let left = left.into();
239 let right = right.into();
240 let up = up.into();
241 let down = down.into();
242 Self(InputCombinator::new(move || {
243 let left = left.get_scalar(0.0, -1.0);
244 let right = right.get_scalar(0.0, 1.0);
245 let up = up.get_scalar(0.0, -1.0);
246 let down = down.get_scalar(0.0, 1.0);
247 [left + right, up + down]
248 }))
249 }
250
251 pub fn get(&self) -> [f32; 2] {
252 self.0.get()
253 }
254}
255
256#[derive(Default)]
257pub struct DualInputCombinator(InputCombinator<f32>);
258
259impl DualInputCombinator {
260 pub fn new(
261 negative: impl Into<InputActionOrAxisRef>,
262 positive: impl Into<InputActionOrAxisRef>,
263 ) -> Self {
264 let negative = negative.into();
265 let positive = positive.into();
266 Self(InputCombinator::new(move || {
267 let negative = negative.get_scalar(0.0, -1.0);
268 let positive = positive.get_scalar(0.0, 1.0);
269 negative + positive
270 }))
271 }
272
273 pub fn get(&self) -> f32 {
274 self.0.get()
275 }
276}
277
278pub struct ArrayInputCombinator<const N: usize>(InputCombinator<[f32; N]>);
279
280impl<const N: usize> Default for ArrayInputCombinator<N> {
281 fn default() -> Self {
282 Self(InputCombinator::new(|| [0.0; N]))
283 }
284}
285
286impl<const N: usize> ArrayInputCombinator<N> {
287 pub fn new(inputs: [impl Into<InputActionOrAxisRef>; N]) -> Self {
288 let items: [InputActionOrAxisRef; N] = inputs.map(|input| input.into());
289 Self(InputCombinator::new(move || {
290 std::array::from_fn(|index| items[index].get_scalar(0.0, 1.0))
291 }))
292 }
293
294 pub fn get(&self) -> [f32; N] {
295 self.0.get()
296 }
297}
298
299#[derive(Debug, Default, Clone)]
300pub struct InputCharacters {
301 characters: String,
302}
303
304impl InputCharacters {
305 pub fn read(&self) -> &str {
306 &self.characters
307 }
308
309 pub fn write(&mut self) -> &mut String {
310 &mut self.characters
311 }
312
313 pub fn take(&mut self) -> String {
314 std::mem::take(&mut self.characters)
315 }
316}
317
318#[derive(Debug, Default, Clone)]
319pub struct InputMapping {
320 pub actions: HashMap<VirtualAction, InputActionRef>,
321 pub axes: HashMap<VirtualAxis, InputAxisRef>,
322 pub consume: InputConsume,
323 pub layer: isize,
324 pub name: Cow<'static, str>,
325 pub gamepad: Option<GamepadId>,
326}
327
328impl InputMapping {
329 pub fn action(mut self, id: VirtualAction, action: InputActionRef) -> Self {
330 self.actions.insert(id, action);
331 self
332 }
333
334 pub fn axis(mut self, id: VirtualAxis, axis: InputAxisRef) -> Self {
335 self.axes.insert(id, axis);
336 self
337 }
338
339 pub fn consume(mut self, consume: InputConsume) -> Self {
340 self.consume = consume;
341 self
342 }
343
344 pub fn layer(mut self, value: isize) -> Self {
345 self.layer = value;
346 self
347 }
348
349 pub fn name(mut self, value: impl Into<Cow<'static, str>>) -> Self {
350 self.name = value.into();
351 self
352 }
353
354 pub fn gamepad(mut self, gamepad: GamepadId) -> Self {
355 self.gamepad = Some(gamepad);
356 self
357 }
358}
359
360impl From<InputMapping> for InputMappingRef {
361 fn from(value: InputMapping) -> Self {
362 Self::new(value)
363 }
364}
365
366#[derive(Debug)]
367pub struct InputContext {
368 pub mouse_wheel_line_scale: f32,
369 pub touch_area_margin: [f64; 4],
371 mappings_stack: Vec<(ID<InputMapping>, InputMappingRef)>,
373 characters: InputCharactersRef,
374 gamepads: Option<Gilrs>,
375 active_touch: Option<u64>,
376 window_size: [f64; 2],
377}
378
379impl Default for InputContext {
380 fn default() -> Self {
381 Self {
382 mouse_wheel_line_scale: Self::default_mouse_wheel_line_scale(),
383 touch_area_margin: Self::default_touch_area_margin(),
384 mappings_stack: Default::default(),
385 characters: Default::default(),
386 gamepads: None,
387 active_touch: None,
388 window_size: Default::default(),
389 }
390 }
391}
392
393impl Clone for InputContext {
394 fn clone(&self) -> Self {
395 Self {
396 mouse_wheel_line_scale: self.mouse_wheel_line_scale,
397 touch_area_margin: self.touch_area_margin,
398 mappings_stack: self.mappings_stack.clone(),
399 characters: self.characters.clone(),
400 gamepads: None,
401 active_touch: self.active_touch,
402 window_size: self.window_size,
403 }
404 }
405}
406
407impl InputContext {
408 fn default_mouse_wheel_line_scale() -> f32 {
409 10.0
410 }
411
412 fn default_touch_area_margin() -> [f64; 4] {
413 [0.0, 0.0, 0.0, 0.0]
414 }
415
416 pub fn with_gamepads(mut self) -> Self {
417 self.gamepads = Gilrs::new().ok();
418 self
419 }
420
421 pub fn with_gamepads_custom(mut self, gamepads: Gilrs) -> Self {
422 self.gamepads = Some(gamepads);
423 self
424 }
425
426 pub fn gamepads(&self) -> Option<&Gilrs> {
427 self.gamepads.as_ref()
428 }
429
430 pub fn gamepads_mut(&mut self) -> Option<&mut Gilrs> {
431 self.gamepads.as_mut()
432 }
433
434 pub fn push_mapping(&mut self, mapping: impl Into<InputMappingRef>) -> ID<InputMapping> {
435 let mapping = mapping.into();
436 let id = ID::default();
437 let layer = mapping.read().unwrap().layer;
438 let index = self
439 .mappings_stack
440 .binary_search_by(|(_, mapping)| {
441 mapping
442 .read()
443 .unwrap()
444 .layer
445 .cmp(&layer)
446 .then(Ordering::Less)
447 })
448 .unwrap_or_else(|index| index);
449 self.mappings_stack.insert(index, (id, mapping));
450 id
451 }
452
453 pub fn pop_mapping(&mut self) -> Option<InputMappingRef> {
454 self.mappings_stack.pop().map(|(_, mapping)| mapping)
455 }
456
457 pub fn top_mapping(&self) -> Option<&InputMappingRef> {
458 self.mappings_stack.last().map(|(_, mapping)| mapping)
459 }
460
461 pub fn remove_mapping(&mut self, id: ID<InputMapping>) -> Option<InputMappingRef> {
462 self.mappings_stack
463 .iter()
464 .position(|(mid, _)| mid == &id)
465 .map(|index| self.mappings_stack.remove(index).1)
466 }
467
468 pub fn mapping(&'_ self, id: ID<InputMapping>) -> Option<RwLockReadGuard<'_, InputMapping>> {
469 self.mappings_stack
470 .iter()
471 .find(|(mid, _)| mid == &id)
472 .and_then(|(_, mapping)| mapping.read())
473 }
474
475 pub fn stack(&self) -> impl Iterator<Item = &InputMappingRef> {
476 self.mappings_stack.iter().map(|(_, mapping)| mapping)
477 }
478
479 pub fn characters(&self) -> InputCharactersRef {
480 self.characters.clone()
481 }
482
483 pub fn maintain(&mut self) {
484 for (_, mapping) in &mut self.mappings_stack {
485 if let Some(mut mapping) = mapping.write() {
486 for action in mapping.actions.values_mut() {
487 if let Some(mut action) = action.write() {
488 *action = action.update();
489 }
490 }
491 for (id, axis) in &mut mapping.axes {
492 if let VirtualAxis::MouseWheelX | VirtualAxis::MouseWheelY = id
493 && let Some(mut axis) = axis.write()
494 {
495 axis.0 = 0.0;
496 }
497 }
498 }
499 }
500
501 if let Some(gamepads) = self.gamepads.as_mut() {
502 while let Some(GamepadEvent { id, event, .. }) = gamepads.next_event() {
503 match event {
504 GamepadEventType::ButtonPressed(info, ..) => {
505 for (_, mapping) in self.mappings_stack.iter().rev() {
506 if let Some(mapping) = mapping.read() {
507 if !mapping.gamepad.map(|gamepad| gamepad == id).unwrap_or(true) {
508 continue;
509 }
510 let mut consume = mapping.consume == InputConsume::All;
511 for (id, data) in &mapping.actions {
512 if let VirtualAction::GamepadButton(button) = id
513 && *button == info
514 && let Some(mut data) = data.write()
515 {
516 *data = data.change(true);
517 if mapping.consume == InputConsume::Hit {
518 consume = true;
519 }
520 }
521 }
522 for (id, data) in &mapping.axes {
523 if let VirtualAxis::GamepadButton(button) = id
524 && *button == info
525 && let Some(mut data) = data.write()
526 {
527 data.0 = 1.0;
528 if mapping.consume == InputConsume::Hit {
529 consume = true;
530 }
531 }
532 }
533 if consume {
534 break;
535 }
536 }
537 }
538 }
539 GamepadEventType::ButtonReleased(info, ..) => {
540 for (_, mapping) in self.mappings_stack.iter().rev() {
541 if let Some(mapping) = mapping.read() {
542 if !mapping.gamepad.map(|gamepad| gamepad == id).unwrap_or(true) {
543 continue;
544 }
545 let mut consume = mapping.consume == InputConsume::All;
546 for (id, data) in &mapping.actions {
547 if let VirtualAction::GamepadButton(button) = id
548 && *button == info
549 && let Some(mut data) = data.write()
550 {
551 *data = data.change(false);
552 if mapping.consume == InputConsume::Hit {
553 consume = true;
554 }
555 }
556 }
557 for (id, data) in &mapping.axes {
558 if let VirtualAxis::GamepadButton(button) = id
559 && *button == info
560 && let Some(mut data) = data.write()
561 {
562 data.0 = 0.0;
563 if mapping.consume == InputConsume::Hit {
564 consume = true;
565 }
566 }
567 }
568 if consume {
569 break;
570 }
571 }
572 }
573 }
574 GamepadEventType::AxisChanged(info, value, ..) => {
575 for (_, mapping) in self.mappings_stack.iter().rev() {
576 if let Some(mapping) = mapping.read() {
577 let mut consume = mapping.consume == InputConsume::All;
578 for (id, data) in &mapping.actions {
579 if let VirtualAction::GamepadAxis(axis) = id
580 && *axis == info
581 && let Some(mut data) = data.write()
582 {
583 *data = data.change(value > 0.5);
584 if mapping.consume == InputConsume::Hit {
585 consume = true;
586 }
587 }
588 }
589 for (id, data) in &mapping.axes {
590 if let VirtualAxis::GamepadAxis(axis) = id
591 && *axis == info
592 && let Some(mut data) = data.write()
593 {
594 data.0 = value;
595 if mapping.consume == InputConsume::Hit {
596 consume = true;
597 }
598 }
599 }
600 if consume {
601 break;
602 }
603 }
604 }
605 }
606 _ => {}
607 }
608 }
609 gamepads.inc();
610 }
611 }
612
613 pub fn on_event(&mut self, event: &WindowEvent) {
614 match event {
615 WindowEvent::Resized(size) => {
616 self.window_size = [size.width as _, size.height as _];
617 }
618 WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
619 self.window_size = [new_inner_size.width as _, new_inner_size.height as _];
620 }
621 WindowEvent::ReceivedCharacter(character) => {
622 if let Some(mut characters) = self.characters.write() {
623 characters.characters.push(*character);
624 }
625 }
626 WindowEvent::KeyboardInput { input, .. } => {
627 if let Some(key) = input.virtual_keycode {
628 for (_, mapping) in self.mappings_stack.iter().rev() {
629 if let Some(mapping) = mapping.read() {
630 let mut consume = mapping.consume == InputConsume::All;
631 for (id, data) in &mapping.actions {
632 if let VirtualAction::KeyButton(button) = id
633 && *button == key
634 && let Some(mut data) = data.write()
635 {
636 *data = data.change(input.state == ElementState::Pressed);
637 if mapping.consume == InputConsume::Hit {
638 consume = true;
639 }
640 }
641 }
642 for (id, data) in &mapping.axes {
643 if let VirtualAxis::KeyButton(button) = id
644 && *button == key
645 && let Some(mut data) = data.write()
646 {
647 data.0 = if input.state == ElementState::Pressed {
648 1.0
649 } else {
650 0.0
651 };
652 if mapping.consume == InputConsume::Hit {
653 consume = true;
654 }
655 }
656 }
657 if consume {
658 break;
659 }
660 }
661 }
662 }
663 }
664 WindowEvent::CursorMoved { position, .. } => {
665 for (_, mapping) in self.mappings_stack.iter().rev() {
666 if let Some(mapping) = mapping.read() {
667 let mut consume = mapping.consume == InputConsume::All;
668 for (id, data) in &mapping.axes {
669 match id {
670 VirtualAxis::MousePositionX => {
671 if let Some(mut data) = data.write() {
672 data.0 = position.x as _;
673 if mapping.consume == InputConsume::Hit {
674 consume = true;
675 }
676 }
677 }
678 VirtualAxis::MousePositionY => {
679 if let Some(mut data) = data.write() {
680 data.0 = position.y as _;
681 if mapping.consume == InputConsume::Hit {
682 consume = true;
683 }
684 }
685 }
686 _ => {}
687 }
688 }
689 if consume {
690 break;
691 }
692 }
693 }
694 }
695 WindowEvent::MouseWheel { delta, .. } => {
696 for (_, mapping) in self.mappings_stack.iter().rev() {
697 if let Some(mapping) = mapping.read() {
698 let mut consume = mapping.consume == InputConsume::All;
699 for (id, data) in &mapping.axes {
700 match id {
701 VirtualAxis::MouseWheelX => {
702 if let Some(mut data) = data.write() {
703 data.0 = match delta {
704 MouseScrollDelta::LineDelta(x, _) => *x,
705 MouseScrollDelta::PixelDelta(pos) => pos.x as _,
706 };
707 if mapping.consume == InputConsume::Hit {
708 consume = true;
709 }
710 }
711 }
712 VirtualAxis::MouseWheelY => {
713 if let Some(mut data) = data.write() {
714 data.0 = match delta {
715 MouseScrollDelta::LineDelta(_, y) => *y,
716 MouseScrollDelta::PixelDelta(pos) => pos.y as _,
717 };
718 if mapping.consume == InputConsume::Hit {
719 consume = true;
720 }
721 }
722 }
723 _ => {}
724 }
725 }
726 if consume {
727 break;
728 }
729 }
730 }
731 }
732 WindowEvent::MouseInput { state, button, .. } => {
733 for (_, mapping) in self.mappings_stack.iter().rev() {
734 if let Some(mapping) = mapping.read() {
735 let mut consume = mapping.consume == InputConsume::All;
736 for (id, data) in &mapping.actions {
737 if let VirtualAction::MouseButton(btn) = id
738 && button == btn
739 && let Some(mut data) = data.write()
740 {
741 *data = data.change(*state == ElementState::Pressed);
742 if mapping.consume == InputConsume::Hit {
743 consume = true;
744 }
745 }
746 }
747 for (id, data) in &mapping.axes {
748 if let VirtualAxis::MouseButton(btn) = id
749 && button == btn
750 && let Some(mut data) = data.write()
751 {
752 data.0 = if *state == ElementState::Pressed {
753 1.0
754 } else {
755 0.0
756 };
757 if mapping.consume == InputConsume::Hit {
758 consume = true;
759 }
760 }
761 }
762 if consume {
763 break;
764 }
765 }
766 }
767 }
768 WindowEvent::AxisMotion { axis, value, .. } => {
769 for (_, mapping) in self.mappings_stack.iter().rev() {
770 if let Some(mapping) = mapping.read() {
771 let mut consume = mapping.consume == InputConsume::All;
772 for (id, data) in &mapping.actions {
773 if let VirtualAction::Axis(index) = id
774 && axis == index
775 && let Some(mut data) = data.write()
776 {
777 *data = data.change(value.abs() > 0.5);
778 if mapping.consume == InputConsume::Hit {
779 consume = true;
780 }
781 }
782 }
783 for (id, data) in &mapping.axes {
784 if let VirtualAxis::Axis(index) = id
785 && axis == index
786 && let Some(mut data) = data.write()
787 {
788 data.0 = *value as _;
789 if mapping.consume == InputConsume::Hit {
790 consume = true;
791 }
792 }
793 }
794 if consume {
795 break;
796 }
797 }
798 }
799 }
800 WindowEvent::Touch(touch) => {
801 if matches!(touch.phase, TouchPhase::Started | TouchPhase::Moved)
802 && self.active_touch.is_none()
803 && touch.location.x >= self.touch_area_margin[0]
804 && touch.location.y >= self.touch_area_margin[1]
805 && touch.location.x < self.window_size[0] - self.touch_area_margin[2]
806 && touch.location.y < self.window_size[1] - self.touch_area_margin[3]
807 {
808 self.active_touch = Some(touch.id);
809 }
810 if let Some(active_touch) = self.active_touch
811 && touch.id == active_touch
812 {
813 for (_, mapping) in self.mappings_stack.iter().rev() {
814 if let Some(mapping) = mapping.read() {
815 let mut consume = mapping.consume == InputConsume::All;
816 for (id, data) in &mapping.actions {
817 if let VirtualAction::Touch = id
818 && let Some(mut data) = data.write()
819 {
820 *data = data.change(matches!(
821 touch.phase,
822 TouchPhase::Started | TouchPhase::Moved
823 ));
824 if mapping.consume == InputConsume::Hit {
825 consume = true;
826 }
827 }
828 }
829 for (id, data) in &mapping.axes {
830 match id {
831 VirtualAxis::TouchX => {
832 if let Some(mut data) = data.write() {
833 data.0 = touch.location.x as _;
834 if mapping.consume == InputConsume::Hit {
835 consume = true;
836 }
837 }
838 }
839 VirtualAxis::TouchY => {
840 if let Some(mut data) = data.write() {
841 data.0 = touch.location.y as _;
842 if mapping.consume == InputConsume::Hit {
843 consume = true;
844 }
845 }
846 }
847 _ => {}
848 }
849 }
850 if consume {
851 break;
852 }
853 }
854 }
855 if matches!(touch.phase, TouchPhase::Ended | TouchPhase::Cancelled) {
856 self.active_touch = None;
857 }
858 }
859 }
860 _ => {}
861 }
862 }
863}
864
865#[cfg(test)]
866mod tests {
867 use super::*;
868
869 #[test]
870 fn test_stack() {
871 let mut context = InputContext::default();
872 context.push_mapping(InputMapping::default().name("a").layer(0));
873 context.push_mapping(InputMapping::default().name("b").layer(0));
874 context.push_mapping(InputMapping::default().name("c").layer(0));
875 context.push_mapping(InputMapping::default().name("d").layer(-1));
876 context.push_mapping(InputMapping::default().name("e").layer(1));
877 context.push_mapping(InputMapping::default().name("f").layer(-1));
878 context.push_mapping(InputMapping::default().name("g").layer(1));
879 context.push_mapping(InputMapping::default().name("h").layer(-2));
880 context.push_mapping(InputMapping::default().name("i").layer(-2));
881 context.push_mapping(InputMapping::default().name("j").layer(2));
882 context.push_mapping(InputMapping::default().name("k").layer(2));
883
884 let provided = context
885 .stack()
886 .map(|mapping| {
887 let mapping = mapping.read().unwrap();
888 (mapping.name.as_ref().to_owned(), mapping.layer)
889 })
890 .collect::<Vec<_>>();
891 assert_eq!(
892 provided,
893 vec![
894 ("h".to_owned(), -2),
895 ("i".to_owned(), -2),
896 ("d".to_owned(), -1),
897 ("f".to_owned(), -1),
898 ("a".to_owned(), 0),
899 ("b".to_owned(), 0),
900 ("c".to_owned(), 0),
901 ("e".to_owned(), 1),
902 ("g".to_owned(), 1),
903 ("j".to_owned(), 2),
904 ("k".to_owned(), 2),
905 ]
906 );
907 }
908}