1use 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#[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 pub phase: TouchPhase,
54 pub position: Vec2,
56 pub window: Entity,
58 pub force: Option<ForceTouch>,
63 pub id: u64,
65}
66
67#[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 Calibrated {
84 force: f64,
91 max_possible_force: f64,
96 altitude_angle: Option<f64>,
102 },
103 Normalized(f64),
108}
109
110#[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 Started,
132 Moved,
134 Ended,
136 Canceled,
141}
142
143#[derive(Debug, Clone, Copy)]
151pub struct Touch {
152 id: u64,
154 start_position: Vec2,
156 start_force: Option<ForceTouch>,
158 previous_position: Vec2,
160 previous_force: Option<ForceTouch>,
162 position: Vec2,
164 force: Option<ForceTouch>,
166}
167
168impl Touch {
169 pub fn delta(&self) -> Vec2 {
171 self.position - self.previous_position
172 }
173
174 pub fn distance(&self) -> Vec2 {
176 self.position - self.start_position
177 }
178
179 #[inline]
181 pub fn id(&self) -> u64 {
182 self.id
183 }
184
185 #[inline]
187 pub fn start_position(&self) -> Vec2 {
188 self.start_position
189 }
190
191 #[inline]
193 pub fn start_force(&self) -> Option<ForceTouch> {
194 self.start_force
195 }
196
197 #[inline]
199 pub fn previous_position(&self) -> Vec2 {
200 self.previous_position
201 }
202
203 #[inline]
205 pub fn previous_force(&self) -> Option<ForceTouch> {
206 self.previous_force
207 }
208
209 #[inline]
211 pub fn position(&self) -> Vec2 {
212 self.position
213 }
214
215 #[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#[derive(Debug, Clone, Default, Resource)]
247pub struct Touches {
248 pressed: HashMap<u64, Touch>,
250 just_pressed: HashMap<u64, Touch>,
252 just_released: HashMap<u64, Touch>,
254 just_canceled: HashMap<u64, Touch>,
256}
257
258impl Touches {
259 pub fn iter(&self) -> impl Iterator<Item = &Touch> + '_ {
261 self.pressed.values()
262 }
263
264 pub fn get_pressed(&self, id: u64) -> Option<&Touch> {
266 self.pressed.get(&id)
267 }
268
269 pub fn any_just_pressed(&self) -> bool {
271 !self.just_pressed.is_empty()
272 }
273
274 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 pub fn release_all(&mut self) {
283 self.just_released.extend(self.pressed.drain());
284 }
285
286 pub fn just_pressed(&self, id: u64) -> bool {
288 self.just_pressed.contains_key(&id)
289 }
290
291 pub fn clear_just_pressed(&mut self, id: u64) -> bool {
295 self.just_pressed.remove(&id).is_some()
296 }
297
298 pub fn iter_just_pressed(&self) -> impl Iterator<Item = &Touch> {
300 self.just_pressed.values()
301 }
302
303 pub fn get_released(&self, id: u64) -> Option<&Touch> {
305 self.just_released.get(&id)
306 }
307
308 pub fn any_just_released(&self) -> bool {
310 !self.just_released.is_empty()
311 }
312
313 pub fn just_released(&self, id: u64) -> bool {
315 self.just_released.contains_key(&id)
316 }
317
318 pub fn clear_just_released(&mut self, id: u64) -> bool {
322 self.just_released.remove(&id).is_some()
323 }
324
325 pub fn iter_just_released(&self) -> impl Iterator<Item = &Touch> {
327 self.just_released.values()
328 }
329
330 pub fn any_just_canceled(&self) -> bool {
332 !self.just_canceled.is_empty()
333 }
334
335 pub fn just_canceled(&self, id: u64) -> bool {
337 self.just_canceled.contains_key(&id)
338 }
339
340 pub fn clear_just_canceled(&mut self, id: u64) -> bool {
344 self.just_canceled.remove(&id).is_some()
345 }
346
347 pub fn iter_just_canceled(&self) -> impl Iterator<Item = &Touch> {
349 self.just_canceled.values()
350 }
351
352 pub fn first_pressed_position(&self) -> Option<Vec2> {
354 self.pressed
357 .values()
358 .next()
359 .or_else(|| self.just_pressed.values().next())
360 .map(|t| t.position)
361 }
362
363 pub fn clear(&mut self) {
367 self.just_pressed.clear();
368 self.just_released.clear();
369 self.just_canceled.clear();
370 }
371
372 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 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 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 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 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
422pub 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 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 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 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 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 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 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 assert_ne!(touch.previous_position, touch.position);
576 }
577
578 #[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 for touch in touches.pressed.values_mut() {
613 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 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 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 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 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 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 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 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}