-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
Implement basic touch support #334
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
use super::keyboard::ElementState; | ||
use crate::Input; | ||
use bevy_app::prelude::{EventReader, Events}; | ||
use bevy_ecs::{Local, Res, ResMut}; | ||
use bevy_math::Vec2; | ||
|
||
/// A finger on a touch screen device | ||
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)] | ||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] | ||
pub struct Finger(pub u64); | ||
|
||
/// A finger pressed event | ||
#[derive(Debug, Clone)] | ||
pub struct TouchFingerInput { | ||
pub finger: Finger, | ||
pub state: ElementState, | ||
pub position: Vec2, | ||
} | ||
|
||
/// A finer motion event | ||
#[derive(Debug, Clone)] | ||
pub struct TouchMotion { | ||
pub finger: Finger, | ||
pub position: Vec2, | ||
} | ||
|
||
/// State used by the mouse button input system | ||
#[derive(Default)] | ||
pub struct TouchFingerInputState { | ||
touch_finger_input_event_reader: EventReader<TouchFingerInput>, | ||
} | ||
|
||
/// Updates the Input<Finger> resource with the latest TouchFingerInput events | ||
pub fn touch_finger_input_system( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As nice as this api is to consume, I think we should remove |
||
mut state: Local<TouchFingerInputState>, | ||
mut touch_finger_input: ResMut<Input<Finger>>, | ||
touch_finger_input_events: Res<Events<TouchFingerInput>>, | ||
) { | ||
touch_finger_input.update(); | ||
for event in state | ||
.touch_finger_input_event_reader | ||
.iter(&touch_finger_input_events) | ||
{ | ||
match event.state { | ||
ElementState::Pressed => touch_finger_input.press(event.finger), | ||
ElementState::Released => touch_finger_input.release(event.finger), | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,8 +2,9 @@ mod converters; | |
mod winit_config; | ||
mod winit_windows; | ||
use bevy_input::{ | ||
keyboard::KeyboardInput, | ||
keyboard::{ElementState, KeyboardInput}, | ||
mouse::{MouseButtonInput, MouseMotion, MouseScrollUnit, MouseWheel}, | ||
touch::{Finger, TouchFingerInput, TouchMotion}, | ||
}; | ||
pub use winit_config::*; | ||
pub use winit_windows::*; | ||
|
@@ -17,7 +18,7 @@ use bevy_window::{ | |
use event::Event; | ||
use winit::{ | ||
event, | ||
event::{DeviceEvent, WindowEvent}, | ||
event::{DeviceEvent, Touch, TouchPhase, WindowEvent}, | ||
event_loop::{ControlFlow, EventLoop, EventLoopWindowTarget}, | ||
}; | ||
|
||
|
@@ -192,6 +193,64 @@ pub fn winit_runner(mut app: App) { | |
}); | ||
} | ||
}, | ||
WindowEvent::Touch( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think its much more legible to compress these into a single match arm, then have a second match inside: WindowEvent::Touch(touch) => match touch.phase {
TouchPhase::Started => {
let mut touch_finger_input_events =
app.resources.get_mut::<Events<TouchFingerInput>>().unwrap();
touch_finger_input_events.send(converters::convert_touch_input(
ElementState::Pressed,
&touch,
));
}
TouchPhase::Ended => {
let mut touch_finger_input_events =
app.resources.get_mut::<Events<TouchFingerInput>>().unwrap();
touch_finger_input_events.send(converters::convert_touch_input(
ElementState::Released,
&touch,
));
}
TouchPhase::Cancelled => {
let mut touch_finger_input_events =
app.resources.get_mut::<Events<TouchFingerInput>>().unwrap();
touch_finger_input_events.send(converters::convert_touch_input(
ElementState::Released,
&touch,
));
}
TouchPhase::Moved => {
let mut touch_finger_moved_events =
app.resources.get_mut::<Events<TouchMotion>>().unwrap();
touch_finger_moved_events.send(TouchMotion {
finger: Finger(touch.id),
position: Vec2::new(touch.location.x as f32, touch.location.y as f32),
});
}
}, |
||
touch | ||
@ | ||
Touch { | ||
phase: TouchPhase::Started, | ||
.. | ||
}, | ||
) => { | ||
let mut touch_finger_input_events = | ||
app.resources.get_mut::<Events<TouchFingerInput>>().unwrap(); | ||
touch_finger_input_events.send(converters::convert_touch_input( | ||
ElementState::Pressed, | ||
&touch, | ||
)); | ||
} | ||
WindowEvent::Touch( | ||
touch | ||
@ | ||
Touch { | ||
phase: TouchPhase::Ended, | ||
.. | ||
}, | ||
) => { | ||
let mut touch_finger_input_events = | ||
app.resources.get_mut::<Events<TouchFingerInput>>().unwrap(); | ||
touch_finger_input_events.send(converters::convert_touch_input( | ||
ElementState::Released, | ||
&touch, | ||
)); | ||
} | ||
WindowEvent::Touch( | ||
touch | ||
@ | ||
Touch { | ||
phase: TouchPhase::Cancelled, | ||
.. | ||
}, | ||
) => { | ||
let mut touch_finger_input_events = | ||
app.resources.get_mut::<Events<TouchFingerInput>>().unwrap(); | ||
touch_finger_input_events.send(converters::convert_touch_input( | ||
ElementState::Released, | ||
&touch, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure we should be mapping There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree with this. We should mirror the winit TouchPhase enum in the bevy events. |
||
)); | ||
} | ||
WindowEvent::Touch(Touch { | ||
phase: TouchPhase::Moved, | ||
id, | ||
location, | ||
.. | ||
}) => { | ||
let mut touch_finger_moved_events = | ||
app.resources.get_mut::<Events<TouchMotion>>().unwrap(); | ||
touch_finger_moved_events.send(TouchMotion { | ||
finger: Finger(id), | ||
position: Vec2::new(location.x as f32, location.y as f32), | ||
}); | ||
} | ||
_ => {} | ||
}, | ||
event::Event::DeviceEvent { ref event, .. } => { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
use bevy::prelude::*; | ||
|
||
fn main() { | ||
App::build() | ||
.add_default_plugins() | ||
.add_system(touch_system.system()) | ||
.run(); | ||
} | ||
|
||
// This system prints messages when you use the touchscreen | ||
fn touch_system(finger_input: Res<Input<Finger>>) { | ||
if finger_input.pressed(Finger(0)) { | ||
println!("finger 0 pressed"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not 100% sure this works on all platforms? For example on iOS I was getting huge numbers, not 0 and 1. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah I think we should assume that a "touch id" is an opaque identifier. |
||
} | ||
|
||
if finger_input.just_pressed(Finger(0)) { | ||
println!("finger 0 just pressed"); | ||
} | ||
|
||
if finger_input.just_released(Finger(0)) { | ||
println!("finger 0 just released"); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
use bevy::{ | ||
input::touch::{TouchFingerInput, TouchMotion}, | ||
prelude::*, | ||
}; | ||
|
||
fn main() { | ||
App::build() | ||
.add_default_plugins() | ||
.init_resource::<State>() | ||
.add_system(print_touch_events_system.system()) | ||
.run(); | ||
} | ||
|
||
#[derive(Default)] | ||
struct State { | ||
touch_finger_event_reader: EventReader<TouchFingerInput>, | ||
touch_motion_event_reader: EventReader<TouchMotion>, | ||
} | ||
|
||
/// This system prints out all touch events as they come in | ||
fn print_touch_events_system( | ||
mut state: ResMut<State>, | ||
touch_finger_input_events: Res<Events<TouchFingerInput>>, | ||
touch_motion_events: Res<Events<TouchMotion>>, | ||
) { | ||
for event in state | ||
.touch_finger_event_reader | ||
.iter(&touch_finger_input_events) | ||
{ | ||
println!("{:?}", event); | ||
} | ||
|
||
for event in state.touch_motion_event_reader.iter(&touch_motion_events) { | ||
println!("{:?}", event); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also think I would prefer it if we didn't call this finger. I think TouchId is a more generic term