Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_input/src/touch.rs
6595 views
1
//! The touch input functionality.
2
3
use bevy_ecs::{
4
entity::Entity,
5
event::{BufferedEvent, EventReader},
6
resource::Resource,
7
system::ResMut,
8
};
9
use bevy_math::Vec2;
10
use bevy_platform::collections::HashMap;
11
#[cfg(feature = "bevy_reflect")]
12
use bevy_reflect::Reflect;
13
14
#[cfg(all(feature = "serialize", feature = "bevy_reflect"))]
15
use 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(BufferedEvent, 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
)]
51
pub 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
)]
79
pub 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
)]
129
pub 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)]
151
pub 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
168
impl 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
222
impl 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)]
247
pub 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
258
impl 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`].
433
pub 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)]
460
mod 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
}
891
892