1#[cfg(feature = "bevy_reflect")]
4use bevy_ecs::prelude::ReflectMessage;
5use bevy_ecs::{
6 entity::Entity,
7 message::{Message, MessageReader},
8 resource::Resource,
9 system::ResMut,
10};
11use bevy_math::Vec2;
12use bevy_platform::collections::HashMap;
13#[cfg(feature = "bevy_reflect")]
14use bevy_reflect::Reflect;
15
16#[cfg(all(feature = "serialize", feature = "bevy_reflect"))]
17use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
18
19#[derive(Message, Debug, Clone, Copy, PartialEq)]
43#[cfg_attr(
44 feature = "bevy_reflect",
45 derive(Reflect),
46 reflect(Debug, PartialEq, Clone, Message)
47)]
48#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
49#[cfg_attr(
50 all(feature = "serialize", feature = "bevy_reflect"),
51 reflect(Serialize, Deserialize)
52)]
53pub struct TouchInput {
54 pub phase: TouchPhase,
56 pub position: Vec2,
58 pub window: Entity,
60 pub force: Option<ForceTouch>,
65 pub id: u64,
67}
68
69#[derive(Debug, Clone, Copy, PartialEq)]
71#[cfg_attr(
72 feature = "bevy_reflect",
73 derive(Reflect),
74 reflect(Debug, PartialEq, Clone)
75)]
76#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
77#[cfg_attr(
78 all(feature = "serialize", feature = "bevy_reflect"),
79 reflect(Serialize, Deserialize)
80)]
81pub enum ForceTouch {
82 Calibrated {
86 force: f64,
93 max_possible_force: f64,
98 altitude_angle: Option<f64>,
104 },
105 Normalized(f64),
110}
111
112#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
121#[cfg_attr(
122 feature = "bevy_reflect",
123 derive(Reflect),
124 reflect(Debug, Hash, PartialEq, Clone)
125)]
126#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
127#[cfg_attr(
128 all(feature = "serialize", feature = "bevy_reflect"),
129 reflect(Serialize, Deserialize)
130)]
131pub enum TouchPhase {
132 Started,
134 Moved,
136 Ended,
138 Canceled,
143}
144
145#[derive(Debug, Clone, Copy)]
153pub struct Touch {
154 id: u64,
156 start_position: Vec2,
158 start_force: Option<ForceTouch>,
160 previous_position: Vec2,
162 previous_force: Option<ForceTouch>,
164 position: Vec2,
166 force: Option<ForceTouch>,
168}
169
170impl Touch {
171 pub fn delta(&self) -> Vec2 {
173 self.position - self.previous_position
174 }
175
176 pub fn distance(&self) -> Vec2 {
178 self.position - self.start_position
179 }
180
181 #[inline]
183 pub fn id(&self) -> u64 {
184 self.id
185 }
186
187 #[inline]
189 pub fn start_position(&self) -> Vec2 {
190 self.start_position
191 }
192
193 #[inline]
195 pub fn start_force(&self) -> Option<ForceTouch> {
196 self.start_force
197 }
198
199 #[inline]
201 pub fn previous_position(&self) -> Vec2 {
202 self.previous_position
203 }
204
205 #[inline]
207 pub fn previous_force(&self) -> Option<ForceTouch> {
208 self.previous_force
209 }
210
211 #[inline]
213 pub fn position(&self) -> Vec2 {
214 self.position
215 }
216
217 #[inline]
219 pub fn force(&self) -> Option<ForceTouch> {
220 self.force
221 }
222}
223
224impl From<&TouchInput> for Touch {
225 fn from(input: &TouchInput) -> Touch {
226 Touch {
227 id: input.id,
228 start_position: input.position,
229 start_force: input.force,
230 previous_position: input.position,
231 previous_force: input.force,
232 position: input.position,
233 force: input.force,
234 }
235 }
236}
237
238#[derive(Debug, Clone, Default, Resource)]
249pub struct Touches {
250 pressed: HashMap<u64, Touch>,
252 just_pressed: HashMap<u64, Touch>,
254 just_released: HashMap<u64, Touch>,
256 just_canceled: HashMap<u64, Touch>,
258}
259
260impl Touches {
261 pub fn iter(&self) -> impl Iterator<Item = &Touch> + '_ {
263 self.pressed.values()
264 }
265
266 pub fn get_pressed(&self, id: u64) -> Option<&Touch> {
268 self.pressed.get(&id)
269 }
270
271 pub fn any_just_pressed(&self) -> bool {
273 !self.just_pressed.is_empty()
274 }
275
276 pub fn release(&mut self, id: u64) {
278 if let Some(touch) = self.pressed.remove(&id) {
279 self.just_released.insert(id, touch);
280 }
281 }
282
283 pub fn release_all(&mut self) {
285 self.just_released.extend(self.pressed.drain());
286 }
287
288 pub fn just_pressed(&self, id: u64) -> bool {
290 self.just_pressed.contains_key(&id)
291 }
292
293 pub fn clear_just_pressed(&mut self, id: u64) -> bool {
297 self.just_pressed.remove(&id).is_some()
298 }
299
300 pub fn iter_just_pressed(&self) -> impl Iterator<Item = &Touch> {
302 self.just_pressed.values()
303 }
304
305 pub fn get_released(&self, id: u64) -> Option<&Touch> {
307 self.just_released.get(&id)
308 }
309
310 pub fn any_just_released(&self) -> bool {
312 !self.just_released.is_empty()
313 }
314
315 pub fn just_released(&self, id: u64) -> bool {
317 self.just_released.contains_key(&id)
318 }
319
320 pub fn clear_just_released(&mut self, id: u64) -> bool {
324 self.just_released.remove(&id).is_some()
325 }
326
327 pub fn iter_just_released(&self) -> impl Iterator<Item = &Touch> {
329 self.just_released.values()
330 }
331
332 pub fn any_just_canceled(&self) -> bool {
334 !self.just_canceled.is_empty()
335 }
336
337 pub fn just_canceled(&self, id: u64) -> bool {
339 self.just_canceled.contains_key(&id)
340 }
341
342 pub fn clear_just_canceled(&mut self, id: u64) -> bool {
346 self.just_canceled.remove(&id).is_some()
347 }
348
349 pub fn iter_just_canceled(&self) -> impl Iterator<Item = &Touch> {
351 self.just_canceled.values()
352 }
353
354 pub fn first_pressed_position(&self) -> Option<Vec2> {
356 self.pressed
359 .values()
360 .next()
361 .or_else(|| self.just_pressed.values().next())
362 .map(|t| t.position)
363 }
364
365 pub fn clear(&mut self) {
369 self.just_pressed.clear();
370 self.just_released.clear();
371 self.just_canceled.clear();
372 }
373
374 pub fn reset_all(&mut self) {
378 self.pressed.clear();
379 self.just_pressed.clear();
380 self.just_released.clear();
381 self.just_canceled.clear();
382 }
383
384 fn process_touch_event(&mut self, event: &TouchInput) {
387 match event.phase {
388 TouchPhase::Started => {
389 self.pressed.insert(event.id, event.into());
390 self.just_pressed.insert(event.id, event.into());
391 }
392 TouchPhase::Moved => {
393 if let Some(mut new_touch) = self.pressed.get(&event.id).cloned() {
394 new_touch.position = event.position;
398 new_touch.force = event.force;
399 self.pressed.insert(event.id, new_touch);
400 }
401 }
402 TouchPhase::Ended => {
403 if let Some((_, v)) = self.pressed.remove_entry(&event.id) {
406 self.just_released.insert(event.id, v);
407 } else {
408 self.just_released.insert(event.id, event.into());
409 }
410 }
411 TouchPhase::Canceled => {
412 if let Some((_, v)) = self.pressed.remove_entry(&event.id) {
415 self.just_canceled.insert(event.id, v);
416 } else {
417 self.just_canceled.insert(event.id, event.into());
418 }
419 }
420 };
421 }
422}
423
424pub fn touch_screen_input_system(
436 mut touch_state: ResMut<Touches>,
437 mut touch_input_reader: MessageReader<TouchInput>,
438) {
439 if !touch_state.just_pressed.is_empty() {
440 touch_state.just_pressed.clear();
441 }
442 if !touch_state.just_released.is_empty() {
443 touch_state.just_released.clear();
444 }
445 if !touch_state.just_canceled.is_empty() {
446 touch_state.just_canceled.clear();
447 }
448
449 if !touch_input_reader.is_empty() {
450 for touch in touch_state.pressed.values_mut() {
451 touch.previous_position = touch.position;
452 touch.previous_force = touch.force;
453 }
454
455 for event in touch_input_reader.read() {
456 touch_state.process_touch_event(event);
457 }
458 }
459}
460
461#[cfg(test)]
462mod test {
463 use super::Touches;
464 use bevy_ecs::{entity::Entity, world::World};
465
466 fn dummy_window_entity() -> Entity {
467 World::default().spawn_empty().id()
468 }
469
470 #[test]
471 fn touch_update() {
472 use crate::{touch::Touch, Touches};
473 use bevy_math::Vec2;
474
475 let mut touches = Touches::default();
476
477 let touch_event = Touch {
478 id: 4,
479 start_position: Vec2::ZERO,
480 start_force: None,
481 previous_position: Vec2::ZERO,
482 previous_force: None,
483 position: Vec2::ZERO,
484 force: None,
485 };
486
487 touches.just_pressed.insert(4, touch_event);
490 touches.just_released.insert(4, touch_event);
491 touches.just_canceled.insert(4, touch_event);
492
493 clear_all(&mut touches);
494
495 assert!(touches.just_pressed.is_empty());
497 assert!(touches.just_released.is_empty());
498 assert!(touches.just_canceled.is_empty());
499 }
500
501 #[test]
502 fn touch_process() {
503 use crate::{touch::TouchPhase, TouchInput, Touches};
504 use bevy_math::Vec2;
505
506 let mut touches = Touches::default();
507
508 let touch_event = TouchInput {
511 phase: TouchPhase::Started,
512 position: Vec2::splat(4.0),
513 window: dummy_window_entity(),
514 force: None,
515 id: 4,
516 };
517
518 clear_all(&mut touches);
519 touches.process_touch_event(&touch_event);
520
521 assert!(touches.pressed.get(&touch_event.id).is_some());
522 assert!(touches.just_pressed.get(&touch_event.id).is_some());
523
524 let moved_touch_event = TouchInput {
527 phase: TouchPhase::Moved,
528 position: Vec2::splat(5.0),
529 window: dummy_window_entity(),
530 force: None,
531 id: touch_event.id,
532 };
533
534 clear_all(&mut touches);
535 touches.process_touch_event(&moved_touch_event);
536
537 assert_eq!(
538 touches
539 .pressed
540 .get(&moved_touch_event.id)
541 .expect("Missing from pressed after move.")
542 .previous_position,
543 touch_event.position
544 );
545
546 let cancel_touch_event = TouchInput {
549 phase: TouchPhase::Canceled,
550 position: Vec2::ONE,
551 window: dummy_window_entity(),
552 force: None,
553 id: touch_event.id,
554 };
555
556 clear_all(&mut touches);
557 touches.process_touch_event(&cancel_touch_event);
558
559 assert!(touches.just_canceled.get(&touch_event.id).is_some());
560 assert!(touches.pressed.get(&touch_event.id).is_none());
561
562 let end_touch_event = TouchInput {
565 phase: TouchPhase::Ended,
566 position: Vec2::splat(4.0),
567 window: dummy_window_entity(),
568 force: None,
569 id: touch_event.id,
570 };
571
572 clear_all(&mut touches);
573 touches.process_touch_event(&touch_event);
574 touches.process_touch_event(&moved_touch_event);
575 touches.process_touch_event(&end_touch_event);
576
577 assert!(touches.just_released.get(&touch_event.id).is_some());
578 assert!(touches.pressed.get(&touch_event.id).is_none());
579 let touch = touches.just_released.get(&touch_event.id).unwrap();
580 assert_ne!(touch.previous_position, touch.position);
582 }
583
584 #[test]
586 fn touch_process_multi_event() {
587 use crate::{touch::TouchPhase, TouchInput, Touches};
588 use bevy_math::Vec2;
589
590 let mut touches = Touches::default();
591
592 let started_touch_event = TouchInput {
593 phase: TouchPhase::Started,
594 position: Vec2::splat(4.0),
595 window: dummy_window_entity(),
596 force: None,
597 id: 4,
598 };
599
600 let moved_touch_event1 = TouchInput {
601 phase: TouchPhase::Moved,
602 position: Vec2::splat(5.0),
603 window: dummy_window_entity(),
604 force: None,
605 id: started_touch_event.id,
606 };
607
608 let moved_touch_event2 = TouchInput {
609 phase: TouchPhase::Moved,
610 position: Vec2::splat(6.0),
611 window: dummy_window_entity(),
612 force: None,
613 id: started_touch_event.id,
614 };
615
616 for touch in touches.pressed.values_mut() {
618 touch.previous_position = touch.position;
620 }
621 touches.process_touch_event(&started_touch_event);
622 touches.process_touch_event(&moved_touch_event1);
623 touches.process_touch_event(&moved_touch_event2);
624
625 {
626 let touch = touches.get_pressed(started_touch_event.id).unwrap();
627 assert_eq!(touch.previous_position, started_touch_event.position);
628 assert_eq!(touch.position, moved_touch_event2.position);
629 }
630
631 for touch in touches.pressed.values_mut() {
633 touch.previous_position = touch.position;
634 }
635 touches.process_touch_event(&moved_touch_event1);
636 touches.process_touch_event(&moved_touch_event2);
637 touches.process_touch_event(&moved_touch_event1);
638
639 {
640 let touch = touches.get_pressed(started_touch_event.id).unwrap();
641 assert_eq!(touch.previous_position, moved_touch_event2.position);
642 assert_eq!(touch.position, moved_touch_event1.position);
643 }
644 }
645
646 #[test]
647 fn touch_pressed() {
648 use crate::{touch::TouchPhase, TouchInput, Touches};
649 use bevy_math::Vec2;
650
651 let mut touches = Touches::default();
652
653 let touch_event = TouchInput {
654 phase: TouchPhase::Started,
655 position: Vec2::splat(4.0),
656 window: dummy_window_entity(),
657 force: None,
658 id: 4,
659 };
660
661 touches.process_touch_event(&touch_event);
663
664 assert!(touches.get_pressed(touch_event.id).is_some());
665 assert!(touches.just_pressed(touch_event.id));
666 assert_eq!(touches.iter().count(), 1);
667
668 touches.clear_just_pressed(touch_event.id);
669 assert!(!touches.just_pressed(touch_event.id));
670 }
671
672 #[test]
673 fn touch_released() {
674 use crate::{touch::TouchPhase, TouchInput, Touches};
675 use bevy_math::Vec2;
676
677 let mut touches = Touches::default();
678
679 let touch_event = TouchInput {
680 phase: TouchPhase::Ended,
681 position: Vec2::splat(4.0),
682 window: dummy_window_entity(),
683 force: None,
684 id: 4,
685 };
686
687 touches.process_touch_event(&touch_event);
689
690 assert!(touches.get_released(touch_event.id).is_some());
691 assert!(touches.just_released(touch_event.id));
692 assert_eq!(touches.iter_just_released().count(), 1);
693
694 touches.clear_just_released(touch_event.id);
695 assert!(!touches.just_released(touch_event.id));
696 }
697
698 #[test]
699 fn touch_canceled() {
700 use crate::{touch::TouchPhase, TouchInput, Touches};
701 use bevy_math::Vec2;
702
703 let mut touches = Touches::default();
704
705 let touch_event = TouchInput {
706 phase: TouchPhase::Canceled,
707 position: Vec2::splat(4.0),
708 window: dummy_window_entity(),
709 force: None,
710 id: 4,
711 };
712
713 touches.process_touch_event(&touch_event);
715
716 assert!(touches.just_canceled(touch_event.id));
717 assert_eq!(touches.iter_just_canceled().count(), 1);
718
719 touches.clear_just_canceled(touch_event.id);
720 assert!(!touches.just_canceled(touch_event.id));
721 }
722
723 #[test]
724 fn release_touch() {
725 use crate::{touch::TouchPhase, TouchInput, Touches};
726 use bevy_math::Vec2;
727
728 let mut touches = Touches::default();
729
730 let touch_event = TouchInput {
731 phase: TouchPhase::Started,
732 position: Vec2::splat(4.0),
733 window: dummy_window_entity(),
734 force: None,
735 id: 4,
736 };
737
738 touches.process_touch_event(&touch_event);
740
741 assert!(touches.get_pressed(touch_event.id).is_some());
742
743 touches.release(touch_event.id);
744 assert!(touches.get_pressed(touch_event.id).is_none());
745 assert!(touches.just_released(touch_event.id));
746 }
747
748 #[test]
749 fn release_all_touches() {
750 use crate::{touch::TouchPhase, TouchInput, Touches};
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: dummy_window_entity(),
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: dummy_window_entity(),
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_math::Vec2;
789
790 let mut touches = Touches::default();
791
792 let touch_press_event = TouchInput {
793 phase: TouchPhase::Started,
794 position: Vec2::splat(4.0),
795 window: dummy_window_entity(),
796 force: None,
797 id: 4,
798 };
799
800 let touch_canceled_event = TouchInput {
801 phase: TouchPhase::Canceled,
802 position: Vec2::splat(4.0),
803 window: dummy_window_entity(),
804 force: None,
805 id: 5,
806 };
807
808 let touch_released_event = TouchInput {
809 phase: TouchPhase::Ended,
810 position: Vec2::splat(4.0),
811 window: dummy_window_entity(),
812 force: None,
813 id: 6,
814 };
815
816 touches.process_touch_event(&touch_press_event);
818 touches.process_touch_event(&touch_canceled_event);
819 touches.process_touch_event(&touch_released_event);
820
821 assert!(touches.get_pressed(touch_press_event.id).is_some());
822 assert!(touches.just_pressed(touch_press_event.id));
823 assert!(touches.just_canceled(touch_canceled_event.id));
824 assert!(touches.just_released(touch_released_event.id));
825
826 touches.clear();
827
828 assert!(touches.get_pressed(touch_press_event.id).is_some());
829 assert!(!touches.just_pressed(touch_press_event.id));
830 assert!(!touches.just_canceled(touch_canceled_event.id));
831 assert!(!touches.just_released(touch_released_event.id));
832 }
833
834 #[test]
835 fn reset_all_touches() {
836 use crate::{touch::TouchPhase, TouchInput, Touches};
837 use bevy_math::Vec2;
838
839 let mut touches = Touches::default();
840
841 let touch_press_event = TouchInput {
842 phase: TouchPhase::Started,
843 position: Vec2::splat(4.0),
844 window: dummy_window_entity(),
845 force: None,
846 id: 4,
847 };
848
849 let touch_canceled_event = TouchInput {
850 phase: TouchPhase::Canceled,
851 position: Vec2::splat(4.0),
852 window: dummy_window_entity(),
853 force: None,
854 id: 5,
855 };
856
857 let touch_released_event = TouchInput {
858 phase: TouchPhase::Ended,
859 position: Vec2::splat(4.0),
860 window: dummy_window_entity(),
861 force: None,
862 id: 6,
863 };
864
865 touches.process_touch_event(&touch_press_event);
867 touches.process_touch_event(&touch_canceled_event);
868 touches.process_touch_event(&touch_released_event);
869
870 assert!(touches.get_pressed(touch_press_event.id).is_some());
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 touches.reset_all();
876
877 assert!(touches.get_pressed(touch_press_event.id).is_none());
878 assert!(!touches.just_pressed(touch_press_event.id));
879 assert!(!touches.just_canceled(touch_canceled_event.id));
880 assert!(!touches.just_released(touch_released_event.id));
881 }
882
883 fn clear_all(touch_state: &mut Touches) {
884 touch_state.just_pressed.clear();
885 touch_state.just_released.clear();
886 touch_state.just_canceled.clear();
887 }
888}