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

Web touch event #2188

Merged
merged 37 commits into from
Dec 23, 2022
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
52fe7c7
feat: add pointer events to web
dsluijk May 20, 2021
93422c1
feat: remove PointerType for touch events
dsluijk May 20, 2021
08cdb4a
Remove duplicate
ryo33 Feb 7, 2022
a09201c
Changelog and features
ryo33 Feb 7, 2022
950a7e5
Remove PointerType
ryo33 Feb 7, 2022
6822fc8
feat: renamed events, added touch type guard
dsluijk May 23, 2021
e47fe8d
Rename
ryo33 Feb 7, 2022
2c7eab9
Flip the y axis
ryo33 Feb 7, 2022
0094ec2
Fix physical position and add force
ryo33 Feb 8, 2022
4f38d82
Update comment
ryo33 Feb 8, 2022
6b22593
Update features
ryo33 Feb 8, 2022
5ef9679
Use normalized force
ryo33 Feb 20, 2022
84f9c66
Remove unnecessary todos
ryo33 May 26, 2022
3c5635f
Update comment
ryo33 May 26, 2022
1911832
Refactor add touch_handler
ryo33 May 26, 2022
a977817
Rephrase by Liamolucko
ryo33 May 26, 2022
2162420
Update CHANGELOG.md
ryo33 May 26, 2022
736168e
Fix duplicate mouse and touch events
johanhelsing Jun 11, 2022
8f57eed
Merge pull request #1 from johanhelsing/touch-only-events
ryo33 Jun 14, 2022
94a8343
Removed workaround for scale factor
oscrim Sep 6, 2022
3eb4a3d
Merge pull request #2 from oscrim/web-touch-event
ryo33 Sep 8, 2022
0987b71
Flip the y axis
ryo33 Sep 8, 2022
bac7e93
Fix
ryo33 Sep 8, 2022
da1b7e5
Merge branch 'master' of github.com:rust-windowing/winit into web-tou…
ryo33 Sep 8, 2022
6d6cd8b
Fmt
ryo33 Sep 8, 2022
4fed48d
Replace `match` with a single pattern with `if let`
ryo33 Sep 8, 2022
579efe3
Update documentation
ryo33 Nov 7, 2022
c32f0a0
Have one callback per event
ryo33 Nov 7, 2022
b980d87
Remove a comment
ryo33 Nov 7, 2022
ee312a8
Fix
ryo33 Nov 7, 2022
c828370
Merge branch 'master' into web-touch-event
ryo33 Nov 7, 2022
79209f9
Remove y-axis flip
ryo33 Nov 26, 2022
0ddacfb
Merge branch 'master' into web-touch-event
ryo33 Nov 26, 2022
8db6ac4
Update src/event.rs
ryo33 Dec 23, 2022
9e25a4b
Merge branch 'master' into web-touch-event
madsmtm Dec 23, 2022
49890f1
Fix platform specific comment
madsmtm Dec 23, 2022
1e9dca1
Fix extra argument to `touch_position` function
madsmtm Dec 23, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ And please only add new entries to the top of this list, right below the `# Unre

# Unreleased

- On Web, add support for touch events.
- On Wayland, fix bug where the cursor wouldn't hide in GNOME.
- On macOS, Windows, and Wayland, add `set_cursor_hittest` to let the window ignore mouse events.
- On Windows, added `WindowExtWindows::set_skip_taskbar` and `WindowBuilderExtWindows::with_skip_taskbar`.
Expand Down
4 changes: 2 additions & 2 deletions FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,8 @@ Legend:
|Cursor grab |✔️ |▢[#165] |▢[#242] |✔️ |**N/A**|**N/A**|✔️ |
|Cursor icon |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|✔️ |
|Cursor hittest |✔️ |✔️ |❌ |✔️ |**N/A**|**N/A**|❌ |
|Touch events |✔️ |❌ |✔️ |✔️ |✔️ |✔️ | |
|Touch pressure |✔️ |❌ |❌ |❌ |❌ |✔️ | |
|Touch events |✔️ |❌ |✔️ |✔️ |✔️ |✔️ |️✔️ |
|Touch pressure |✔️ |❌ |❌ |❌ |❌ |✔️ |✔️ |
|Multitouch |✔️ |❌ |✔️ |✔️ |✔️ |✔️ |❌ |
|Keyboard events |✔️ |✔️ |✔️ |✔️ |❓ |❌ |✔️ |
|Drag & Drop |▢[#720] |▢[#720] |▢[#720] |❌[#306] |**N/A**|**N/A**|❓ |
Expand Down
58 changes: 57 additions & 1 deletion src/platform_impl/web/event_loop/window_target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use super::{
};
use crate::dpi::{PhysicalSize, Size};
use crate::event::{
DeviceEvent, DeviceId as RootDeviceId, ElementState, Event, KeyboardInput, TouchPhase,
DeviceEvent, DeviceId as RootDeviceId, ElementState, Event, KeyboardInput, Touch, TouchPhase,
WindowEvent,
};
use crate::event_loop::ControlFlow;
Expand Down Expand Up @@ -235,6 +235,62 @@ impl<T> EventLoopWindowTarget<T> {
runner.request_redraw(RootWindowId(id));
});

let runner = self.runner.clone();
canvas.on_touch_move(move |device_id, location, force| {
runner.send_event(Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::Touch(Touch {
id: device_id as u64,
device_id: RootDeviceId(DeviceId(device_id)),
phase: TouchPhase::Moved,
force: Some(force),
location,
}),
});
});

let runner = self.runner.clone();
canvas.on_touch_down(move |device_id, location, force| {
runner.send_event(Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::Touch(Touch {
id: device_id as u64,
device_id: RootDeviceId(DeviceId(device_id)),
phase: TouchPhase::Started,
force: Some(force),
location,
}),
});
});

let runner = self.runner.clone();
canvas.on_touch_up(move |device_id, location, force| {
runner.send_event(Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::Touch(Touch {
id: device_id as u64,
device_id: RootDeviceId(DeviceId(device_id)),
phase: TouchPhase::Ended,
force: Some(force),
location,
}),
});
});

let runner = self.runner.clone();
canvas.on_touch_cancel(move |device_id, location, force| {
runner.send_event(Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::Touch(Touch {
id: device_id as u64,
device_id: RootDeviceId(DeviceId(device_id)),
phase: TouchPhase::Cancelled,
force: Some(force),
location,
}),
});
});

let runner = self.runner.clone();
canvas.on_dark_mode(move |is_dark_mode| {
let theme = if is_dark_mode {
Expand Down
44 changes: 43 additions & 1 deletion src/platform_impl/web/web_sys/canvas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ use super::event_handle::EventListenerHandle;
use super::media_query_handle::MediaQueryListHandle;
use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize};
use crate::error::OsError as RootOE;
use crate::event::{ModifiersState, MouseButton, MouseScrollDelta, ScanCode, VirtualKeyCode};
use crate::event::{
Force, ModifiersState, MouseButton, MouseScrollDelta, ScanCode, VirtualKeyCode,
};
use crate::platform_impl::{OsError, PlatformSpecificWindowBuilderAttributes};

use std::cell::RefCell;
Expand Down Expand Up @@ -261,6 +263,46 @@ impl Canvas {
}
}

pub fn on_touch_move<F>(&mut self, handler: F)
where
F: 'static + FnMut(i32, PhysicalPosition<f64>, Force),
{
match &mut self.mouse_state {
MouseState::HasPointerEvent(h) => h.on_touch_move(&self.common, handler),
_ => {}
}
}

pub fn on_touch_down<F>(&mut self, handler: F)
where
F: 'static + FnMut(i32, PhysicalPosition<f64>, Force),
{
match &mut self.mouse_state {
MouseState::HasPointerEvent(h) => h.on_touch_down(&self.common, handler),
_ => {}
}
}

pub fn on_touch_up<F>(&mut self, handler: F)
where
F: 'static + FnMut(i32, PhysicalPosition<f64>, Force),
{
match &mut self.mouse_state {
MouseState::HasPointerEvent(h) => h.on_touch_up(&self.common, handler),
_ => {}
}
}

pub fn on_touch_cancel<F>(&mut self, handler: F)
where
F: 'static + FnMut(i32, PhysicalPosition<f64>, Force),
{
match &mut self.mouse_state {
MouseState::HasPointerEvent(h) => h.on_touch_cancel(&self.common, handler),
_ => {}
}
}

pub fn on_mouse_wheel<F>(&mut self, mut handler: F)
where
F: 'static + FnMut(i32, MouseScrollDelta, ModifiersState),
Expand Down
98 changes: 98 additions & 0 deletions src/platform_impl/web/web_sys/canvas/pointer_handler.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::event;
use super::EventListenerHandle;
use crate::dpi::PhysicalPosition;
use crate::event::Force;
use crate::event::{ModifiersState, MouseButton};

use web_sys::PointerEvent;
Expand All @@ -12,6 +13,10 @@ pub(super) struct PointerHandler {
on_cursor_move: Option<EventListenerHandle<dyn FnMut(PointerEvent)>>,
on_pointer_press: Option<EventListenerHandle<dyn FnMut(PointerEvent)>>,
on_pointer_release: Option<EventListenerHandle<dyn FnMut(PointerEvent)>>,
on_touch_move: Option<EventListenerHandle<dyn FnMut(PointerEvent)>>,
on_touch_down: Option<EventListenerHandle<dyn FnMut(PointerEvent)>>,
on_touch_up: Option<EventListenerHandle<dyn FnMut(PointerEvent)>>,
on_touch_cancel: Option<EventListenerHandle<dyn FnMut(PointerEvent)>>,
}

impl PointerHandler {
Expand All @@ -22,6 +27,10 @@ impl PointerHandler {
on_cursor_move: None,
on_pointer_press: None,
on_pointer_release: None,
on_touch_move: None,
on_touch_down: None,
on_touch_up: None,
on_touch_cancel: None,
}
}

Expand All @@ -32,6 +41,13 @@ impl PointerHandler {
self.on_cursor_leave = Some(canvas_common.add_event(
"pointerout",
move |event: PointerEvent| {
// touch events are handled separately
// handling them here would produce duplicate mouse events, inconsistent with
// other platforms.
if event.pointer_type() == "touch" {
return;
}

handler(event.pointer_id());
},
));
Expand All @@ -44,6 +60,13 @@ impl PointerHandler {
self.on_cursor_enter = Some(canvas_common.add_event(
"pointerover",
move |event: PointerEvent| {
// touch events are handled separately
// handling them here would produce duplicate mouse events, inconsistent with
// other platforms.
if event.pointer_type() == "touch" {
return;
}

handler(event.pointer_id());
},
));
Expand All @@ -56,6 +79,13 @@ impl PointerHandler {
self.on_pointer_release = Some(canvas_common.add_user_event(
"pointerup",
move |event: PointerEvent| {
// touch events are handled separately
// handling them here would produce duplicate mouse events, inconsistent with
// other platforms.
if event.pointer_type() == "touch" {
return;
}

handler(
event.pointer_id(),
event::mouse_button(&event),
Expand All @@ -73,6 +103,13 @@ impl PointerHandler {
self.on_pointer_press = Some(canvas_common.add_user_event(
"pointerdown",
move |event: PointerEvent| {
// touch events are handled separately
// handling them here would produce duplicate mouse events, inconsistent with
// other platforms.
if event.pointer_type() == "touch" {
return;
}

handler(
event.pointer_id(),
event::mouse_position(&event).to_physical(super::super::scale_factor()),
Expand All @@ -95,6 +132,13 @@ impl PointerHandler {
self.on_cursor_move = Some(canvas_common.add_event(
"pointermove",
move |event: PointerEvent| {
// touch events are handled separately
// handling them here would produce duplicate mouse events, inconsistent with
// other platforms.
if event.pointer_type() == "touch" {
return;
}

handler(
event.pointer_id(),
event::mouse_position(&event).to_physical(super::super::scale_factor()),
Expand All @@ -105,11 +149,65 @@ impl PointerHandler {
));
}

pub fn on_touch_move<F>(&mut self, canvas_common: &super::Common, handler: F)
where
F: 'static + FnMut(i32, PhysicalPosition<f64>, Force),
{
self.on_touch_move =
Some(canvas_common.add_event("pointermove", touch_handler(handler)));
}

pub fn on_touch_down<F>(&mut self, canvas_common: &super::Common, handler: F)
where
F: 'static + FnMut(i32, PhysicalPosition<f64>, Force),
{
self.on_touch_down =
Some(canvas_common.add_event("pointerdown", touch_handler(handler)));
}

pub fn on_touch_up<F>(&mut self, canvas_common: &super::Common, handler: F)
where
F: 'static + FnMut(i32, PhysicalPosition<f64>, Force),
{
self.on_touch_up =
Some(canvas_common.add_event("pointerup", touch_handler(handler)));
}

pub fn on_touch_cancel<F>(&mut self, canvas_common: &super::Common, handler: F)
where
F: 'static + FnMut(i32, PhysicalPosition<f64>, Force),
{
self.on_touch_cancel =
Some(canvas_common.add_event("pointercancel", touch_handler(handler)));
}

pub fn remove_listeners(&mut self) {
self.on_cursor_leave = None;
self.on_cursor_enter = None;
self.on_cursor_move = None;
self.on_pointer_press = None;
self.on_pointer_release = None;
self.on_touch_move = None;
self.on_touch_down = None;
self.on_touch_up = None;
self.on_touch_cancel = None;
}
}

fn touch_handler<F>(mut handler: F) -> impl FnMut(PointerEvent)
where
F: 'static + FnMut(i32, PhysicalPosition<f64>, Force),
{
move |event: PointerEvent| {
if event.pointer_type() != "touch" {
return;
}

handler(
event.pointer_id(),
event::touch_position(&event)
.to_physical(super::super::scale_factor()),
Force::Normalized(event.pressure() as f64),
);
}
}
10 changes: 9 additions & 1 deletion src/platform_impl/web/web_sys/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::dpi::LogicalPosition;
use crate::event::{ModifiersState, MouseButton, MouseScrollDelta, ScanCode, VirtualKeyCode};

use std::convert::TryInto;
use web_sys::{HtmlCanvasElement, KeyboardEvent, MouseEvent, WheelEvent};
use web_sys::{HtmlCanvasElement, KeyboardEvent, MouseEvent, WheelEvent, PointerEvent};

pub fn mouse_button(event: &MouseEvent) -> MouseButton {
match event.button() {
Expand Down Expand Up @@ -246,3 +246,11 @@ pub fn codepoint(event: &KeyboardEvent) -> char {
// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key
event.key().chars().next().unwrap()
}

pub fn touch_position(event: &PointerEvent) -> LogicalPosition<f64> {
LogicalPosition {
x: event.client_x() as f64,
// Flip the Y axis because canvas's origin is top-left.
ryo33 marked this conversation as resolved.
Show resolved Hide resolved
y: event.client_y() as f64,
}
}