spitfire_input/
lib.rs

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    /// [left, top, right, bottom]
370    pub touch_area_margin: [f64; 4],
371    /// [(id, mapping)]
372    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}