Skip to content

Commit

Permalink
Web: Pen/Stylus implementation
Browse files Browse the repository at this point in the history
Fixed: device events are emitted regardless of cursor type.
  • Loading branch information
daxpedda committed Jul 22, 2024
1 parent 584a073 commit 67e2fec
Show file tree
Hide file tree
Showing 8 changed files with 332 additions and 194 deletions.
3 changes: 3 additions & 0 deletions clippy.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ disallowed-methods = [
{ path = "web_sys::Element::request_fullscreen", reason = "Doesn't account for compatibility with Safari" },
{ path = "web_sys::Document::exit_fullscreen", reason = "Doesn't account for compatibility with Safari" },
{ path = "web_sys::Document::fullscreen_element", reason = "Doesn't account for compatibility with Safari" },
{ path = "web_sys::PointerEvent::pointer_type", reason = "Use `WebPointerType` to emit warnings" },
{ path = "web_sys::MouseEvent::button", reason = "Use `backend::event::cursor_button()` to avoid wrong conversions" },
{ path = "web_sys::MouseEvent::buttons", reason = "Use `backend::event::cursor_buttons()` to avoid wrong conversions" },
{ path = "objc2_app_kit::NSView::visibleRect", reason = "We expose a render target to the user, and visibility is not really relevant to that (and can break if you don't use the rectangle position as well). Use `frame` instead." },
{ path = "objc2_app_kit::NSWindow::setFrameTopLeftPoint", reason = "Not sufficient when working with Winit's coordinate system, use `flip_window_screen_coordinates` instead" },
]
2 changes: 2 additions & 0 deletions src/changelog/unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ changelog entry.
- Add `ActiveEventLoop::create_proxy()`.
- On Web, implement `Error` for `platform::web::CustomCursorError`.
- Add `WindowEvent::CursorMoved::type` with a new type `CursorType` introducing pen/stylus support.
Currently only implemented on Web.

### Changed

Expand Down Expand Up @@ -91,3 +92,4 @@ changelog entry.
### Fixed

