Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend Touches with clear and reset methods #10930

Merged
merged 7 commits into from
Jan 4, 2024
225 changes: 225 additions & 0 deletions crates/bevy_input/src/touch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,11 +255,30 @@ impl Touches {
!self.just_pressed.is_empty()
}

/// Register a release for a given touch input.
pub fn release(&mut self, id: u64) {
if let Some(touch) = self.pressed.remove(&id) {
self.just_released.insert(id, touch);
}
}

/// Registers a release for all currently pressed touch inputs.
pub fn release_all(&mut self) {
self.just_released.extend(self.pressed.drain());
}

/// Returns `true` if the input corresponding to the `id` has just been pressed.
pub fn just_pressed(&self, id: u64) -> bool {
self.just_pressed.contains_key(&id)
}

/// Clears the `just_pressed` state of the touch input and returns `true` if the touch input has just been pressed.
///
/// Future calls to [`Touches::just_pressed`] for the given touch input will return false until a new press event occurs.
pub fn clear_just_pressed(&mut self, id: u64) -> bool {
self.just_pressed.remove(&id).is_some()
}

/// An iterator visiting every just pressed [`Touch`] input in arbitrary order.
pub fn iter_just_pressed(&self) -> impl Iterator<Item = &Touch> {
self.just_pressed.values()
Expand All @@ -280,6 +299,13 @@ impl Touches {
self.just_released.contains_key(&id)
}

/// Clears the `just_released` state of the touch input and returns `true` if the touch input has just been released.
///
/// Future calls to [`Touches::just_released`] for the given touch input will return false until a new release event occurs.
pub fn clear_just_released(&mut self, id: u64) -> bool {
self.just_released.remove(&id).is_some()
}

/// An iterator visiting every just released [`Touch`] input in arbitrary order.
pub fn iter_just_released(&self) -> impl Iterator<Item = &Touch> {
self.just_released.values()
Expand All @@ -295,6 +321,13 @@ impl Touches {
self.just_canceled.contains_key(&id)
}

/// Clears the `just_canceled` state of the touch input and returns `true` if the touch input has just been canceled.
///
/// Future calls to [`Touches::just_canceled`] for the given touch input will return false until a new cancel event occurs.
pub fn clear_just_canceled(&mut self, id: u64) -> bool {
self.just_canceled.remove(&id).is_some()
}

/// An iterator visiting every just canceled [`Touch`] input in arbitrary order.
pub fn iter_just_canceled(&self) -> impl Iterator<Item = &Touch> {
self.just_canceled.values()
Expand All @@ -305,6 +338,25 @@ impl Touches {
self.pressed.values().next().map(|t| t.position)
}

/// Clears `just_pressed`, `just_released`, and `just_canceled` data for every touch input.
///
/// See also [`Touches::reset_all`] for a full reset.
pub fn clear(&mut self) {
self.just_pressed.clear();
self.just_released.clear();
self.just_canceled.clear();
}

/// Clears `pressed`, `just_pressed`, `just_released`, and `just_canceled` data for every touch input.
///
/// See also [`Touches::clear`] for clearing only touches that have just been pressed, released or canceled.
pub fn reset_all(&mut self) {
self.pressed.clear();
self.just_pressed.clear();
self.just_released.clear();
self.just_canceled.clear();
}

/// Processes a [`TouchInput`] event by updating the `pressed`, `just_pressed`,
/// `just_released`, and `just_canceled` collections.
fn process_touch_event(&mut self, event: &TouchInput) {
Expand Down Expand Up @@ -514,6 +566,9 @@ mod test {
assert!(touches.get_pressed(touch_event.id).is_some());
assert!(touches.just_pressed(touch_event.id));
assert_eq!(touches.iter().count(), 1);

touches.clear_just_pressed(touch_event.id);
assert!(!touches.just_pressed(touch_event.id));
}

#[test]
Expand All @@ -538,6 +593,9 @@ mod test {
assert!(touches.get_released(touch_event.id).is_some());
assert!(touches.just_released(touch_event.id));
assert_eq!(touches.iter_just_released().count(), 1);

touches.clear_just_released(touch_event.id);
assert!(!touches.just_released(touch_event.id));
}

#[test]
Expand All @@ -561,5 +619,172 @@ mod test {

assert!(touches.just_canceled(touch_event.id));
assert_eq!(touches.iter_just_canceled().count(), 1);

touches.clear_just_canceled(touch_event.id);
assert!(!touches.just_canceled(touch_event.id));
}

#[test]
fn release_touch() {
use crate::{touch::TouchPhase, TouchInput, Touches};
use bevy_ecs::entity::Entity;
use bevy_math::Vec2;

let mut touches = Touches::default();

let touch_event = TouchInput {
phase: TouchPhase::Started,
position: Vec2::splat(4.0),
window: Entity::PLACEHOLDER,
force: None,
id: 4,
};

// Register the touch and test that it was registered correctly
touches.process_touch_event(&touch_event);

assert!(touches.get_pressed(touch_event.id).is_some());

touches.release(touch_event.id);
assert!(touches.get_pressed(touch_event.id).is_none());
assert!(touches.just_released(touch_event.id));
}

#[test]
fn release_all_touches() {
use crate::{touch::TouchPhase, TouchInput, Touches};
use bevy_ecs::entity::Entity;
use bevy_math::Vec2;

let mut touches = Touches::default();

let touch_pressed_event = TouchInput {
phase: TouchPhase::Started,
position: Vec2::splat(4.0),
window: Entity::PLACEHOLDER,
force: None,
id: 4,
};

let touch_moved_event = TouchInput {
phase: TouchPhase::Moved,
position: Vec2::splat(4.0),
window: Entity::PLACEHOLDER,
force: None,
id: 4,
};

touches.process_touch_event(&touch_pressed_event);
touches.process_touch_event(&touch_moved_event);

assert!(touches.get_pressed(touch_pressed_event.id).is_some());
assert!(touches.get_pressed(touch_moved_event.id).is_some());

touches.release_all();

assert!(touches.get_pressed(touch_pressed_event.id).is_none());
assert!(touches.just_released(touch_pressed_event.id));
assert!(touches.get_pressed(touch_moved_event.id).is_none());
assert!(touches.just_released(touch_moved_event.id));
}

#[test]
fn clear_touches() {
use crate::{touch::TouchPhase, TouchInput, Touches};
use bevy_ecs::entity::Entity;
use bevy_math::Vec2;

let mut touches = Touches::default();

let touch_press_event = TouchInput {
phase: TouchPhase::Started,
position: Vec2::splat(4.0),
window: Entity::PLACEHOLDER,
force: None,
id: 4,
};

let touch_canceled_event = TouchInput {
phase: TouchPhase::Canceled,
position: Vec2::splat(4.0),
window: Entity::PLACEHOLDER,
force: None,
id: 5,
};

let touch_released_event = TouchInput {
phase: TouchPhase::Ended,
position: Vec2::splat(4.0),
window: Entity::PLACEHOLDER,
force: None,
id: 6,
};

// Register the touches and test that it was registered correctly
touches.process_touch_event(&touch_press_event);
touches.process_touch_event(&touch_canceled_event);
touches.process_touch_event(&touch_released_event);

assert!(touches.get_pressed(touch_press_event.id).is_some());
assert!(touches.just_pressed(touch_press_event.id));
assert!(touches.just_canceled(touch_canceled_event.id));
assert!(touches.just_released(touch_released_event.id));

touches.clear();

assert!(touches.get_pressed(touch_press_event.id).is_some());
assert!(!touches.just_pressed(touch_press_event.id));
assert!(!touches.just_canceled(touch_canceled_event.id));
assert!(!touches.just_released(touch_released_event.id));
}

#[test]
fn reset_all_touches() {
use crate::{touch::TouchPhase, TouchInput, Touches};
use bevy_ecs::entity::Entity;
use bevy_math::Vec2;

let mut touches = Touches::default();

let touch_press_event = TouchInput {
phase: TouchPhase::Started,
position: Vec2::splat(4.0),
window: Entity::PLACEHOLDER,
force: None,
id: 4,
};

let touch_canceled_event = TouchInput {
phase: TouchPhase::Canceled,
position: Vec2::splat(4.0),
window: Entity::PLACEHOLDER,
force: None,
id: 5,
};

let touch_released_event = TouchInput {
phase: TouchPhase::Ended,
position: Vec2::splat(4.0),
window: Entity::PLACEHOLDER,
force: None,
id: 6,
};

// Register the touches and test that it was registered correctly
touches.process_touch_event(&touch_press_event);
touches.process_touch_event(&touch_canceled_event);
touches.process_touch_event(&touch_released_event);

assert!(touches.get_pressed(touch_press_event.id).is_some());
assert!(touches.just_pressed(touch_press_event.id));
assert!(touches.just_canceled(touch_canceled_event.id));
assert!(touches.just_released(touch_released_event.id));

touches.reset_all();

assert!(touches.get_pressed(touch_press_event.id).is_none());
assert!(!touches.just_pressed(touch_press_event.id));
assert!(!touches.just_canceled(touch_canceled_event.id));
assert!(!touches.just_released(touch_released_event.id));
}
}