1use bevy_ecs::{
4 entity::Entity,
5 event::{Event, EventReader},
6 system::{ResMut, Resource},
7};
8use bevy_math::Vec2;
9#[cfg(feature = "bevy_reflect")]
10use bevy_reflect::Reflect;
11use bevy_utils::HashMap;
12
13#[cfg(all(feature = "serialize", feature = "bevy_reflect"))]
14use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
15
16#[derive(Event, Debug, Clone, Copy, PartialEq)]
40#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug, PartialEq))]
41#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
42#[cfg_attr(
43 all(feature = "serialize", feature = "bevy_reflect"),
44 reflect(Serialize, Deserialize)
45)]
46pub struct TouchInput {
47 pub phase: TouchPhase,
49 pub position: Vec2,
51 pub window: Entity,
53 pub force: Option<ForceTouch>,
58 pub id: u64,
60}
61
62#[derive(Debug, Clone, Copy, PartialEq)]
64#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug, PartialEq))]
65#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
66#[cfg_attr(
67 all(feature = "serialize", feature = "bevy_reflect"),
68 reflect(Serialize, Deserialize)
69)]
70pub enum ForceTouch {
71 Calibrated {
75 force: f64,
82 max_possible_force: f64,
87 altitude_angle: Option<f64>,
93 },
94 Normalized(f64),
99}
100
101#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
110#[cfg_attr(
111 feature = "bevy_reflect",
112 derive(Reflect),
113 reflect(Debug, Hash, PartialEq)
114)]
115#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
116#[cfg_attr(
117 all(feature = "serialize", feature = "bevy_reflect"),
118 reflect(Serialize, Deserialize)
119)]
120pub enum TouchPhase {
121 Started,
123 Moved,
125 Ended,
127 Canceled,
132}
133
134#[derive(Debug, Clone, Copy)]
142pub struct Touch {
143 id: u64,
145 start_position: Vec2,
147 start_force: Option<ForceTouch>,
149 previous_position: Vec2,
151 previous_force: Option<ForceTouch>,
153 position: Vec2,
155 force: Option<ForceTouch>,
157}
158
159impl Touch {
160 pub fn delta(&self) -> Vec2 {
162 self.position - self.previous_position
163 }
164
165 pub fn distance(&self) -> Vec2 {
167 self.position - self.start_position
168 }
169
170 #[inline]
172 pub fn id(&self) -> u64 {
173 self.id
174 }
175
176 #[inline]
178 pub fn start_position(&self) -> Vec2 {
179 self.start_position
180 }
181
182 #[inline]
184 pub fn start_force(&self) -> Option<ForceTouch> {
185 self.start_force
186 }
187
188 #[inline]
190 pub fn previous_position(&self) -> Vec2 {
191 self.previous_position
192 }
193
194 #[inline]
196 pub fn previous_force(&self) -> Option<ForceTouch> {
197 self.previous_force
198 }
199
200 #[inline]
202 pub fn position(&self) -> Vec2 {
203 self.position
204 }
205
206 #[inline]
208 pub fn force(&self) -> Option<ForceTouch> {
209 self.force
210 }
211}
212
213impl From<&TouchInput> for Touch {
214 fn from(input: &TouchInput) -> Touch {
215 Touch {
216 id: input.id,
217 start_position: input.position,
218 start_force: input.force,
219 previous_position: input.position,
220 previous_force: input.force,
221 position: input.position,
222 force: input.force,
223 }
224 }
225}
226
227#[derive(Debug, Clone, Default, Resource)]
238pub struct Touches {
239 pressed: HashMap<u64, Touch>,
241 just_pressed: HashMap<u64, Touch>,
243 just_released: HashMap<u64, Touch>,
245 just_canceled: HashMap<u64, Touch>,
247}
248
249impl Touches {
250 pub fn iter(&self) -> impl Iterator<Item = &Touch> + '_ {
252 self.pressed.values()
253 }
254
255 pub fn get_pressed(&self, id: u64) -> Option<&Touch> {
257 self.pressed.get(&id)
258 }
259
260 pub fn any_just_pressed(&self) -> bool {
262 !self.just_pressed.is_empty()
263 }
264
265 pub fn release(&mut self, id: u64) {
267 if let Some(touch) = self.pressed.remove(&id) {
268 self.just_released.insert(id, touch);
269 }
270 }
271
272 pub fn release_all(&mut self) {
274 self.just_released.extend(self.pressed.drain());
275 }
276
277 pub fn just_pressed(&self, id: u64) -> bool {
279 self.just_pressed.contains_key(&id)
280 }
281
282 pub fn clear_just_pressed(&mut self, id: u64) -> bool {
286 self.just_pressed.remove(&id).is_some()
287 }
288
289 pub fn iter_just_pressed(&self) -> impl Iterator<Item = &Touch> {
291 self.just_pressed.values()
292 }
293
294 pub fn get_released(&self, id: u64) -> Option<&Touch> {
296 self.just_released.get(&id)
297 }
298
299 pub fn any_just_released(&self) -> bool {
301 !self.just_released.is_empty()
302 }
303
304 pub fn just_released(&self, id: u64) -> bool {
306 self.just_released.contains_key(&id)
307 }
308
309 pub fn clear_just_released(&mut self, id: u64) -> bool {
313 self.just_released.remove(&id).is_some()
314 }
315
316 pub fn iter_just_released(&self) -> impl Iterator<Item = &Touch> {
318 self.just_released.values()
319 }
320
321 pub fn any_just_canceled(&self) -> bool {
323 !self.just_canceled.is_empty()
324 }
325
326 pub fn just_canceled(&self, id: u64) -> bool {
328 self.just_canceled.contains_key(&id)
329 }
330
331 pub fn clear_just_canceled(&mut self, id: u64) -> bool {
335 self.just_canceled.remove(&id).is_some()
336 }
337
338 pub fn iter_just_canceled(&self) -> impl Iterator<Item = &Touch> {
340 self.just_canceled.values()
341 }
342
343 pub fn first_pressed_position(&self) -> Option<Vec2> {
345 self.pressed
348 .values()
349 .next()
350 .or_else(|| self.just_pressed.values().next())
351 .map(|t| t.position)
352 }
353
354 pub fn clear(&mut self) {
358 self.just_pressed.clear();
359 self.just_released.clear();
360 self.just_canceled.clear();
361 }
362
363 pub fn reset_all(&mut self) {
367 self.pressed.clear();
368 self.just_pressed.clear();
369 self.just_released.clear();
370 self.just_canceled.clear();
371 }
372
373 fn process_touch_event(&mut self, event: &TouchInput) {
376 match event.phase {
377 TouchPhase::Started => {
378 self.pressed.insert(event.id, event.into());
379 self.just_pressed.insert(event.id, event.into());
380 }
381 TouchPhase::Moved => {
382 if let Some(mut new_touch) = self.pressed.get(&event.id).cloned() {
383 new_touch.position = event.position;
387 new_touch.force = event.force;
388 self.pressed.insert(event.id, new_touch);
389 }
390 }
391 TouchPhase::Ended => {
392 if let Some((_, v)) = self.pressed.remove_entry(&event.id) {
395 self.just_released.insert(event.id, v);
396 } else {
397 self.just_released.insert(event.id, event.into());
398 }
399 }
400 TouchPhase::Canceled => {
401 if let Some((_, v)) = self.pressed.remove_entry(&event.id) {
404 self.just_canceled.insert(event.id, v);
405 } else {
406 self.just_canceled.insert(event.id, event.into());
407 }
408 }
409 };
410 }
411}
412
413pub fn touch_screen_input_system(
425 mut touch_state: ResMut<Touches>,
426 mut touch_input_events: EventReader<TouchInput>,
427) {
428 if !touch_state.just_pressed.is_empty() {
429 touch_state.just_pressed.clear();
430 }
431 if !touch_state.just_released.is_empty() {
432 touch_state.just_released.clear();
433 }
434 if !touch_state.just_canceled.is_empty() {
435 touch_state.just_canceled.clear();
436 }
437
438 if !touch_input_events.is_empty() {
439 for touch in touch_state.pressed.values_mut() {
440 touch.previous_position = touch.position;
441 touch.previous_force = touch.force;
442 }
443
444 for event in touch_input_events.read() {
445 touch_state.process_touch_event(event);
446 }
447 }
448}
449
450#[cfg(test)]
451mod test {
452 use super::Touches;
453
454 #[test]
455 fn touch_update() {
456 use crate::{touch::Touch, Touches};
457 use bevy_math::Vec2;
458
459 let mut touches = Touches::default();
460
461 let touch_event = Touch {
462 id: 4,
463 start_position: Vec2::ZERO,
464 start_force: None,
465 previous_position: Vec2::ZERO,
466 previous_force: None,
467 position: Vec2::ZERO,
468 force: None,
469 };
470
471 touches.just_pressed.insert(4, touch_event);
474 touches.just_released.insert(4, touch_event);
475 touches.just_canceled.insert(4, touch_event);
476
477 clear_all(&mut touches);
478
479 assert!(touches.just_pressed.is_empty());
481 assert!(touches.just_released.is_empty());
482 assert!(touches.just_canceled.is_empty());
483 }
484
485 #[test]
486 fn touch_process() {
487 use crate::{touch::TouchPhase, TouchInput, Touches};
488 use bevy_ecs::entity::Entity;
489 use bevy_math::Vec2;
490
491 let mut touches = Touches::default();
492
493 let touch_event = TouchInput {
496 phase: TouchPhase::Started,
497 position: Vec2::splat(4.0),
498 window: Entity::PLACEHOLDER,
499 force: None,
500 id: 4,
501 };
502
503 clear_all(&mut touches);
504 touches.process_touch_event(&touch_event);
505
506 assert!(touches.pressed.get(&touch_event.id).is_some());
507 assert!(touches.just_pressed.get(&touch_event.id).is_some());
508
509 let moved_touch_event = TouchInput {
512 phase: TouchPhase::Moved,
513 position: Vec2::splat(5.0),
514 window: Entity::PLACEHOLDER,
515 force: None,
516 id: touch_event.id,
517 };
518
519 clear_all(&mut touches);
520 touches.process_touch_event(&moved_touch_event);
521
522 assert_eq!(
523 touches
524 .pressed
525 .get(&moved_touch_event.id)
526 .expect("Missing from pressed after move.")
527 .previous_position,
528 touch_event.position
529 );
530
531 let cancel_touch_event = TouchInput {
534 phase: TouchPhase::Canceled,
535 position: Vec2::ONE,
536 window: Entity::PLACEHOLDER,
537 force: None,
538 id: touch_event.id,
539 };
540
541 clear_all(&mut touches);
542 touches.process_touch_event(&cancel_touch_event);
543
544 assert!(touches.just_canceled.get(&touch_event.id).is_some());
545 assert!(touches.pressed.get(&touch_event.id).is_none());
546
547 let end_touch_event = TouchInput {
550 phase: TouchPhase::Ended,
551 position: Vec2::splat(4.0),
552 window: Entity::PLACEHOLDER,
553 force: None,
554 id: touch_event.id,
555 };
556
557 clear_all(&mut touches);
558 touches.process_touch_event(&touch_event);
559 touches.process_touch_event(&moved_touch_event);
560 touches.process_touch_event(&end_touch_event);
561
562 assert!(touches.just_released.get(&touch_event.id).is_some());
563 assert!(touches.pressed.get(&touch_event.id).is_none());
564 let touch = touches.just_released.get(&touch_event.id).unwrap();
565 assert_ne!(touch.previous_position, touch.position);
567 }
568
569 #[test]
571 fn touch_process_multi_event() {
572 use crate::{touch::TouchPhase, TouchInput, Touches};
573 use bevy_ecs::entity::Entity;
574 use bevy_math::Vec2;
575
576 let mut touches = Touches::default();
577
578 let started_touch_event = TouchInput {
579 phase: TouchPhase::Started,
580 position: Vec2::splat(4.0),
581 window: Entity::PLACEHOLDER,
582 force: None,
583 id: 4,
584 };
585
586 let moved_touch_event1 = TouchInput {
587 phase: TouchPhase::Moved,
588 position: Vec2::splat(5.0),
589 window: Entity::PLACEHOLDER,
590 force: None,
591 id: started_touch_event.id,
592 };
593
594 let moved_touch_event2 = TouchInput {
595 phase: TouchPhase::Moved,
596 position: Vec2::splat(6.0),
597 window: Entity::PLACEHOLDER,
598 force: None,
599 id: started_touch_event.id,
600 };
601
602 for touch in touches.pressed.values_mut() {
604 touch.previous_position = touch.position;
606 }
607 touches.process_touch_event(&started_touch_event);
608 touches.process_touch_event(&moved_touch_event1);
609 touches.process_touch_event(&moved_touch_event2);
610
611 {
612 let touch = touches.get_pressed(started_touch_event.id).unwrap();
613 assert_eq!(touch.previous_position, started_touch_event.position);
614 assert_eq!(touch.position, moved_touch_event2.position);
615 }
616
617 for touch in touches.pressed.values_mut() {
619 touch.previous_position = touch.position;
620 }
621 touches.process_touch_event(&moved_touch_event1);
622 touches.process_touch_event(&moved_touch_event2);
623 touches.process_touch_event(&moved_touch_event1);
624
625 {
626 let touch = touches.get_pressed(started_touch_event.id).unwrap();
627 assert_eq!(touch.previous_position, moved_touch_event2.position);
628 assert_eq!(touch.position, moved_touch_event1.position);
629 }
630 }
631
632 #[test]
633 fn touch_pressed() {
634 use crate::{touch::TouchPhase, TouchInput, Touches};
635 use bevy_ecs::entity::Entity;
636 use bevy_math::Vec2;
637
638 let mut touches = Touches::default();
639
640 let touch_event = TouchInput {
641 phase: TouchPhase::Started,
642 position: Vec2::splat(4.0),
643 window: Entity::PLACEHOLDER,
644 force: None,
645 id: 4,
646 };
647
648 touches.process_touch_event(&touch_event);
650
651 assert!(touches.get_pressed(touch_event.id).is_some());
652 assert!(touches.just_pressed(touch_event.id));
653 assert_eq!(touches.iter().count(), 1);
654
655 touches.clear_just_pressed(touch_event.id);
656 assert!(!touches.just_pressed(touch_event.id));
657 }
658
659 #[test]
660 fn touch_released() {
661 use crate::{touch::TouchPhase, TouchInput, Touches};
662 use bevy_ecs::entity::Entity;
663 use bevy_math::Vec2;
664
665 let mut touches = Touches::default();
666
667 let touch_event = TouchInput {
668 phase: TouchPhase::Ended,
669 position: Vec2::splat(4.0),
670 window: Entity::PLACEHOLDER,
671 force: None,
672 id: 4,
673 };
674
675 touches.process_touch_event(&touch_event);
677
678 assert!(touches.get_released(touch_event.id).is_some());
679 assert!(touches.just_released(touch_event.id));
680 assert_eq!(touches.iter_just_released().count(), 1);
681
682 touches.clear_just_released(touch_event.id);
683 assert!(!touches.just_released(touch_event.id));
684 }
685
686 #[test]
687 fn touch_canceled() {
688 use crate::{touch::TouchPhase, TouchInput, Touches};
689 use bevy_ecs::entity::Entity;
690 use bevy_math::Vec2;
691
692 let mut touches = Touches::default();
693
694 let touch_event = TouchInput {
695 phase: TouchPhase::Canceled,
696 position: Vec2::splat(4.0),
697 window: Entity::PLACEHOLDER,
698 force: None,
699 id: 4,
700 };
701
702 touches.process_touch_event(&touch_event);
704
705 assert!(touches.just_canceled(touch_event.id));
706 assert_eq!(touches.iter_just_canceled().count(), 1);
707
708 touches.clear_just_canceled(touch_event.id);
709 assert!(!touches.just_canceled(touch_event.id));
710 }
711
712 #[test]
713 fn release_touch() {
714 use crate::{touch::TouchPhase, TouchInput, Touches};
715 use bevy_ecs::entity::Entity;
716 use bevy_math::Vec2;
717
718 let mut touches = Touches::default();
719
720 let touch_event = TouchInput {
721 phase: TouchPhase::Started,
722 position: Vec2::splat(4.0),
723 window: Entity::PLACEHOLDER,
724 force: None,
725 id: 4,
726 };
727
728 touches.process_touch_event(&touch_event);
730
731 assert!(touches.get_pressed(touch_event.id).is_some());
732
733 touches.release(touch_event.id);
734 assert!(touches.get_pressed(touch_event.id).is_none());
735 assert!(touches.just_released(touch_event.id));
736 }
737
738 #[test]
739 fn release_all_touches() {
740 use crate::{touch::TouchPhase, TouchInput, Touches};
741 use bevy_ecs::entity::Entity;
742 use bevy_math::Vec2;
743
744 let mut touches = Touches::default();
745
746 let touch_pressed_event = TouchInput {
747 phase: TouchPhase::Started,
748 position: Vec2::splat(4.0),
749 window: Entity::PLACEHOLDER,
750 force: None,
751 id: 4,
752 };
753
754 let touch_moved_event = TouchInput {
755 phase: TouchPhase::Moved,
756 position: Vec2::splat(4.0),
757 window: Entity::PLACEHOLDER,
758 force: None,
759 id: 4,
760 };
761
762 touches.process_touch_event(&touch_pressed_event);
763 touches.process_touch_event(&touch_moved_event);
764
765 assert!(touches.get_pressed(touch_pressed_event.id).is_some());
766 assert!(touches.get_pressed(touch_moved_event.id).is_some());
767
768 touches.release_all();
769
770 assert!(touches.get_pressed(touch_pressed_event.id).is_none());
771 assert!(touches.just_released(touch_pressed_event.id));
772 assert!(touches.get_pressed(touch_moved_event.id).is_none());
773 assert!(touches.just_released(touch_moved_event.id));
774 }
775
776 #[test]
777 fn clear_touches() {
778 use crate::{touch::TouchPhase, TouchInput, Touches};
779 use bevy_ecs::entity::Entity;
780 use bevy_math::Vec2;
781
782 let mut touches = Touches::default();
783
784 let touch_press_event = TouchInput {
785 phase: TouchPhase::Started,
786 position: Vec2::splat(4.0),
787 window: Entity::PLACEHOLDER,
788 force: None,
789 id: 4,
790 };
791
792 let touch_canceled_event = TouchInput {
793 phase: TouchPhase::Canceled,
794 position: Vec2::splat(4.0),
795 window: Entity::PLACEHOLDER,
796 force: None,
797 id: 5,
798 };
799
800 let touch_released_event = TouchInput {
801 phase: TouchPhase::Ended,
802 position: Vec2::splat(4.0),
803 window: Entity::PLACEHOLDER,
804 force: None,
805 id: 6,
806 };
807
808 touches.process_touch_event(&touch_press_event);
810 touches.process_touch_event(&touch_canceled_event);
811 touches.process_touch_event(&touch_released_event);
812
813 assert!(touches.get_pressed(touch_press_event.id).is_some());
814 assert!(touches.just_pressed(touch_press_event.id));
815 assert!(touches.just_canceled(touch_canceled_event.id));
816 assert!(touches.just_released(touch_released_event.id));
817
818 touches.clear();
819
820 assert!(touches.get_pressed(touch_press_event.id).is_some());
821 assert!(!touches.just_pressed(touch_press_event.id));
822 assert!(!touches.just_canceled(touch_canceled_event.id));
823 assert!(!touches.just_released(touch_released_event.id));
824 }
825
826 #[test]
827 fn reset_all_touches() {
828 use crate::{touch::TouchPhase, TouchInput, Touches};
829 use bevy_ecs::entity::Entity;
830 use bevy_math::Vec2;
831
832 let mut touches = Touches::default();
833
834 let touch_press_event = TouchInput {
835 phase: TouchPhase::Started,
836 position: Vec2::splat(4.0),
837 window: Entity::PLACEHOLDER,
838 force: None,
839 id: 4,
840 };
841
842 let touch_canceled_event = TouchInput {
843 phase: TouchPhase::Canceled,
844 position: Vec2::splat(4.0),
845 window: Entity::PLACEHOLDER,
846 force: None,
847 id: 5,
848 };
849
850 let touch_released_event = TouchInput {
851 phase: TouchPhase::Ended,
852 position: Vec2::splat(4.0),
853 window: Entity::PLACEHOLDER,
854 force: None,
855 id: 6,
856 };
857
858 touches.process_touch_event(&touch_press_event);
860 touches.process_touch_event(&touch_canceled_event);
861 touches.process_touch_event(&touch_released_event);
862
863 assert!(touches.get_pressed(touch_press_event.id).is_some());
864 assert!(touches.just_pressed(touch_press_event.id));
865 assert!(touches.just_canceled(touch_canceled_event.id));
866 assert!(touches.just_released(touch_released_event.id));
867
868 touches.reset_all();
869
870 assert!(touches.get_pressed(touch_press_event.id).is_none());
871 assert!(!touches.just_pressed(touch_press_event.id));
872 assert!(!touches.just_canceled(touch_canceled_event.id));
873 assert!(!touches.just_released(touch_released_event.id));
874 }
875
876 fn clear_all(touch_state: &mut Touches) {
877 touch_state.just_pressed.clear();
878 touch_state.just_released.clear();
879 touch_state.just_canceled.clear();
880 }
881}