- On MacOS, fix building with `feature = "rwh_04"`.
- On Web, device events are emitted regardless of cursor type.
54 changes: 20 additions & 34 deletions src/platform_impl/web/event_loop/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ use web_sys::{Document, KeyboardEvent, PageTransitionEvent, PointerEvent, WheelE
use web_time::{Duration, Instant};

use super::super::main_thread::MainThreadMarker;
use super::super::web_sys::pointer::{PointerEventExt, WebPointerType};
use super::super::DeviceId;
use super::backend;
use super::backend::{self, ButtonsState, EventListenerHandle};
use super::state::State;
use crate::dpi::PhysicalSize;
use crate::event::{
Expand All @@ -21,7 +22,6 @@ use crate::event::{
};
use crate::event_loop::{ControlFlow, DeviceEvents};
use crate::platform::web::{PollStrategy, WaitUntilStrategy};
use crate::platform_impl::platform::backend::EventListenerHandle;
use crate::platform_impl::platform::r#async::{DispatchRunner, Waker, WakerSpawner};
use crate::platform_impl::platform::window::Inner;
use crate::window::WindowId;
Expand Down Expand Up @@ -58,7 +58,7 @@ pub struct Execution {
destroy_pending: RefCell<VecDeque<WindowId>>,
page_transition_event_handle: RefCell<Option<backend::PageTransitionEventHandle>>,
device_events: Cell<DeviceEvents>,
on_mouse_move: OnEventHandle<PointerEvent>,
on_mouse_move: OnEventHandle<PointerEventExt>,
on_wheel: OnEventHandle<WheelEvent>,
on_mouse_press: OnEventHandle<PointerEvent>,
on_mouse_release: OnEventHandle<PointerEvent>,
Expand Down Expand Up @@ -239,35 +239,26 @@ impl Shared {
*self.0.on_mouse_move.borrow_mut() = Some(EventListenerHandle::new(
self.window().clone(),
"pointermove",
Closure::new(move |event: PointerEvent| {
Closure::new(move |event: PointerEventExt| {
if !runner.device_events() {
return;
}

let pointer_type = event.pointer_type();

if pointer_type != "mouse" {
return;
}

// chorded button event
let device_id = RootDeviceId(DeviceId(event.pointer_id()));

if let Some(button) = backend::event::mouse_button(&event) {
debug_assert_eq!(
pointer_type, "mouse",
"expect pointer type of a chorded button event to be a mouse"
);

let state = if backend::event::mouse_buttons(&event).contains(button.into()) {
if let Some(button) = backend::event::raw_button(&event) {
let state = if backend::event::cursor_buttons(&event)
.contains(ButtonsState::from_bits_retain(button))
{
ElementState::Pressed
} else {
ElementState::Released
};

runner.send_event(Event::DeviceEvent {
device_id,
event: DeviceEvent::Button { button: button.to_id(), state },
event: DeviceEvent::Button { button: button.into(), state },
});

return;
Expand All @@ -288,10 +279,13 @@ impl Shared {
event: DeviceEvent::Motion { axis: 1, value: delta.y },
});

x_motion.into_iter().chain(y_motion).chain(iter::once(Event::DeviceEvent {
device_id,
event: DeviceEvent::MouseMotion { delta: (delta.x, delta.y) },
}))
x_motion.into_iter().chain(y_motion).chain(
matches!(WebPointerType::from_event(&event), Some(WebPointerType::Mouse))
.then_some(Event::DeviceEvent {
device_id,
event: DeviceEvent::MouseMotion { delta: (delta.x, delta.y) },
}),
)
}));
}),
));
Expand Down Expand Up @@ -322,15 +316,11 @@ impl Shared {
return;
}

if event.pointer_type() != "mouse" {
return;
}

let button = backend::event::mouse_button(&event).expect("no mouse button pressed");
let button = backend::event::raw_button(&event).expect("no pointer button pressed");
runner.send_event(Event::DeviceEvent {
device_id: RootDeviceId(DeviceId(event.pointer_id())),
event: DeviceEvent::Button {
button: button.to_id(),
button: button.into(),
state: ElementState::Pressed,
},
});
Expand All @@ -345,15 +335,11 @@ impl Shared {
return;
}

if event.pointer_type() != "mouse" {
return;
}

let button = backend::event::mouse_button(&event).expect("no mouse button pressed");
let button = backend::event::raw_button(&event).expect("no pointer button pressed");
runner.send_event(Event::DeviceEvent {
device_id: RootDeviceId(DeviceId(event.pointer_id())),
event: DeviceEvent::Button {
button: button.to_id(),
button: button.into(),
state: ElementState::Released,
},
});
Expand Down
50 changes: 18 additions & 32 deletions src/platform_impl/web/event_loop/window_target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ use super::runner::{EventWrapper, Execution};
use super::window::WindowId;
use super::{backend, runner, EventLoopProxy};
use crate::event::{
CursorType, DeviceId as RootDeviceId, ElementState, Event, KeyEvent, Touch, TouchPhase,
WindowEvent,
DeviceId as RootDeviceId, ElementState, Event, KeyEvent, Touch, TouchPhase, WindowEvent,
};
use crate::event_loop::{ControlFlow, DeviceEvents};
use crate::keyboard::ModifiersState;
Expand Down Expand Up @@ -297,18 +296,16 @@ impl ActiveEventLoop {
}
});

runner.send_events(modifiers.into_iter().chain(events.flat_map(|position| {
let device_id = RootDeviceId(DeviceId(pointer_id));
runner.send_events(modifiers.into_iter().chain(events.flat_map(
|(position, r#type)| {
let device_id = RootDeviceId(DeviceId(pointer_id));

iter::once(Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::CursorMoved {
device_id,
position,
r#type: CursorType::Mouse,
},
})
})));
iter::once(Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::CursorMoved { device_id, position, r#type },
})
},
)));
}
},
{
Expand Down Expand Up @@ -348,6 +345,7 @@ impl ActiveEventLoop {
move |active_modifiers,
pointer_id,
position: crate::dpi::PhysicalPosition<f64>,
r#type,
buttons,
button| {
let modifiers =
Expand All @@ -373,11 +371,7 @@ impl ActiveEventLoop {
runner.send_events(modifiers.into_iter().chain([
Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::CursorMoved {
device_id,
position,
r#type: CursorType::Mouse,
},
event: WindowEvent::CursorMoved { device_id, position, r#type },
},
Event::WindowEvent {
window_id: RootWindowId(id),
Expand Down Expand Up @@ -407,7 +401,7 @@ impl ActiveEventLoop {
let runner = self.runner.clone();
let modifiers = self.modifiers.clone();

move |active_modifiers, pointer_id, position, button| {
move |active_modifiers, pointer_id, position, r#type, button| {
let modifiers = (modifiers.get() != active_modifiers).then(|| {
modifiers.set(active_modifiers);
Event::WindowEvent {
Expand All @@ -424,18 +418,14 @@ impl ActiveEventLoop {
runner.send_events(modifiers.into_iter().chain([
Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::CursorMoved {
device_id,
position,
r#type: CursorType::Mouse,
},
event: WindowEvent::CursorMoved { device_id, position, r#type },
},
Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::CursorInput {
device_id,
state: ElementState::Pressed,
button: button.into(),
button,
},
},
]));
Expand Down Expand Up @@ -491,7 +481,7 @@ impl ActiveEventLoop {
let has_focus = has_focus.clone();
let modifiers = self.modifiers.clone();

move |active_modifiers, pointer_id, position, button| {
move |active_modifiers, pointer_id, position, r#type, button| {
let modifiers =
(has_focus.get() && modifiers.get() != active_modifiers).then(|| {
modifiers.set(active_modifiers);
Expand All @@ -509,18 +499,14 @@ impl ActiveEventLoop {
runner.send_events(modifiers.into_iter().chain([
Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::CursorMoved {
device_id,
position,
r#type: CursorType::Mouse,
},
event: WindowEvent::CursorMoved { device_id, position, r#type },
},
Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::CursorInput {
device_id,
state: ElementState::Released,
button: button.into(),
button,
},
},
]));
Expand Down
41 changes: 27 additions & 14 deletions src/platform_impl/web/web_sys/canvas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use super::pointer::PointerHandler;
use super::{event, fullscreen, ButtonsState, ResizeScaleHandle};
use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize};
use crate::error::OsError as RootOE;
use crate::event::{CursorButton, Force, InnerSizeWriter, MouseButton, MouseScrollDelta};
use crate::event::{CursorButton, CursorType, Force, InnerSizeWriter, MouseScrollDelta};
use crate::keyboard::{Key, KeyLocation, ModifiersState, PhysicalKey};
use crate::platform_impl::OsError;
use crate::window::{WindowAttributes, WindowId as RootWindowId};
Expand Down Expand Up @@ -328,60 +328,73 @@ impl Canvas {
self.pointer_handler.on_cursor_enter(&self.common, handler)
}

pub fn on_mouse_release<MOD, M, T>(
pub fn on_mouse_release<MOD, C, T>(
&mut self,
modifier_handler: MOD,
mouse_handler: M,
cursor_handler: C,
touch_handler: T,
) where
MOD: 'static + FnMut(ModifiersState),
M: 'static + FnMut(ModifiersState, i32, PhysicalPosition<f64>, MouseButton),
C: 'static + FnMut(ModifiersState, i32, PhysicalPosition<f64>, CursorType, CursorButton),
T: 'static + FnMut(ModifiersState, i32, PhysicalPosition<f64>, Force),
{
self.pointer_handler.on_mouse_release(
&self.common,
modifier_handler,
mouse_handler,
cursor_handler,
touch_handler,
)
}

pub fn on_mouse_press<MOD, M, T>(
pub fn on_mouse_press<MOD, C, T>(
&mut self,
modifier_handler: MOD,
mouse_handler: M,
cursor_handler: C,
touch_handler: T,
) where
MOD: 'static + FnMut(ModifiersState),
M: 'static + FnMut(ModifiersState, i32, PhysicalPosition<f64>, MouseButton),
C: 'static + FnMut(ModifiersState, i32, PhysicalPosition<f64>, CursorType, CursorButton),
T: 'static + FnMut(ModifiersState, i32, PhysicalPosition<f64>, Force),
{
self.pointer_handler.on_mouse_press(
&self.common,
modifier_handler,
mouse_handler,
cursor_handler,
touch_handler,
Rc::clone(&self.prevent_default),
)
}

pub fn on_cursor_move<MOD, M, T, B>(
pub fn on_cursor_move<MOD, C, T, B>(
&mut self,
modifier_handler: MOD,
mouse_handler: M,
cursor_handler: C,
touch_handler: T,
button_handler: B,
) where
MOD: 'static + FnMut(ModifiersState),
M: 'static + FnMut(ModifiersState, i32, &mut dyn Iterator<Item = PhysicalPosition<f64>>),
C: 'static
+ FnMut(
ModifiersState,
i32,
&mut dyn Iterator<Item = (PhysicalPosition<f64>, CursorType)>,
),
T: 'static
+ FnMut(ModifiersState, i32, &mut dyn Iterator<Item = (PhysicalPosition<f64>, Force)>),
B: 'static + FnMut(ModifiersState, i32, PhysicalPosition<f64>, ButtonsState, CursorButton),
B: 'static
+ FnMut(
ModifiersState,
i32,
PhysicalPosition<f64>,
CursorType,
ButtonsState,
CursorButton,
),
{
self.pointer_handler.on_cursor_move(
&self.common,
modifier_handler,
mouse_handler,
cursor_handler,
touch_handler,
button_handler,
Rc::clone(&self.prevent_default),
Expand Down
Loading

0 comments on commit 67e2fec

Please sign in to comment.