bevy_input/
touch.rs

1//! The touch input functionality.
2
3use bevy_ecs::{
4    entity::Entity,
5    event::{Event, EventReader},
6    resource::Resource,
7    system::ResMut,
8};
9use bevy_math::Vec2;
10use bevy_platform::collections::HashMap;
11#[cfg(feature = "bevy_reflect")]
12use bevy_reflect::Reflect;
13
14#[cfg(all(feature = "serialize", feature = "bevy_reflect"))]
15use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
16
17/// A touch input event.
18///
19/// ## Logic
20///
21/// Every time the user touches the screen, a new [`TouchPhase::Started`] event with an unique
22/// identifier for the finger is generated. When the finger is lifted, the [`TouchPhase::Ended`]
23/// event is generated with the same finger id.
24///
25/// After a [`TouchPhase::Started`] event has been emitted, there may be zero or more [`TouchPhase::Moved`]
26/// events when the finger is moved or the touch pressure changes.
27///
28/// The finger id may be reused by the system after an [`TouchPhase::Ended`] event. The user
29/// should assume that a new [`TouchPhase::Started`] event received with the same id has nothing
30/// to do with the old finger and is a new finger.
31///
32/// A [`TouchPhase::Canceled`] event is emitted when the system has canceled tracking this
33/// touch, such as when the window loses focus, or on iOS if the user moves the
34/// device against their face.
35///
36/// ## Note
37///
38/// This event is the translated version of the `WindowEvent::Touch` from the `winit` crate.
39/// It is available to the end user and can be used for game logic.
40#[derive(Event, Debug, Clone, Copy, PartialEq)]
41#[cfg_attr(
42    feature = "bevy_reflect",
43    derive(Reflect),
44    reflect(Debug, PartialEq, Clone)
45)]
46#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
47#[cfg_attr(
48    all(feature = "serialize", feature = "bevy_reflect"),
49    reflect(Serialize, Deserialize)
50)]
51pub struct TouchInput {
52    /// The phase of the touch input.
53    pub phase: TouchPhase,
54    /// The position of the finger on the touchscreen.
55    pub position: Vec2,
56    /// The window entity registering the touch.
57    pub window: Entity,
58    /// Describes how hard the screen was pressed.
59    ///
60    /// May be [`None`] if the platform does not support pressure sensitivity.
61    /// This feature is only available on **iOS** 9.0+ and **Windows** 8+.
62    pub force: Option<ForceTouch>,
63    /// The unique identifier of the finger.
64    pub id: u64,
65}
66
67/// A force description of a [`Touch`] input.
68#[derive(Debug, Clone, Copy, PartialEq)]
69#[cfg_attr(
70    feature = "bevy_reflect",
71    derive(Reflect),
72    reflect(Debug, PartialEq, Clone)
73)]
74#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
75#[cfg_attr(
76    all(feature = "serialize", feature = "bevy_reflect"),
77    reflect(Serialize, Deserialize)
78)]
79pub enum ForceTouch {
80    /// On iOS, the force is calibrated so that the same number corresponds to
81    /// roughly the same amount of pressure on the screen regardless of the
82    /// device.
83    Calibrated {
84        /// The force of the touch, where a value of 1.0 represents the force of
85        /// an average touch (predetermined by the system, not user-specific).
86        ///
87        /// The force reported by Apple Pencil is measured along the axis of the
88        /// pencil. If you want a force perpendicular to the device, you need to
89        /// calculate this value using the `altitude_angle` value.
90        force: f64,
91        /// The maximum possible force for a touch.
92        ///
93        /// The value of this field is sufficiently high to provide a wide
94        /// dynamic range for values of the `force` field.
95        max_possible_force: f64,
96        /// The altitude (in radians) of the stylus.
97        ///
98        /// A value of 0 radians indicates that the stylus is parallel to the
99        /// surface. The value of this property is Pi/2 when the stylus is
100        /// perpendicular to the surface.
101        altitude_angle: Option<f64>,
102    },
103    /// If the platform reports the force as normalized, we have no way of
104    /// knowing how much pressure 1.0 corresponds to – we know it's the maximum
105    /// amount of force, but as to how much force, you might either have to
106    /// press really hard, or not hard at all, depending on the device.
107    Normalized(f64),
108}
109
110/// A phase of a [`TouchInput`].
111///
112/// ## Usage
113///
114/// It is used to describe the phase of the touch input that is currently active.
115/// This includes a phase that indicates that a touch input has started or ended,
116/// or that a finger has moved. There is also a canceled phase that indicates that
117/// the system canceled the tracking of the finger.
118#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
119#[cfg_attr(
120    feature = "bevy_reflect",
121    derive(Reflect),
122    reflect(Debug, Hash, PartialEq, Clone)
123)]
124#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
125#[cfg_attr(
126    all(feature = "serialize", feature = "bevy_reflect"),
127    reflect(Serialize, Deserialize)
128)]
129pub enum TouchPhase {
130    /// A finger started to touch the touchscreen.
131    Started,
132    /// A finger moved over the touchscreen.
133    Moved,
134    /// A finger stopped touching the touchscreen.
135    Ended,
136    /// The system canceled the tracking of the finger.
137    ///
138    /// This occurs when the window loses focus, or on iOS if the user moves the
139    /// device against their face.
140    Canceled,
141}
142
143/// A touch input.
144///
145/// ## Usage
146///
147/// It is used to store the position and force of a touch input and also the `id` of the finger.
148/// The data of the touch input comes from the [`TouchInput`] event and is being stored
149/// inside of the [`Touches`] `bevy` resource.
150#[derive(Debug, Clone, Copy)]
151pub struct Touch {
152    /// The id of the touch input.
153    id: u64,
154    /// The starting position of the touch input.
155    start_position: Vec2,
156    /// The starting force of the touch input.
157    start_force: Option<ForceTouch>,
158    /// The previous position of the touch input.
159    previous_position: Vec2,
160    /// The previous force of the touch input.
161    previous_force: Option<ForceTouch>,
162    /// The current position of the touch input.
163    position: Vec2,
164    /// The current force of the touch input.
165    force: Option<ForceTouch>,
166}
167
168impl Touch {
169    /// The delta of the current `position` and the `previous_position`.
170    pub fn delta(&self) -> Vec2 {
171        self.position - self.previous_position
172    }
173
174    /// The distance of the `start_position` and the current `position`.
175    pub fn distance(&self) -> Vec2 {
176        self.position - self.start_position
177    }
178
179    /// Returns the `id` of the touch.
180    #[inline]
181    pub fn id(&self) -> u64 {
182        self.id
183    }
184
185    /// Returns the `start_position` of the touch.
186    #[inline]
187    pub fn start_position(&self) -> Vec2 {
188        self.start_position
189    }
190
191    /// Returns the `start_force` of the touch.
192    #[inline]
193    pub fn start_force(&self) -> Option<ForceTouch> {
194        self.start_force
195    }
196
197    /// Returns the `previous_position` of the touch.
198    #[inline]
199    pub fn previous_position(&self) -> Vec2 {
200        self.previous_position
201    }
202
203    /// Returns the `previous_force` of the touch.
204    #[inline]
205    pub fn previous_force(&self) -> Option<ForceTouch> {
206        self.previous_force
207    }
208
209    /// Returns the current `position` of the touch.
210    #[inline]
211    pub fn position(&self) -> Vec2 {
212        self.position
213    }
214
215    /// Returns the current `force` of the touch.
216    #[inline]
217    pub fn force(&self) -> Option<ForceTouch> {
218        self.force
219    }
220}
221
222impl From<&TouchInput> for Touch {
223    fn from(input: &TouchInput) -> Touch {
224        Touch {
225            id: input.id,
226            start_position: input.position,
227            start_force: input.force,
228            previous_position: input.position,
229            previous_force: input.force,
230            position: input.position,
231            force: input.force,
232        }
233    }
234}
235
236/// A collection of [`Touch`]es.
237///
238/// ## Usage
239///
240/// It is used to create a `bevy` resource that stores the data of the touches on a touchscreen
241/// and can be accessed inside of a system.
242///
243/// ## Updating
244///
245/// The resource is updated inside of the [`touch_screen_input_system`].
246#[derive(Debug, Clone, Default, Resource)]
247pub struct Touches {
248    /// A collection of every [`Touch`] that is currently being pressed.
249    pressed: HashMap<u64, Touch>,
250    /// A collection of every [`Touch`] that just got pressed.
251    just_pressed: HashMap<u64, Touch>,
252    /// A collection of every [`Touch`] that just got released.
253    just_released: HashMap<u64, Touch>,
254    /// A collection of every [`Touch`] that just got canceled.
255    just_canceled: HashMap<u64, Touch>,
256}
257
258impl Touches {
259    /// An iterator visiting every pressed [`Touch`] input in arbitrary order.
260    pub fn iter(&self) -> impl Iterator<Item = &Touch> + '_ {
261        self.pressed.values()
262    }
263
264    /// Returns the [`Touch`] input corresponding to the `id` if it is being pressed.
265    pub fn get_pressed(&self, id: u64) -> Option<&Touch> {
266        self.pressed.get(&id)
267    }
268
269    /// Checks if any touch input was just pressed.
270    pub fn any_just_pressed(&self) -> bool {
271        !self.just_pressed.is_empty()
272    }
273
274    /// Register a release for a given touch input.
275    pub fn release(&mut self, id: u64) {
276        if let Some(touch) = self.pressed.remove(&id) {
277            self.just_released.insert(id, touch);
278        }
279    }
280
281    /// Registers a release for all currently pressed touch inputs.
282    pub fn release_all(&mut self) {
283        self.just_released.extend(self.pressed.drain());
284    }
285
286    /// Returns `true` if the input corresponding to the `id` has just been pressed.
287    pub fn just_pressed(&self, id: u64) -> bool {
288        self.just_pressed.contains_key(&id)
289    }
290
291    /// Clears the `just_pressed` state of the touch input and returns `true` if the touch input has just been pressed.
292    ///
293    /// Future calls to [`Touches::just_pressed`] for the given touch input will return false until a new press event occurs.
294    pub fn clear_just_pressed(&mut self, id: u64) -> bool {
295        self.just_pressed.remove(&id).is_some()
296    }
297
298    /// An iterator visiting every just pressed [`Touch`] input in arbitrary order.
299    pub fn iter_just_pressed(&self) -> impl Iterator<Item = &Touch> {
300        self.just_pressed.values()
301    }
302
303    /// Returns the [`Touch`] input corresponding to the `id` if it has just been released.
304    pub fn get_released(&self, id: u64) -> Option<&Touch> {
305        self.just_released.get(&id)
306    }
307
308    /// Checks if any touch input was just released.
309    pub fn any_just_released(&self) -> bool {
310        !self.just_released.is_empty()
311    }
312
313    /// Returns `true` if the input corresponding to the `id` has just been released.
314    pub fn just_released(&self, id: u64) -> bool {
315        self.just_released.contains_key(&id)
316    }
317
318    /// Clears the `just_released` state of the touch input and returns `true` if the touch input has just been released.
319    ///
320    /// Future calls to [`Touches::just_released`] for the given touch input will return false until a new release event occurs.
321    pub fn clear_just_released(&mut self, id: u64) -> bool {
322        self.just_released.remove(&id).is_some()
323    }
324
325    /// An iterator visiting every just released [`Touch`] input in arbitrary order.
326    pub fn iter_just_released(&self) -> impl Iterator<Item = &Touch> {
327        self.just_released.values()
328    }
329
330    /// Checks if any touch input was just canceled.
331    pub fn any_just_canceled(&self) -> bool {
332        !self.just_canceled.is_empty()
333    }
334
335    /// Returns `true` if the input corresponding to the `id` has just been canceled.
336    pub fn just_canceled(&self, id: u64) -> bool {
337        self.just_canceled.contains_key(&id)
338    }
339
340    /// Clears the `just_canceled` state of the touch input and returns `true` if the touch input has just been canceled.
341    ///
342    /// Future calls to [`Touches::just_canceled`] for the given touch input will return false until a new cancel event occurs.
343    pub fn clear_just_canceled(&mut self, id: u64) -> bool {
344        self.just_canceled.remove(&id).is_some()
345    }
346
347    /// An iterator visiting every just canceled [`Touch`] input in arbitrary order.
348    pub fn iter_just_canceled(&self) -> impl Iterator<Item = &Touch> {
349        self.just_canceled.values()
350    }
351
352    /// Retrieves the position of the first currently pressed touch, if any
353    pub fn first_pressed_position(&self) -> Option<Vec2> {
354        // Looking for the position in `pressed`. If nothing is found, also look into `just_pressed`
355        // A touch can be in `just_pressed` but not in `pressed` if it ended in the same frame it started
356        self.pressed
357            .values()
358            .next()
359            .or_else(|| self.just_pressed.values().next())
360            .map(|t| t.position)
361    }
362
363    /// Clears `just_pressed`, `just_released`, and `just_canceled` data for every touch input.
364    ///
365    /// See also [`Touches::reset_all`] for a full reset.
366    pub fn clear(&mut self) {
367        self.just_pressed.clear();
368        self.just_released.clear();
369        self.just_canceled.clear();
370    }
371
372    /// Clears `pressed`, `just_pressed`, `just_released`, and `just_canceled` data for every touch input.
373    ///
374    /// See also [`Touches::clear`] for clearing only touches that have just been pressed, released or canceled.
375    pub fn reset_all(&mut self) {
376        self.pressed.clear();
377        self.just_pressed.clear();
378        self.just_released.clear();
379        self.just_canceled.clear();
380    }
381
382    /// Processes a [`TouchInput`] event by updating the `pressed`, `just_pressed`,
383    /// `just_released`, and `just_canceled` collections.
384    fn process_touch_event(&mut self, event: &TouchInput) {
385        match event.phase {
386            TouchPhase::Started => {
387                self.pressed.insert(event.id, event.into());
388                self.just_pressed.insert(event.id, event.into());
389            }
390            TouchPhase::Moved => {
391                if let Some(mut new_touch) = self.pressed.get(&event.id).cloned() {
392                    // NOTE: This does not update the previous_force / previous_position field;
393                    // they should be updated once per frame, not once per event
394                    // See https://github.com/bevyengine/bevy/issues/12442
395                    new_touch.position = event.position;
396                    new_touch.force = event.force;
397                    self.pressed.insert(event.id, new_touch);
398                }
399            }
400            TouchPhase::Ended => {
401                // if touch `just_released`, add related event to it
402                // the event position info is inside `pressed`, so use it unless not found
403                if let Some((_, v)) = self.pressed.remove_entry(&event.id) {
404                    self.just_released.insert(event.id, v);
405                } else {
406                    self.just_released.insert(event.id, event.into());
407                }
408            }
409            TouchPhase::Canceled => {
410                // if touch `just_canceled`, add related event to it
411                // the event position info is inside `pressed`, so use it unless not found
412                if let Some((_, v)) = self.pressed.remove_entry(&event.id) {
413                    self.just_canceled.insert(event.id, v);
414                } else {
415                    self.just_canceled.insert(event.id, event.into());
416                }
417            }
418        };
419    }
420}
421
422/// Updates the [`Touches`] resource with the latest [`TouchInput`] events.
423///
424/// This is not clearing the `pressed` collection, because it could incorrectly mark a touch input
425/// as not pressed even though it is pressed. This could happen if the touch input is not moving
426/// for a single frame and would therefore be marked as not pressed, because this function is
427/// called on every single frame no matter if there was an event or not.
428///
429/// ## Differences
430///
431/// The main difference between the [`TouchInput`] event and the [`Touches`] resource is that
432/// the latter has convenient functions like [`Touches::just_pressed`] and [`Touches::just_released`].
433pub fn touch_screen_input_system(
434    mut touch_state: ResMut<Touches>,
435    mut touch_input_events: EventReader<TouchInput>,
436) {
437    if !touch_state.just_pressed.is_empty() {
438        touch_state.just_pressed.clear();
439    }
440    if !touch_state.just_released.is_empty() {
441        touch_state.just_released.clear();
442    }
443    if !touch_state.just_canceled.is_empty() {
444        touch_state.just_canceled.clear();
445    }
446
447    if !touch_input_events.is_empty() {
448        for touch in touch_state.pressed.values_mut() {
449            touch.previous_position = touch.position;
450            touch.previous_force = touch.force;
451        }
452
453        for event in touch_input_events.read() {
454            touch_state.process_touch_event(event);
455        }
456    }
457}
458
459#[cfg(test)]
460mod test {
461    use super::Touches;
462
463    #[test]
464    fn touch_update() {
465        use crate::{touch::Touch, Touches};
466        use bevy_math::Vec2;
467
468        let mut touches = Touches::default();
469
470        let touch_event = Touch {
471            id: 4,
472            start_position: Vec2::ZERO,
473            start_force: None,
474            previous_position: Vec2::ZERO,
475            previous_force: None,
476            position: Vec2::ZERO,
477            force: None,
478        };
479
480        // Add a touch to `just_pressed`, 'just_released', and 'just canceled'
481
482        touches.just_pressed.insert(4, touch_event);
483        touches.just_released.insert(4, touch_event);
484        touches.just_canceled.insert(4, touch_event);
485
486        clear_all(&mut touches);
487
488        // Verify that all the `just_x` maps are cleared
489        assert!(touches.just_pressed.is_empty());
490        assert!(touches.just_released.is_empty());
491        assert!(touches.just_canceled.is_empty());
492    }
493
494    #[test]
495    fn touch_process() {
496        use crate::{touch::TouchPhase, TouchInput, Touches};
497        use bevy_ecs::entity::Entity;
498        use bevy_math::Vec2;
499
500        let mut touches = Touches::default();
501
502        // Test adding a `TouchPhase::Started`
503
504        let touch_event = TouchInput {
505            phase: TouchPhase::Started,
506            position: Vec2::splat(4.0),
507            window: Entity::PLACEHOLDER,
508            force: None,
509            id: 4,
510        };
511
512        clear_all(&mut touches);
513        touches.process_touch_event(&touch_event);
514
515        assert!(touches.pressed.get(&touch_event.id).is_some());
516        assert!(touches.just_pressed.get(&touch_event.id).is_some());
517
518        // Test adding a `TouchPhase::Moved`
519
520        let moved_touch_event = TouchInput {
521            phase: TouchPhase::Moved,
522            position: Vec2::splat(5.0),
523            window: Entity::PLACEHOLDER,
524            force: None,
525            id: touch_event.id,
526        };
527
528        clear_all(&mut touches);
529        touches.process_touch_event(&moved_touch_event);
530
531        assert_eq!(
532            touches
533                .pressed
534                .get(&moved_touch_event.id)
535                .expect("Missing from pressed after move.")
536                .previous_position,
537            touch_event.position
538        );
539
540        // Test cancelling an event
541
542        let cancel_touch_event = TouchInput {
543            phase: TouchPhase::Canceled,
544            position: Vec2::ONE,
545            window: Entity::PLACEHOLDER,
546            force: None,
547            id: touch_event.id,
548        };
549
550        clear_all(&mut touches);
551        touches.process_touch_event(&cancel_touch_event);
552
553        assert!(touches.just_canceled.get(&touch_event.id).is_some());
554        assert!(touches.pressed.get(&touch_event.id).is_none());
555
556        // Test ending an event
557
558        let end_touch_event = TouchInput {
559            phase: TouchPhase::Ended,
560            position: Vec2::splat(4.0),
561            window: Entity::PLACEHOLDER,
562            force: None,
563            id: touch_event.id,
564        };
565
566        clear_all(&mut touches);
567        touches.process_touch_event(&touch_event);
568        touches.process_touch_event(&moved_touch_event);
569        touches.process_touch_event(&end_touch_event);
570
571        assert!(touches.just_released.get(&touch_event.id).is_some());
572        assert!(touches.pressed.get(&touch_event.id).is_none());
573        let touch = touches.just_released.get(&touch_event.id).unwrap();
574        // Make sure the position is updated from TouchPhase::Moved and TouchPhase::Ended
575        assert_ne!(touch.previous_position, touch.position);
576    }
577
578    // See https://github.com/bevyengine/bevy/issues/12442
579    #[test]
580    fn touch_process_multi_event() {
581        use crate::{touch::TouchPhase, TouchInput, Touches};
582        use bevy_ecs::entity::Entity;
583        use bevy_math::Vec2;
584
585        let mut touches = Touches::default();
586
587        let started_touch_event = TouchInput {
588            phase: TouchPhase::Started,
589            position: Vec2::splat(4.0),
590            window: Entity::PLACEHOLDER,
591            force: None,
592            id: 4,
593        };
594
595        let moved_touch_event1 = TouchInput {
596            phase: TouchPhase::Moved,
597            position: Vec2::splat(5.0),
598            window: Entity::PLACEHOLDER,
599            force: None,
600            id: started_touch_event.id,
601        };
602
603        let moved_touch_event2 = TouchInput {
604            phase: TouchPhase::Moved,
605            position: Vec2::splat(6.0),
606            window: Entity::PLACEHOLDER,
607            force: None,
608            id: started_touch_event.id,
609        };
610
611        // tick 1: touch is started during frame
612        for touch in touches.pressed.values_mut() {
613            // update ONCE, at start of frame
614            touch.previous_position = touch.position;
615        }
616        touches.process_touch_event(&started_touch_event);
617        touches.process_touch_event(&moved_touch_event1);
618        touches.process_touch_event(&moved_touch_event2);
619
620        {
621            let touch = touches.get_pressed(started_touch_event.id).unwrap();
622            assert_eq!(touch.previous_position, started_touch_event.position);
623            assert_eq!(touch.position, moved_touch_event2.position);
624        }
625
626        // tick 2: touch was started before frame
627        for touch in touches.pressed.values_mut() {
628            touch.previous_position = touch.position;
629        }
630        touches.process_touch_event(&moved_touch_event1);
631        touches.process_touch_event(&moved_touch_event2);
632        touches.process_touch_event(&moved_touch_event1);
633
634        {
635            let touch = touches.get_pressed(started_touch_event.id).unwrap();
636            assert_eq!(touch.previous_position, moved_touch_event2.position);
637            assert_eq!(touch.position, moved_touch_event1.position);
638        }
639    }
640
641    #[test]
642    fn touch_pressed() {
643        use crate::{touch::TouchPhase, TouchInput, Touches};
644        use bevy_ecs::entity::Entity;
645        use bevy_math::Vec2;
646
647        let mut touches = Touches::default();
648
649        let touch_event = TouchInput {
650            phase: TouchPhase::Started,
651            position: Vec2::splat(4.0),
652            window: Entity::PLACEHOLDER,
653            force: None,
654            id: 4,
655        };
656
657        // Register the touch and test that it was registered correctly
658        touches.process_touch_event(&touch_event);
659
660        assert!(touches.get_pressed(touch_event.id).is_some());
661        assert!(touches.just_pressed(touch_event.id));
662        assert_eq!(touches.iter().count(), 1);
663
664        touches.clear_just_pressed(touch_event.id);
665        assert!(!touches.just_pressed(touch_event.id));
666    }
667
668    #[test]
669    fn touch_released() {
670        use crate::{touch::TouchPhase, TouchInput, Touches};
671        use bevy_ecs::entity::Entity;
672        use bevy_math::Vec2;
673
674        let mut touches = Touches::default();
675
676        let touch_event = TouchInput {
677            phase: TouchPhase::Ended,
678            position: Vec2::splat(4.0),
679            window: Entity::PLACEHOLDER,
680            force: None,
681            id: 4,
682        };
683
684        // Register the touch and test that it was registered correctly
685        touches.process_touch_event(&touch_event);
686
687        assert!(touches.get_released(touch_event.id).is_some());
688        assert!(touches.just_released(touch_event.id));
689        assert_eq!(touches.iter_just_released().count(), 1);
690
691        touches.clear_just_released(touch_event.id);
692        assert!(!touches.just_released(touch_event.id));
693    }
694
695    #[test]
696    fn touch_canceled() {
697        use crate::{touch::TouchPhase, TouchInput, Touches};
698        use bevy_ecs::entity::Entity;
699        use bevy_math::Vec2;
700
701        let mut touches = Touches::default();
702
703        let touch_event = TouchInput {
704            phase: TouchPhase::Canceled,
705            position: Vec2::splat(4.0),
706            window: Entity::PLACEHOLDER,
707            force: None,
708            id: 4,
709        };
710
711        // Register the touch and test that it was registered correctly
712        touches.process_touch_event(&touch_event);
713
714        assert!(touches.just_canceled(touch_event.id));
715        assert_eq!(touches.iter_just_canceled().count(), 1);
716
717        touches.clear_just_canceled(touch_event.id);
718        assert!(!touches.just_canceled(touch_event.id));
719    }
720
721    #[test]
722    fn release_touch() {
723        use crate::{touch::TouchPhase, TouchInput, Touches};
724        use bevy_ecs::entity::Entity;
725        use bevy_math::Vec2;
726
727        let mut touches = Touches::default();
728
729        let touch_event = TouchInput {
730            phase: TouchPhase::Started,
731            position: Vec2::splat(4.0),
732            window: Entity::PLACEHOLDER,
733            force: None,
734            id: 4,
735        };
736
737        // Register the touch and test that it was registered correctly
738        touches.process_touch_event(&touch_event);
739
740        assert!(touches.get_pressed(touch_event.id).is_some());
741
742        touches.release(touch_event.id);
743        assert!(touches.get_pressed(touch_event.id).is_none());
744        assert!(touches.just_released(touch_event.id));
745    }
746
747    #[test]
748    fn release_all_touches() {
749        use crate::{touch::TouchPhase, TouchInput, Touches};
750        use bevy_ecs::entity::Entity;
751        use bevy_math::Vec2;
752
753        let mut touches = Touches::default();
754
755        let touch_pressed_event = TouchInput {
756            phase: TouchPhase::Started,
757            position: Vec2::splat(4.0),
758            window: Entity::PLACEHOLDER,
759            force: None,
760            id: 4,
761        };
762
763        let touch_moved_event = TouchInput {
764            phase: TouchPhase::Moved,
765            position: Vec2::splat(4.0),
766            window: Entity::PLACEHOLDER,
767            force: None,
768            id: 4,
769        };
770
771        touches.process_touch_event(&touch_pressed_event);
772        touches.process_touch_event(&touch_moved_event);
773
774        assert!(touches.get_pressed(touch_pressed_event.id).is_some());
775        assert!(touches.get_pressed(touch_moved_event.id).is_some());
776
777        touches.release_all();
778
779        assert!(touches.get_pressed(touch_pressed_event.id).is_none());
780        assert!(touches.just_released(touch_pressed_event.id));
781        assert!(touches.get_pressed(touch_moved_event.id).is_none());
782        assert!(touches.just_released(touch_moved_event.id));
783    }
784
785    #[test]
786    fn clear_touches() {
787        use crate::{touch::TouchPhase, TouchInput, Touches};
788        use bevy_ecs::entity::Entity;
789        use bevy_math::Vec2;
790
791        let mut touches = Touches::default();
792
793        let touch_press_event = TouchInput {
794            phase: TouchPhase::Started,
795            position: Vec2::splat(4.0),
796            window: Entity::PLACEHOLDER,
797            force: None,
798            id: 4,
799        };
800
801        let touch_canceled_event = TouchInput {
802            phase: TouchPhase::Canceled,
803            position: Vec2::splat(4.0),
804            window: Entity::PLACEHOLDER,
805            force: None,
806            id: 5,
807        };
808
809        let touch_released_event = TouchInput {
810            phase: TouchPhase::Ended,
811            position: Vec2::splat(4.0),
812            window: Entity::PLACEHOLDER,
813            force: None,
814            id: 6,
815        };
816
817        // Register the touches and test that it was registered correctly
818        touches.process_touch_event(&touch_press_event);
819        touches.process_touch_event(&touch_canceled_event);
820        touches.process_touch_event(&touch_released_event);
821
822        assert!(touches.get_pressed(touch_press_event.id).is_some());
823        assert!(touches.just_pressed(touch_press_event.id));
824        assert!(touches.just_canceled(touch_canceled_event.id));
825        assert!(touches.just_released(touch_released_event.id));
826
827        touches.clear();
828
829        assert!(touches.get_pressed(touch_press_event.id).is_some());
830        assert!(!touches.just_pressed(touch_press_event.id));
831        assert!(!touches.just_canceled(touch_canceled_event.id));
832        assert!(!touches.just_released(touch_released_event.id));
833    }
834
835    #[test]
836    fn reset_all_touches() {
837        use crate::{touch::TouchPhase, TouchInput, Touches};
838        use bevy_ecs::entity::Entity;
839        use bevy_math::Vec2;
840
841        let mut touches = Touches::default();
842
843        let touch_press_event = TouchInput {
844            phase: TouchPhase::Started,
845            position: Vec2::splat(4.0),
846            window: Entity::PLACEHOLDER,
847            force: None,
848            id: 4,
849        };
850
851        let touch_canceled_event = TouchInput {
852            phase: TouchPhase::Canceled,
853            position: Vec2::splat(4.0),
854            window: Entity::PLACEHOLDER,
855            force: None,
856            id: 5,
857        };
858
859        let touch_released_event = TouchInput {
860            phase: TouchPhase::Ended,
861            position: Vec2::splat(4.0),
862            window: Entity::PLACEHOLDER,
863            force: None,
864            id: 6,
865        };
866
867        // Register the touches and test that it was registered correctly
868        touches.process_touch_event(&touch_press_event);
869        touches.process_touch_event(&touch_canceled_event);
870        touches.process_touch_event(&touch_released_event);
871
872        assert!(touches.get_pressed(touch_press_event.id).is_some());
873        assert!(touches.just_pressed(touch_press_event.id));
874        assert!(touches.just_canceled(touch_canceled_event.id));
875        assert!(touches.just_released(touch_released_event.id));
876
877        touches.reset_all();
878
879        assert!(touches.get_pressed(touch_press_event.id).is_none());
880        assert!(!touches.just_pressed(touch_press_event.id));
881        assert!(!touches.just_canceled(touch_canceled_event.id));
882        assert!(!touches.just_released(touch_released_event.id));
883    }
884
885    fn clear_all(touch_state: &mut Touches) {
886        touch_state.just_pressed.clear();
887        touch_state.just_released.clear();
888        touch_state.just_canceled.clear();
889    }
890}