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
465 #[test]
466 fn touch_update() {
467 use crate::{touch::Touch, Touches};
468 use bevy_math::Vec2;
469
470 let mut touches = Touches::default();
471
472 let touch_event = Touch {
473 id: 4,
474 start_position: Vec2::ZERO,
475 start_force: None,
476 previous_position: Vec2::ZERO,
477 previous_force: None,
478 position: Vec2::ZERO,
479 force: None,
480 };
481
482 touches.just_pressed.insert(4, touch_event);
485 touches.just_released.insert(4, touch_event);
486 touches.just_canceled.insert(4, touch_event);
487
488 clear_all(&mut touches);
489
490 assert!(touches.just_pressed.is_empty());
492 assert!(touches.just_released.is_empty());
493 assert!(touches.just_canceled.is_empty());
494 }
495
496 #[test]
497 fn touch_process() {
498 use crate::{touch::TouchPhase, TouchInput, Touches};
499 use bevy_ecs::entity::Entity;
500 use bevy_math::Vec2;
501
502 let mut touches = Touches::default();
503
504 let touch_event = TouchInput {
507 phase: TouchPhase::Started,
508 position: Vec2::splat(4.0),
509 window: Entity::PLACEHOLDER,
510 force: None,
511 id: 4,
512 };
513
514 clear_all(&mut touches);
515 touches.process_touch_event(&touch_event);
516
517 assert!(touches.pressed.get(&touch_event.id).is_some());
518 assert!(touches.just_pressed.get(&touch_event.id).is_some());
519
520 let moved_touch_event = TouchInput {
523 phase: TouchPhase::Moved,
524 position: Vec2::splat(5.0),
525 window: Entity::PLACEHOLDER,
526 force: None,
527 id: touch_event.id,
528 };
529
530 clear_all(&mut touches);
531 touches.process_touch_event(&moved_touch_event);
532
533 assert_eq!(
534 touches
535 .pressed
536 .get(&moved_touch_event.id)
537 .expect("Missing from pressed after move.")
538 .previous_position,
539 touch_event.position
540 );
541
542 let cancel_touch_event = TouchInput {
545 phase: TouchPhase::Canceled,
546 position: Vec2::ONE,
547 window: Entity::PLACEHOLDER,
548 force: None,
549 id: touch_event.id,
550 };
551
552 clear_all(&mut touches);
553 touches.process_touch_event(&cancel_touch_event);
554
555 assert!(touches.just_canceled.get(&touch_event.id).is_some());
556 assert!(touches.pressed.get(&touch_event.id).is_none());
557
558 let end_touch_event = TouchInput {
561 phase: TouchPhase::Ended,
562 position: Vec2::splat(4.0),
563 window: Entity::PLACEHOLDER,
564 force: None,
565 id: touch_event.id,
566 };
567
568 clear_all(&mut touches);
569 touches.process_touch_event(&touch_event);
570 touches.process_touch_event(&moved_touch_event);
571 touches.process_touch_event(&end_touch_event);
572
573 assert!(touches.just_released.get(&touch_event.id).is_some());
574 assert!(touches.pressed.get(&touch_event.id).is_none());
575 let touch = touches.just_released.get(&touch_event.id).unwrap();
576 assert_ne!(touch.previous_position, touch.position);
578 }
579
580 #[test]
582 fn touch_process_multi_event() {
583 use crate::{touch::TouchPhase, TouchInput, Touches};
584 use bevy_ecs::entity::Entity;
585 use bevy_math::Vec2;
586
587 let mut touches = Touches::default();
588
589 let started_touch_event = TouchInput {
590 phase: TouchPhase::Started,
591 position: Vec2::splat(4.0),
592 window: Entity::PLACEHOLDER,
593 force: None,
594 id: 4,
595 };
596
597 let moved_touch_event1 = TouchInput {
598 phase: TouchPhase::Moved,
599 position: Vec2::splat(5.0),
600 window: Entity::PLACEHOLDER,
601 force: None,
602 id: started_touch_event.id,
603 };
604
605 let moved_touch_event2 = TouchInput {
606 phase: TouchPhase::Moved,
607 position: Vec2::splat(6.0),
608 window: Entity::PLACEHOLDER,
609 force: None,
610 id: started_touch_event.id,
611 };
612
613 for touch in touches.pressed.values_mut() {
615 touch.previous_position = touch.position;
617 }
618 touches.process_touch_event(&started_touch_event);
619 touches.process_touch_event(&moved_touch_event1);
620 touches.process_touch_event(&moved_touch_event2);
621
622 {
623 let touch = touches.get_pressed(started_touch_event.id).unwrap();
624 assert_eq!(touch.previous_position, started_touch_event.position);
625 assert_eq!(touch.position, moved_touch_event2.position);
626 }
627
628 for touch in touches.pressed.values_mut() {
630 touch.previous_position = touch.position;
631 }
632 touches.process_touch_event(&moved_touch_event1);
633 touches.process_touch_event(&moved_touch_event2);
634 touches.process_touch_event(&moved_touch_event1);
635
636 {
637 let touch = touches.get_pressed(started_touch_event.id).unwrap();
638 assert_eq!(touch.previous_position, moved_touch_event2.position);
639 assert_eq!(touch.position, moved_touch_event1.position);
640 }
641 }
642
643 #[test]
644 fn touch_pressed() {
645 use crate::{touch::TouchPhase, TouchInput, Touches};
646 use bevy_ecs::entity::Entity;
647 use bevy_math::Vec2;
648
649 let mut touches = Touches::default();
650
651 let touch_event = TouchInput {
652 phase: TouchPhase::Started,
653 position: Vec2::splat(4.0),
654 window: Entity::PLACEHOLDER,
655 force: None,
656 id: 4,
657 };
658
659 touches.process_touch_event(&touch_event);
661
662 assert!(touches.get_pressed(touch_event.id).is_some());
663 assert!(touches.just_pressed(touch_event.id));
664 assert_eq!(touches.iter().count(), 1);
665
666 touches.clear_just_pressed(touch_event.id);
667 assert!(!touches.just_pressed(touch_event.id));
668 }
669
670 #[test]
671 fn touch_released() {
672 use crate::{touch::TouchPhase, TouchInput, Touches};
673 use bevy_ecs::entity::Entity;
674 use bevy_math::Vec2;
675
676 let mut touches = Touches::default();
677
678 let touch_event = TouchInput {
679 phase: TouchPhase::Ended,
680 position: Vec2::splat(4.0),
681 window: Entity::PLACEHOLDER,
682 force: None,
683 id: 4,
684 };
685
686 touches.process_touch_event(&touch_event);
688
689 assert!(touches.get_released(touch_event.id).is_some());
690 assert!(touches.just_released(touch_event.id));
691 assert_eq!(touches.iter_just_released().count(), 1);
692
693 touches.clear_just_released(touch_event.id);
694 assert!(!touches.just_released(touch_event.id));
695 }
696
697 #[test]
698 fn touch_canceled() {
699 use crate::{touch::TouchPhase, TouchInput, Touches};
700 use bevy_ecs::entity::Entity;
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: Entity::PLACEHOLDER,
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_ecs::entity::Entity;
727 use bevy_math::Vec2;
728
729 let mut touches = Touches::default();
730
731 let touch_event = TouchInput {
732 phase: TouchPhase::Started,
733 position: Vec2::splat(4.0),
734 window: Entity::PLACEHOLDER,
735 force: None,
736 id: 4,
737 };
738
739 touches.process_touch_event(&touch_event);
741
742 assert!(touches.get_pressed(touch_event.id).is_some());
743
744 touches.release(touch_event.id);
745 assert!(touches.get_pressed(touch_event.id).is_none());
746 assert!(touches.just_released(touch_event.id));
747 }
748
749 #[test]
750 fn release_all_touches() {
751 use crate::{touch::TouchPhase, TouchInput, Touches};
752 use bevy_ecs::entity::Entity;
753 use bevy_math::Vec2;
754
755 let mut touches = Touches::default();
756
757 let touch_pressed_event = TouchInput {
758 phase: TouchPhase::Started,
759 position: Vec2::splat(4.0),
760 window: Entity::PLACEHOLDER,
761 force: None,
762 id: 4,
763 };
764
765 let touch_moved_event = TouchInput {
766 phase: TouchPhase::Moved,
767 position: Vec2::splat(4.0),
768 window: Entity::PLACEHOLDER,
769 force: None,
770 id: 4,
771 };
772
773 touches.process_touch_event(&touch_pressed_event);
774 touches.process_touch_event(&touch_moved_event);
775
776 assert!(touches.get_pressed(touch_pressed_event.id).is_some());
777 assert!(touches.get_pressed(touch_moved_event.id).is_some());
778
779 touches.release_all();
780
781 assert!(touches.get_pressed(touch_pressed_event.id).is_none());
782 assert!(touches.just_released(touch_pressed_event.id));
783 assert!(touches.get_pressed(touch_moved_event.id).is_none());
784 assert!(touches.just_released(touch_moved_event.id));
785 }
786
787 #[test]
788 fn clear_touches() {
789 use crate::{touch::TouchPhase, TouchInput, Touches};
790 use bevy_ecs::entity::Entity;
791 use bevy_math::Vec2;
792
793 let mut touches = Touches::default();
794
795 let touch_press_event = TouchInput {
796 phase: TouchPhase::Started,
797 position: Vec2::splat(4.0),
798 window: Entity::PLACEHOLDER,
799 force: None,
800 id: 4,
801 };
802
803 let touch_canceled_event = TouchInput {
804 phase: TouchPhase::Canceled,
805 position: Vec2::splat(4.0),
806 window: Entity::PLACEHOLDER,
807 force: None,
808 id: 5,
809 };
810
811 let touch_released_event = TouchInput {
812 phase: TouchPhase::Ended,
813 position: Vec2::splat(4.0),
814 window: Entity::PLACEHOLDER,
815 force: None,
816 id: 6,
817 };
818
819 touches.process_touch_event(&touch_press_event);
821 touches.process_touch_event(&touch_canceled_event);
822 touches.process_touch_event(&touch_released_event);
823
824 assert!(touches.get_pressed(touch_press_event.id).is_some());
825 assert!(touches.just_pressed(touch_press_event.id));
826 assert!(touches.just_canceled(touch_canceled_event.id));
827 assert!(touches.just_released(touch_released_event.id));
828
829 touches.clear();
830
831 assert!(touches.get_pressed(touch_press_event.id).is_some());
832 assert!(!touches.just_pressed(touch_press_event.id));
833 assert!(!touches.just_canceled(touch_canceled_event.id));
834 assert!(!touches.just_released(touch_released_event.id));
835 }
836
837 #[test]
838 fn reset_all_touches() {
839 use crate::{touch::TouchPhase, TouchInput, Touches};
840 use bevy_ecs::entity::Entity;
841 use bevy_math::Vec2;
842
843 let mut touches = Touches::default();
844
845 let touch_press_event = TouchInput {
846 phase: TouchPhase::Started,
847 position: Vec2::splat(4.0),
848 window: Entity::PLACEHOLDER,
849 force: None,
850 id: 4,
851 };
852
853 let touch_canceled_event = TouchInput {
854 phase: TouchPhase::Canceled,
855 position: Vec2::splat(4.0),
856 window: Entity::PLACEHOLDER,
857 force: None,
858 id: 5,
859 };
860
861 let touch_released_event = TouchInput {
862 phase: TouchPhase::Ended,
863 position: Vec2::splat(4.0),
864 window: Entity::PLACEHOLDER,
865 force: None,
866 id: 6,
867 };
868
869 touches.process_touch_event(&touch_press_event);
871 touches.process_touch_event(&touch_canceled_event);
872 touches.process_touch_event(&touch_released_event);
873
874 assert!(touches.get_pressed(touch_press_event.id).is_some());
875 assert!(touches.just_pressed(touch_press_event.id));
876 assert!(touches.just_canceled(touch_canceled_event.id));
877 assert!(touches.just_released(touch_released_event.id));
878
879 touches.reset_all();
880
881 assert!(touches.get_pressed(touch_press_event.id).is_none());
882 assert!(!touches.just_pressed(touch_press_event.id));
883 assert!(!touches.just_canceled(touch_canceled_event.id));
884 assert!(!touches.just_released(touch_released_event.id));
885 }
886
887 fn clear_all(touch_state: &mut Touches) {
888 touch_state.just_pressed.clear();
889 touch_state.just_released.clear();
890 touch_state.just_canceled.clear();
891 }
892}