mirror of
https://github.com/bevyengine/bevy
synced 2025-02-16 14:08:32 +00:00
rename touchpad to gesture, and add new gestures (#13660)
# Objective - With the recent winit update, touchpad specific events can also be triggered on mobile ## Solution - Rename them to gestures and add support for the new ones ## Testing - Tested on the mobile example on iOS https://github.com/bevyengine/bevy/assets/8672791/da4ed23f-ff0a-41b2-9dcd-726e8546bef2 ## Migration Guide - `TouchpadMagnify` has been renamed to `PinchGesture` - `TouchpadRotate` has been renamed to `RotationGesture ` --------- Co-authored-by: mike <ramirezmike2@gmail.com>
This commit is contained in:
parent
58a0c1336c
commit
df57850310
9 changed files with 217 additions and 67 deletions
73
crates/bevy_input/src/gestures.rs
Normal file
73
crates/bevy_input/src/gestures.rs
Normal file
|
@ -0,0 +1,73 @@
|
|||
//! Gestures functionality, from touchscreens and touchpads.
|
||||
|
||||
use bevy_ecs::event::Event;
|
||||
use bevy_math::Vec2;
|
||||
use bevy_reflect::Reflect;
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
|
||||
|
||||
/// Two-finger pinch gesture, often used for magnifications.
|
||||
///
|
||||
/// Positive delta values indicate magnification (zooming in) and
|
||||
/// negative delta values indicate shrinking (zooming out).
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - Only available on **`macOS`** and **`iOS`**.
|
||||
/// - On **`iOS`**, must be enabled first
|
||||
#[derive(Event, Debug, Clone, Copy, PartialEq, Reflect)]
|
||||
#[reflect(Debug, PartialEq)]
|
||||
#[cfg_attr(
|
||||
feature = "serialize",
|
||||
derive(serde::Serialize, serde::Deserialize),
|
||||
reflect(Serialize, Deserialize)
|
||||
)]
|
||||
pub struct PinchGesture(pub f32);
|
||||
|
||||
/// Two-finger rotation gesture.
|
||||
///
|
||||
/// Positive delta values indicate rotation counterclockwise and
|
||||
/// negative delta values indicate rotation clockwise.
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - Only available on **`macOS`** and **`iOS`**.
|
||||
/// - On **`iOS`**, must be enabled first
|
||||
#[derive(Event, Debug, Clone, Copy, PartialEq, Reflect)]
|
||||
#[reflect(Debug, PartialEq)]
|
||||
#[cfg_attr(
|
||||
feature = "serialize",
|
||||
derive(serde::Serialize, serde::Deserialize),
|
||||
reflect(Serialize, Deserialize)
|
||||
)]
|
||||
pub struct RotationGesture(pub f32);
|
||||
|
||||
/// Double tap gesture.
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - Only available on **`macOS`** and **`iOS`**.
|
||||
/// - On **`iOS`**, must be enabled first
|
||||
#[derive(Event, Debug, Clone, Copy, PartialEq, Reflect)]
|
||||
#[reflect(Debug, PartialEq)]
|
||||
#[cfg_attr(
|
||||
feature = "serialize",
|
||||
derive(serde::Serialize, serde::Deserialize),
|
||||
reflect(Serialize, Deserialize)
|
||||
)]
|
||||
pub struct DoubleTapGesture;
|
||||
|
||||
/// Pan gesture.
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - On **`iOS`**, must be enabled first
|
||||
#[derive(Event, Debug, Clone, Copy, PartialEq, Reflect)]
|
||||
#[reflect(Debug, PartialEq)]
|
||||
#[cfg_attr(
|
||||
feature = "serialize",
|
||||
derive(serde::Serialize, serde::Deserialize),
|
||||
reflect(Serialize, Deserialize)
|
||||
)]
|
||||
pub struct PanGesture(pub Vec2);
|
|
@ -16,10 +16,10 @@ mod button_input;
|
|||
/// Common run conditions
|
||||
pub mod common_conditions;
|
||||
pub mod gamepad;
|
||||
pub mod gestures;
|
||||
pub mod keyboard;
|
||||
pub mod mouse;
|
||||
pub mod touch;
|
||||
pub mod touchpad;
|
||||
|
||||
pub use axis::*;
|
||||
pub use button_input::*;
|
||||
|
@ -41,10 +41,10 @@ pub mod prelude {
|
|||
use bevy_app::prelude::*;
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_reflect::Reflect;
|
||||
use gestures::*;
|
||||
use keyboard::{keyboard_input_system, KeyCode, KeyboardInput};
|
||||
use mouse::{mouse_button_input_system, MouseButton, MouseButtonInput, MouseMotion, MouseWheel};
|
||||
use touch::{touch_screen_input_system, TouchInput, Touches};
|
||||
use touchpad::{TouchpadMagnify, TouchpadRotate};
|
||||
|
||||
use gamepad::{
|
||||
gamepad_axis_event_system, gamepad_button_event_system, gamepad_connection_system,
|
||||
|
@ -77,8 +77,10 @@ impl Plugin for InputPlugin {
|
|||
.add_event::<MouseWheel>()
|
||||
.init_resource::<ButtonInput<MouseButton>>()
|
||||
.add_systems(PreUpdate, mouse_button_input_system.in_set(InputSystem))
|
||||
.add_event::<TouchpadMagnify>()
|
||||
.add_event::<TouchpadRotate>()
|
||||
.add_event::<PinchGesture>()
|
||||
.add_event::<RotationGesture>()
|
||||
.add_event::<DoubleTapGesture>()
|
||||
.add_event::<PanGesture>()
|
||||
// gamepad
|
||||
.add_event::<GamepadConnectionEvent>()
|
||||
.add_event::<GamepadButtonChangedEvent>()
|
||||
|
@ -114,8 +116,10 @@ impl Plugin for InputPlugin {
|
|||
app.register_type::<ButtonState>()
|
||||
.register_type::<KeyboardInput>()
|
||||
.register_type::<MouseButtonInput>()
|
||||
.register_type::<TouchpadMagnify>()
|
||||
.register_type::<TouchpadRotate>()
|
||||
.register_type::<PinchGesture>()
|
||||
.register_type::<RotationGesture>()
|
||||
.register_type::<DoubleTapGesture>()
|
||||
.register_type::<PanGesture>()
|
||||
.register_type::<TouchInput>()
|
||||
.register_type::<GamepadEvent>()
|
||||
.register_type::<GamepadButtonInput>()
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
//! The touchpad input functionality.
|
||||
|
||||
use bevy_ecs::event::Event;
|
||||
use bevy_reflect::Reflect;
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
|
||||
|
||||
/// Touchpad magnification event with two-finger pinch gesture.
|
||||
///
|
||||
/// Positive delta values indicate magnification (zooming in) and
|
||||
/// negative delta values indicate shrinking (zooming out).
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - Only available on **`macOS`**.
|
||||
#[derive(Event, Debug, Clone, Copy, PartialEq, Reflect)]
|
||||
#[reflect(Debug, PartialEq)]
|
||||
#[cfg_attr(
|
||||
feature = "serialize",
|
||||
derive(serde::Serialize, serde::Deserialize),
|
||||
reflect(Serialize, Deserialize)
|
||||
)]
|
||||
pub struct TouchpadMagnify(pub f32);
|
||||
|
||||
/// Touchpad rotation event with two-finger rotation gesture.
|
||||
///
|
||||
/// Positive delta values indicate rotation counterclockwise and
|
||||
/// negative delta values indicate rotation clockwise.
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - Only available on **`macOS`**.
|
||||
#[derive(Event, Debug, Clone, Copy, PartialEq, Reflect)]
|
||||
#[reflect(Debug, PartialEq)]
|
||||
#[cfg_attr(
|
||||
feature = "serialize",
|
||||
derive(serde::Serialize, serde::Deserialize),
|
||||
reflect(Serialize, Deserialize)
|
||||
)]
|
||||
pub struct TouchpadRotate(pub f32);
|
|
@ -281,6 +281,33 @@ pub struct Window {
|
|||
/// [`wgpu::SurfaceConfiguration::desired_maximum_frame_latency`]:
|
||||
/// https://docs.rs/wgpu/latest/wgpu/type.SurfaceConfiguration.html#structfield.desired_maximum_frame_latency
|
||||
pub desired_maximum_frame_latency: Option<NonZeroU32>,
|
||||
/// Sets whether this window recognizes [`PinchGesture`]
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - Only used on iOS.
|
||||
/// - On macOS, they are recognized by default and can't be disabled.
|
||||
pub recognize_pinch_gesture: bool,
|
||||
/// Sets whether this window recognizes [`RotationGesture`]
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - Only used on iOS.
|
||||
/// - On macOS, they are recognized by default and can't be disabled.
|
||||
pub recognize_rotation_gesture: bool,
|
||||
/// Sets whether this window recognizes [`DoubleTapGesture`]
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - Only used on iOS.
|
||||
/// - On macOS, they are recognized by default and can't be disabled.
|
||||
pub recognize_doubletap_gesture: bool,
|
||||
/// Sets whether this window recognizes [`PanGesture`], with a number of fingers between the first value and the last.
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - Only used on iOS.
|
||||
pub recognize_pan_gesture: Option<(u8, u8)>,
|
||||
}
|
||||
|
||||
impl Default for Window {
|
||||
|
@ -311,6 +338,10 @@ impl Default for Window {
|
|||
visible: true,
|
||||
skip_taskbar: false,
|
||||
desired_maximum_frame_latency: None,
|
||||
recognize_pinch_gesture: false,
|
||||
recognize_rotation_gesture: false,
|
||||
recognize_doubletap_gesture: false,
|
||||
recognize_pan_gesture: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ use bevy_ecs::prelude::*;
|
|||
use bevy_ecs::system::SystemState;
|
||||
use bevy_ecs::world::FromWorld;
|
||||
use bevy_input::{
|
||||
gestures::*,
|
||||
mouse::{MouseButtonInput, MouseMotion, MouseScrollUnit, MouseWheel},
|
||||
touchpad::{TouchpadMagnify, TouchpadRotate},
|
||||
};
|
||||
use bevy_log::{error, trace, warn};
|
||||
use bevy_math::{ivec2, DVec2, Vec2};
|
||||
|
@ -264,10 +264,19 @@ impl<T: Event> ApplicationHandler<T> for WinitAppRunnerState<T> {
|
|||
});
|
||||
}
|
||||
WindowEvent::PinchGesture { delta, .. } => {
|
||||
self.winit_events.send(TouchpadMagnify(delta as f32));
|
||||
self.winit_events.send(PinchGesture(delta as f32));
|
||||
}
|
||||
WindowEvent::RotationGesture { delta, .. } => {
|
||||
self.winit_events.send(TouchpadRotate(delta));
|
||||
self.winit_events.send(RotationGesture(delta));
|
||||
}
|
||||
WindowEvent::DoubleTapGesture { .. } => {
|
||||
self.winit_events.send(DoubleTapGesture);
|
||||
}
|
||||
WindowEvent::PanGesture { delta, .. } => {
|
||||
self.winit_events.send(PanGesture(Vec2 {
|
||||
x: delta.x,
|
||||
y: delta.y,
|
||||
}));
|
||||
}
|
||||
WindowEvent::MouseWheel { delta, .. } => match delta {
|
||||
event::MouseScrollDelta::LineDelta(x, y) => {
|
||||
|
@ -674,10 +683,16 @@ impl<T: Event> WinitAppRunnerState<T> {
|
|||
WinitEvent::MouseWheel(e) => {
|
||||
world.send_event(e);
|
||||
}
|
||||
WinitEvent::TouchpadMagnify(e) => {
|
||||
WinitEvent::PinchGesture(e) => {
|
||||
world.send_event(e);
|
||||
}
|
||||
WinitEvent::TouchpadRotate(e) => {
|
||||
WinitEvent::RotationGesture(e) => {
|
||||
world.send_event(e);
|
||||
}
|
||||
WinitEvent::DoubleTapGesture(e) => {
|
||||
world.send_event(e);
|
||||
}
|
||||
WinitEvent::PanGesture(e) => {
|
||||
world.send_event(e);
|
||||
}
|
||||
WinitEvent::TouchInput(e) => {
|
||||
|
|
|
@ -16,6 +16,8 @@ use winit::dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize};
|
|||
use winit::event_loop::ActiveEventLoop;
|
||||
|
||||
use bevy_ecs::query::With;
|
||||
#[cfg(target_os = "ios")]
|
||||
use winit::platform::ios::WindowExtIOS;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use winit::platform::web::WindowExtWebSys;
|
||||
|
||||
|
@ -97,6 +99,19 @@ pub fn create_windows<F: QueryFilter + 'static>(
|
|||
style.set_property("height", "100%").unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "ios")]
|
||||
{
|
||||
winit_window.recognize_pinch_gesture(window.recognize_pinch_gesture);
|
||||
winit_window.recognize_rotation_gesture(window.recognize_rotation_gesture);
|
||||
winit_window.recognize_doubletap_gesture(window.recognize_doubletap_gesture);
|
||||
if let Some((min, max)) = window.recognize_pan_gesture {
|
||||
winit_window.recognize_pan_gesture(true, min, max);
|
||||
} else {
|
||||
winit_window.recognize_pan_gesture(false, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
window_created_events.send(WindowCreated { window: entity });
|
||||
}
|
||||
}
|
||||
|
@ -360,6 +375,31 @@ pub(crate) fn changed_windows(
|
|||
winit_window.set_visible(window.visible);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "ios")]
|
||||
{
|
||||
if window.recognize_pinch_gesture != cache.window.recognize_pinch_gesture {
|
||||
winit_window.recognize_pinch_gesture(window.recognize_pinch_gesture);
|
||||
}
|
||||
if window.recognize_rotation_gesture != cache.window.recognize_rotation_gesture {
|
||||
winit_window.recognize_rotation_gesture(window.recognize_rotation_gesture);
|
||||
}
|
||||
if window.recognize_doubletap_gesture != cache.window.recognize_doubletap_gesture {
|
||||
winit_window.recognize_doubletap_gesture(window.recognize_doubletap_gesture);
|
||||
}
|
||||
if window.recognize_pan_gesture != cache.window.recognize_pan_gesture {
|
||||
match (
|
||||
window.recognize_pan_gesture,
|
||||
cache.window.recognize_pan_gesture,
|
||||
) {
|
||||
(Some(_), Some(_)) => {
|
||||
warn!("Bevy currently doesn't support modifying PanGesture number of fingers recognition. Please disable it before re-enabling it with the new number of fingers");
|
||||
}
|
||||
(Some((min, max)), _) => winit_window.recognize_pan_gesture(true, min, max),
|
||||
_ => winit_window.recognize_pan_gesture(false, 0, 0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cache.window = window.clone();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@ use bevy_ecs::prelude::*;
|
|||
use bevy_input::keyboard::KeyboardInput;
|
||||
use bevy_input::touch::TouchInput;
|
||||
use bevy_input::{
|
||||
gestures::*,
|
||||
mouse::{MouseButtonInput, MouseMotion, MouseWheel},
|
||||
touchpad::{TouchpadMagnify, TouchpadRotate},
|
||||
};
|
||||
use bevy_reflect::Reflect;
|
||||
#[cfg(feature = "serialize")]
|
||||
|
@ -55,8 +55,10 @@ pub enum WinitEvent {
|
|||
MouseMotion(MouseMotion),
|
||||
MouseWheel(MouseWheel),
|
||||
|
||||
TouchpadMagnify(TouchpadMagnify),
|
||||
TouchpadRotate(TouchpadRotate),
|
||||
PinchGesture(PinchGesture),
|
||||
RotationGesture(RotationGesture),
|
||||
DoubleTapGesture(DoubleTapGesture),
|
||||
PanGesture(PanGesture),
|
||||
|
||||
TouchInput(TouchInput),
|
||||
|
||||
|
@ -168,14 +170,24 @@ impl From<MouseWheel> for WinitEvent {
|
|||
Self::MouseWheel(e)
|
||||
}
|
||||
}
|
||||
impl From<TouchpadMagnify> for WinitEvent {
|
||||
fn from(e: TouchpadMagnify) -> Self {
|
||||
Self::TouchpadMagnify(e)
|
||||
impl From<PinchGesture> for WinitEvent {
|
||||
fn from(e: PinchGesture) -> Self {
|
||||
Self::PinchGesture(e)
|
||||
}
|
||||
}
|
||||
impl From<TouchpadRotate> for WinitEvent {
|
||||
fn from(e: TouchpadRotate) -> Self {
|
||||
Self::TouchpadRotate(e)
|
||||
impl From<RotationGesture> for WinitEvent {
|
||||
fn from(e: RotationGesture) -> Self {
|
||||
Self::RotationGesture(e)
|
||||
}
|
||||
}
|
||||
impl From<DoubleTapGesture> for WinitEvent {
|
||||
fn from(e: DoubleTapGesture) -> Self {
|
||||
Self::DoubleTapGesture(e)
|
||||
}
|
||||
}
|
||||
impl From<PanGesture> for WinitEvent {
|
||||
fn from(e: PanGesture) -> Self {
|
||||
Self::PanGesture(e)
|
||||
}
|
||||
}
|
||||
impl From<TouchInput> for WinitEvent {
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
use bevy::{
|
||||
input::{
|
||||
gestures::*,
|
||||
mouse::{MouseButtonInput, MouseMotion, MouseWheel},
|
||||
touchpad::{TouchpadMagnify, TouchpadRotate},
|
||||
},
|
||||
prelude::*,
|
||||
};
|
||||
|
@ -21,8 +21,9 @@ fn print_mouse_events_system(
|
|||
mut mouse_motion_events: EventReader<MouseMotion>,
|
||||
mut cursor_moved_events: EventReader<CursorMoved>,
|
||||
mut mouse_wheel_events: EventReader<MouseWheel>,
|
||||
mut touchpad_magnify_events: EventReader<TouchpadMagnify>,
|
||||
mut touchpad_rotate_events: EventReader<TouchpadRotate>,
|
||||
mut pinch_gesture_events: EventReader<PinchGesture>,
|
||||
mut rotation_gesture_events: EventReader<RotationGesture>,
|
||||
mut double_tap_gesture_events: EventReader<DoubleTapGesture>,
|
||||
) {
|
||||
for event in mouse_button_input_events.read() {
|
||||
info!("{:?}", event);
|
||||
|
@ -41,12 +42,17 @@ fn print_mouse_events_system(
|
|||
}
|
||||
|
||||
// This event will only fire on macOS
|
||||
for event in touchpad_magnify_events.read() {
|
||||
for event in pinch_gesture_events.read() {
|
||||
info!("{:?}", event);
|
||||
}
|
||||
|
||||
// This event will only fire on macOS
|
||||
for event in touchpad_rotate_events.read() {
|
||||
for event in rotation_gesture_events.read() {
|
||||
info!("{:?}", event);
|
||||
}
|
||||
|
||||
// This event will only fire on macOS
|
||||
for event in double_tap_gesture_events.read() {
|
||||
info!("{:?}", event);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use bevy::{
|
||||
color::palettes::basic::*,
|
||||
input::touch::TouchPhase,
|
||||
input::{gestures::RotationGesture, touch::TouchPhase},
|
||||
prelude::*,
|
||||
window::{AppLifecycle, WindowMode},
|
||||
};
|
||||
|
@ -15,6 +15,9 @@ fn main() {
|
|||
primary_window: Some(Window {
|
||||
resizable: false,
|
||||
mode: WindowMode::BorderlessFullscreen,
|
||||
// on iOS, gestures must be enabled.
|
||||
// This doesn't work on Android
|
||||
recognize_rotation_gesture: true,
|
||||
..default()
|
||||
}),
|
||||
..default()
|
||||
|
@ -35,6 +38,7 @@ fn touch_camera(
|
|||
mut touches: EventReader<TouchInput>,
|
||||
mut camera: Query<&mut Transform, With<Camera3d>>,
|
||||
mut last_position: Local<Option<Vec2>>,
|
||||
mut rotations: EventReader<RotationGesture>,
|
||||
) {
|
||||
let window = windows.single();
|
||||
|
||||
|
@ -55,6 +59,12 @@ fn touch_camera(
|
|||
}
|
||||
*last_position = Some(touch.position);
|
||||
}
|
||||
// Rotation gestures only work on iOS
|
||||
for rotation in rotations.read() {
|
||||
let mut transform = camera.single_mut();
|
||||
let forward = transform.forward();
|
||||
transform.rotate_axis(forward, rotation.0 / 10.0);
|
||||
}
|
||||
}
|
||||
|
||||
/// set up a simple 3D scene
|
||||
|
|
Loading…
Add table
Reference in a new issue