Skip to content

Commit 67e2fec

Browse files
committed
Web: Pen/Stylus implementation
Fixed: device events are emitted regardless of cursor type.
1 parent 584a073 commit 67e2fec

File tree

8 files changed

+332
-194
lines changed

8 files changed

+332
-194
lines changed

clippy.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ disallowed-methods = [
1010
{ path = "web_sys::Element::request_fullscreen", reason = "Doesn't account for compatibility with Safari" },
1111
{ path = "web_sys::Document::exit_fullscreen", reason = "Doesn't account for compatibility with Safari" },
1212
{ path = "web_sys::Document::fullscreen_element", reason = "Doesn't account for compatibility with Safari" },
13+
{ path = "web_sys::PointerEvent::pointer_type", reason = "Use `WebPointerType` to emit warnings" },
14+
{ path = "web_sys::MouseEvent::button", reason = "Use `backend::event::cursor_button()` to avoid wrong conversions" },
15+
{ path = "web_sys::MouseEvent::buttons", reason = "Use `backend::event::cursor_buttons()` to avoid wrong conversions" },
1316
{ 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." },
1417
{ path = "objc2_app_kit::NSWindow::setFrameTopLeftPoint", reason = "Not sufficient when working with Winit's coordinate system, use `flip_window_screen_coordinates` instead" },
1518
]

src/changelog/unreleased.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ changelog entry.
4545
- Add `ActiveEventLoop::create_proxy()`.
4646
- On Web, implement `Error` for `platform::web::CustomCursorError`.
4747
- Add `WindowEvent::CursorMoved::type` with a new type `CursorType` introducing pen/stylus support.
48+
Currently only implemented on Web.
4849

4950
### Changed
5051

@@ -91,3 +92,4 @@ changelog entry.
9192
### Fixed
9293

9394
- On MacOS, fix building with `feature = "rwh_04"`.
95+
- On Web, device events are emitted regardless of cursor type.

src/platform_impl/web/event_loop/runner.rs

Lines changed: 20 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ use web_sys::{Document, KeyboardEvent, PageTransitionEvent, PointerEvent, WheelE
1111
use web_time::{Duration, Instant};
1212

1313
use super::super::main_thread::MainThreadMarker;
14+
use super::super::web_sys::pointer::{PointerEventExt, WebPointerType};
1415
use super::super::DeviceId;
15-
use super::backend;
16+
use super::backend::{self, ButtonsState, EventListenerHandle};
1617
use super::state::State;
1718
use crate::dpi::PhysicalSize;
1819
use crate::event::{
@@ -21,7 +22,6 @@ use crate::event::{
2122
};
2223
use crate::event_loop::{ControlFlow, DeviceEvents};
2324
use crate::platform::web::{PollStrategy, WaitUntilStrategy};
24-
use crate::platform_impl::platform::backend::EventListenerHandle;
2525
use crate::platform_impl::platform::r#async::{DispatchRunner, Waker, WakerSpawner};
2626
use crate::platform_impl::platform::window::Inner;
2727
use crate::window::WindowId;
@@ -58,7 +58,7 @@ pub struct Execution {
5858
destroy_pending: RefCell<VecDeque<WindowId>>,
5959
page_transition_event_handle: RefCell<Option<backend::PageTransitionEventHandle>>,
6060
device_events: Cell<DeviceEvents>,
61-
on_mouse_move: OnEventHandle<PointerEvent>,
61+
on_mouse_move: OnEventHandle<PointerEventExt>,
6262
on_wheel: OnEventHandle<WheelEvent>,
6363
on_mouse_press: OnEventHandle<PointerEvent>,
6464
on_mouse_release: OnEventHandle<PointerEvent>,
@@ -239,35 +239,26 @@ impl Shared {
239239
*self.0.on_mouse_move.borrow_mut() = Some(EventListenerHandle::new(
240240
self.window().clone(),
241241
"pointermove",
242-
Closure::new(move |event: PointerEvent| {
242+
Closure::new(move |event: PointerEventExt| {
243243
if !runner.device_events() {
244244
return;
245245
}
246246

247-
let pointer_type = event.pointer_type();
248-
249-
if pointer_type != "mouse" {
250-
return;
251-
}
252-
253247
// chorded button event
254248
let device_id = RootDeviceId(DeviceId(event.pointer_id()));
255249

256-
if let Some(button) = backend::event::mouse_button(&event) {
257-
debug_assert_eq!(
258-
pointer_type, "mouse",
259-
"expect pointer type of a chorded button event to be a mouse"
260-
);
261-
262-
let state = if backend::event::mouse_buttons(&event).contains(button.into()) {
250+
if let Some(button) = backend::event::raw_button(&event) {
251+
let state = if backend::event::cursor_buttons(&event)
252+
.contains(ButtonsState::from_bits_retain(button))
253+
{
263254
ElementState::Pressed
264255
} else {
265256
ElementState::Released
266257
};
267258

268259
runner.send_event(Event::DeviceEvent {
269260
device_id,
270-
event: DeviceEvent::Button { button: button.to_id(), state },
261+
event: DeviceEvent::Button { button: button.into(), state },
271262
});
272263

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

291-
x_motion.into_iter().chain(y_motion).chain(iter::once(Event::DeviceEvent {
292-
device_id,
293-
event: DeviceEvent::MouseMotion { delta: (delta.x, delta.y) },
294-
}))
282+
x_motion.into_iter().chain(y_motion).chain(
283+
matches!(WebPointerType::from_event(&event), Some(WebPointerType::Mouse))
284+
.then_some(Event::DeviceEvent {
285+
device_id,
286+
event: DeviceEvent::MouseMotion { delta: (delta.x, delta.y) },
287+
}),
288+
)
295289
}));
296290
}),
297291
));
@@ -322,15 +316,11 @@ impl Shared {
322316
return;
323317
}
324318

325-
if event.pointer_type() != "mouse" {
326-
return;
327-
}
328-
329-
let button = backend::event::mouse_button(&event).expect("no mouse button pressed");
319+
let button = backend::event::raw_button(&event).expect("no pointer button pressed");
330320
runner.send_event(Event::DeviceEvent {
331321
device_id: RootDeviceId(DeviceId(event.pointer_id())),
332322
event: DeviceEvent::Button {
333-
button: button.to_id(),
323+
button: button.into(),
334324
state: ElementState::Pressed,
335325
},
336326
});
@@ -345,15 +335,11 @@ impl Shared {
345335
return;
346336
}
347337

348-
if event.pointer_type() != "mouse" {
349-
return;
350-
}
351-
352-
let button = backend::event::mouse_button(&event).expect("no mouse button pressed");
338+
let button = backend::event::raw_button(&event).expect("no pointer button pressed");
353339
runner.send_event(Event::DeviceEvent {
354340
device_id: RootDeviceId(DeviceId(event.pointer_id())),
355341
event: DeviceEvent::Button {
356-
button: button.to_id(),
342+
button: button.into(),
357343
state: ElementState::Released,
358344
},
359345
});

src/platform_impl/web/event_loop/window_target.rs

Lines changed: 18 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ use super::runner::{EventWrapper, Execution};
1414
use super::window::WindowId;
1515
use super::{backend, runner, EventLoopProxy};
1616
use crate::event::{
17-
CursorType, DeviceId as RootDeviceId, ElementState, Event, KeyEvent, Touch, TouchPhase,
18-
WindowEvent,
17+
DeviceId as RootDeviceId, ElementState, Event, KeyEvent, Touch, TouchPhase, WindowEvent,
1918
};
2019
use crate::event_loop::{ControlFlow, DeviceEvents};
2120
use crate::keyboard::ModifiersState;
@@ -297,18 +296,16 @@ impl ActiveEventLoop {
297296
}
298297
});
299298

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

303-
iter::once(Event::WindowEvent {
304-
window_id: RootWindowId(id),
305-
event: WindowEvent::CursorMoved {
306-
device_id,
307-
position,
308-
r#type: CursorType::Mouse,
309-
},
310-
})
311-
})));
303+
iter::once(Event::WindowEvent {
304+
window_id: RootWindowId(id),
305+
event: WindowEvent::CursorMoved { device_id, position, r#type },
306+
})
307+
},
308+
)));
312309
}
313310
},
314311
{
@@ -348,6 +345,7 @@ impl ActiveEventLoop {
348345
move |active_modifiers,
349346
pointer_id,
350347
position: crate::dpi::PhysicalPosition<f64>,
348+
r#type,
351349
buttons,
352350
button| {
353351
let modifiers =
@@ -373,11 +371,7 @@ impl ActiveEventLoop {
373371
runner.send_events(modifiers.into_iter().chain([
374372
Event::WindowEvent {
375373
window_id: RootWindowId(id),
376-
event: WindowEvent::CursorMoved {
377-
device_id,
378-
position,
379-
r#type: CursorType::Mouse,
380-
},
374+
event: WindowEvent::CursorMoved { device_id, position, r#type },
381375
},
382376
Event::WindowEvent {
383377
window_id: RootWindowId(id),
@@ -407,7 +401,7 @@ impl ActiveEventLoop {
407401
let runner = self.runner.clone();
408402
let modifiers = self.modifiers.clone();
409403

410-
move |active_modifiers, pointer_id, position, button| {
404+
move |active_modifiers, pointer_id, position, r#type, button| {
411405
let modifiers = (modifiers.get() != active_modifiers).then(|| {
412406
modifiers.set(active_modifiers);
413407
Event::WindowEvent {
@@ -424,18 +418,14 @@ impl ActiveEventLoop {
424418
runner.send_events(modifiers.into_iter().chain([
425419
Event::WindowEvent {
426420
window_id: RootWindowId(id),
427-
event: WindowEvent::CursorMoved {
428-
device_id,
429-
position,
430-
r#type: CursorType::Mouse,
431-
},
421+
event: WindowEvent::CursorMoved { device_id, position, r#type },
432422
},
433423
Event::WindowEvent {
434424
window_id: RootWindowId(id),
435425
event: WindowEvent::CursorInput {
436426
device_id,
437427
state: ElementState::Pressed,
438-
button: button.into(),
428+
button,
439429
},
440430
},
441431
]));
@@ -491,7 +481,7 @@ impl ActiveEventLoop {
491481
let has_focus = has_focus.clone();
492482
let modifiers = self.modifiers.clone();
493483

494-
move |active_modifiers, pointer_id, position, button| {
484+
move |active_modifiers, pointer_id, position, r#type, button| {
495485
let modifiers =
496486
(has_focus.get() && modifiers.get() != active_modifiers).then(|| {
497487
modifiers.set(active_modifiers);
@@ -509,18 +499,14 @@ impl ActiveEventLoop {
509499
runner.send_events(modifiers.into_iter().chain([
510500
Event::WindowEvent {
511501
window_id: RootWindowId(id),
512-
event: WindowEvent::CursorMoved {
513-
device_id,
514-
position,
515-
r#type: CursorType::Mouse,
516-
},
502+
event: WindowEvent::CursorMoved { device_id, position, r#type },
517503
},
518504
Event::WindowEvent {
519505
window_id: RootWindowId(id),
520506
event: WindowEvent::CursorInput {
521507
device_id,
522508
state: ElementState::Released,
523-
button: button.into(),
509+
button,
524510
},
525511
},
526512
]));

src/platform_impl/web/web_sys/canvas.rs

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use super::pointer::PointerHandler;
2222
use super::{event, fullscreen, ButtonsState, ResizeScaleHandle};
2323
use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize};
2424
use crate::error::OsError as RootOE;
25-
use crate::event::{CursorButton, Force, InnerSizeWriter, MouseButton, MouseScrollDelta};
25+
use crate::event::{CursorButton, CursorType, Force, InnerSizeWriter, MouseScrollDelta};
2626
use crate::keyboard::{Key, KeyLocation, ModifiersState, PhysicalKey};
2727
use crate::platform_impl::OsError;
2828
use crate::window::{WindowAttributes, WindowId as RootWindowId};
@@ -328,60 +328,73 @@ impl Canvas {
328328
self.pointer_handler.on_cursor_enter(&self.common, handler)
329329
}
330330

331-
pub fn on_mouse_release<MOD, M, T>(
331+
pub fn on_mouse_release<MOD, C, T>(
332332
&mut self,
333333
modifier_handler: MOD,
334-
mouse_handler: M,
334+
cursor_handler: C,
335335
touch_handler: T,
336336
) where
337337
MOD: 'static + FnMut(ModifiersState),
338-
M: 'static + FnMut(ModifiersState, i32, PhysicalPosition<f64>, MouseButton),
338+
C: 'static + FnMut(ModifiersState, i32, PhysicalPosition<f64>, CursorType, CursorButton),
339339
T: 'static + FnMut(ModifiersState, i32, PhysicalPosition<f64>, Force),
340340
{
341341
self.pointer_handler.on_mouse_release(
342342
&self.common,
343343
modifier_handler,
344-
mouse_handler,
344+
cursor_handler,
345345
touch_handler,
346346
)
347347
}
348348

349-
pub fn on_mouse_press<MOD, M, T>(
349+
pub fn on_mouse_press<MOD, C, T>(
350350
&mut self,
351351
modifier_handler: MOD,
352-
mouse_handler: M,
352+
cursor_handler: C,
353353
touch_handler: T,
354354
) where
355355
MOD: 'static + FnMut(ModifiersState),
356-
M: 'static + FnMut(ModifiersState, i32, PhysicalPosition<f64>, MouseButton),
356+
C: 'static + FnMut(ModifiersState, i32, PhysicalPosition<f64>, CursorType, CursorButton),
357357
T: 'static + FnMut(ModifiersState, i32, PhysicalPosition<f64>, Force),
358358
{
359359
self.pointer_handler.on_mouse_press(
360360
&self.common,
361361
modifier_handler,
362-
mouse_handler,
362+
cursor_handler,
363363
touch_handler,
364364
Rc::clone(&self.prevent_default),
365365
)
366366
}
367367

368-
pub fn on_cursor_move<MOD, M, T, B>(
368+
pub fn on_cursor_move<MOD, C, T, B>(
369369
&mut self,
370370
modifier_handler: MOD,
371-
mouse_handler: M,
371+
cursor_handler: C,
372372
touch_handler: T,
373373
button_handler: B,
374374
) where
375375
MOD: 'static + FnMut(ModifiersState),
376-
M: 'static + FnMut(ModifiersState, i32, &mut dyn Iterator<Item = PhysicalPosition<f64>>),
376+
C: 'static
377+
+ FnMut(
378+
ModifiersState,
379+
i32,
380+
&mut dyn Iterator<Item = (PhysicalPosition<f64>, CursorType)>,
381+
),
377382
T: 'static
378383
+ FnMut(ModifiersState, i32, &mut dyn Iterator<Item = (PhysicalPosition<f64>, Force)>),
379-
B: 'static + FnMut(ModifiersState, i32, PhysicalPosition<f64>, ButtonsState, CursorButton),
384+
B: 'static
385+
+ FnMut(
386+
ModifiersState,
387+
i32,
388+
PhysicalPosition<f64>,
389+
CursorType,
390+
ButtonsState,
391+
CursorButton,
392+
),
380393
{
381394
self.pointer_handler.on_cursor_move(
382395
&self.common,
383396
modifier_handler,
384-
mouse_handler,
397+
cursor_handler,
385398
touch_handler,
386399
button_handler,
387400
Rc::clone(&self.prevent_default),

0 commit comments

Comments
 (0)