Skip to content

Commit

Permalink
Web: implement DeviceIdExtWebSys::is_primary()
Browse files Browse the repository at this point in the history
  • Loading branch information
daxpedda committed Jul 10, 2024
1 parent 39a7d5b commit 196bd82
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 72 deletions.
2 changes: 2 additions & 0 deletions src/changelog/unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ changelog entry.
### Added

- Add `ActiveEventLoop::create_proxy()`.
- On Web, add `DeviceIdExtWebSys::is_primary()`, exposing a way to determine
the primary pointer device.

### Changed

Expand Down
17 changes: 17 additions & 0 deletions src/platform/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ use web_sys::HtmlCanvasElement;

use crate::application::ApplicationHandler;
use crate::cursor::CustomCursorSource;
use crate::event::DeviceId;
use crate::event_loop::{ActiveEventLoop, EventLoop};
#[cfg(web_platform)]
use crate::platform_impl::CustomCursorFuture as PlatformCustomCursorFuture;
Expand Down Expand Up @@ -438,3 +439,19 @@ impl Display for CustomCursorError {
}
}
}

/// Additional methods on [`DeviceId``] that are specific to Web.
pub trait DeviceIdExtWebSys {
/// Indicates if the pointer represents the primary pointer of a pointer type. For non-pointer
/// devices this always returns [`true`].
///
/// This is relevant in multi-touch scenarios, where the the first finger to touch the screen
/// becomes the primary pointer.
fn is_primary(&self) -> bool;
}

impl DeviceIdExtWebSys for DeviceId {
fn is_primary(&self) -> bool {
self.0.is_primary()
}
}
24 changes: 21 additions & 3 deletions src/platform_impl/web/device.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,26 @@
use web_sys::PointerEvent;

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DeviceId(pub i32);
pub struct DeviceId {
pub id: Option<u32>,
pub primary: bool,
}

impl DeviceId {
pub const unsafe fn dummy() -> Self {
Self(0)
pub fn new(event: &PointerEvent) -> Self {
Self {
// We assume that browsers don't use negative numbers unless they are representing the
// reserved `-1` for non-pointing devices.
id: event.pointer_id().try_into().ok(),
primary: event.is_primary(),
}
}

pub const fn dummy() -> Self {
Self { id: None, primary: true }
}

pub const fn is_primary(&self) -> bool {
self.primary
}
}
12 changes: 6 additions & 6 deletions src/platform_impl/web/event_loop/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ impl Shared {
}

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

if let Some(button) = backend::event::mouse_button(&event) {
debug_assert_eq!(
Expand Down Expand Up @@ -307,7 +307,7 @@ impl Shared {

if let Some(delta) = backend::event::mouse_scroll_delta(&window, &event) {
runner.send_event(Event::DeviceEvent {
device_id: RootDeviceId(DeviceId(0)),
device_id: RootDeviceId(DeviceId::dummy()),
event: DeviceEvent::MouseWheel { delta },
});
}
Expand All @@ -328,7 +328,7 @@ impl Shared {

let button = backend::event::mouse_button(&event).expect("no mouse button pressed");
runner.send_event(Event::DeviceEvent {
device_id: RootDeviceId(DeviceId(event.pointer_id())),
device_id: RootDeviceId(DeviceId::new(&event)),
event: DeviceEvent::Button {
button: button.to_id(),
state: ElementState::Pressed,
Expand All @@ -351,7 +351,7 @@ impl Shared {

let button = backend::event::mouse_button(&event).expect("no mouse button pressed");
runner.send_event(Event::DeviceEvent {
device_id: RootDeviceId(DeviceId(event.pointer_id())),
device_id: RootDeviceId(DeviceId::new(&event)),
event: DeviceEvent::Button {
button: button.to_id(),
state: ElementState::Released,
Expand All @@ -369,7 +369,7 @@ impl Shared {
}

runner.send_event(Event::DeviceEvent {
device_id: RootDeviceId(unsafe { DeviceId::dummy() }),
device_id: RootDeviceId(DeviceId::dummy()),
event: DeviceEvent::Key(RawKeyEvent {
physical_key: backend::event::key_code(&event),
state: ElementState::Pressed,
Expand All @@ -387,7 +387,7 @@ impl Shared {
}

runner.send_event(Event::DeviceEvent {
device_id: RootDeviceId(unsafe { DeviceId::dummy() }),
device_id: RootDeviceId(DeviceId::dummy()),
event: DeviceEvent::Key(RawKeyEvent {
physical_key: backend::event::key_code(&event),
state: ElementState::Released,
Expand Down
52 changes: 24 additions & 28 deletions src/platform_impl/web/event_loop/window_target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ impl ActiveEventLoop {
}
});

let device_id = RootDeviceId(unsafe { DeviceId::dummy() });
let device_id = RootDeviceId(DeviceId::dummy());

runner.send_events(
iter::once(Event::WindowEvent {
Expand Down Expand Up @@ -186,7 +186,7 @@ impl ActiveEventLoop {
}
});

let device_id = RootDeviceId(unsafe { DeviceId::dummy() });
let device_id = RootDeviceId(DeviceId::dummy());

runner.send_events(
iter::once(Event::WindowEvent {
Expand Down Expand Up @@ -225,11 +225,9 @@ impl ActiveEventLoop {
}
});

let pointer = pointer_id.map(|pointer_id| Event::WindowEvent {
let pointer = pointer_id.map(|device_id| Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::CursorLeft {
device_id: RootDeviceId(DeviceId(pointer_id)),
},
event: WindowEvent::CursorLeft { device_id: RootDeviceId(device_id) },
});

if focus.is_some() || pointer.is_some() {
Expand All @@ -252,11 +250,9 @@ impl ActiveEventLoop {
}
});

let pointer = pointer_id.map(|pointer_id| Event::WindowEvent {
let pointer = pointer_id.map(|device_id| Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::CursorEntered {
device_id: RootDeviceId(DeviceId(pointer_id)),
},
event: WindowEvent::CursorEntered { device_id: RootDeviceId(device_id) },
});

if focus.is_some() || pointer.is_some() {
Expand Down Expand Up @@ -286,7 +282,7 @@ impl ActiveEventLoop {
let has_focus = has_focus.clone();
let modifiers = self.modifiers.clone();

move |active_modifiers, pointer_id, events| {
move |active_modifiers, device_id, events| {
let modifiers =
(has_focus.get() && modifiers.get() != active_modifiers).then(|| {
modifiers.set(active_modifiers);
Expand All @@ -297,7 +293,7 @@ impl ActiveEventLoop {
});

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

iter::once(Event::WindowEvent {
window_id: RootWindowId(id),
Expand Down Expand Up @@ -325,8 +321,8 @@ impl ActiveEventLoop {
|(location, force)| Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::Touch(Touch {
id: device_id as u64,
device_id: RootDeviceId(DeviceId(device_id)),
id: device_id.id.unwrap_or(0).into(),
device_id: RootDeviceId(device_id),
phase: TouchPhase::Moved,
force: Some(force),
location,
Expand All @@ -341,7 +337,7 @@ impl ActiveEventLoop {
let modifiers = self.modifiers.clone();

move |active_modifiers,
pointer_id,
device_id,
position: crate::dpi::PhysicalPosition<f64>,
buttons,
button| {
Expand All @@ -354,7 +350,7 @@ impl ActiveEventLoop {
}
});

let device_id = RootDeviceId(DeviceId(pointer_id));
let device_id = RootDeviceId(device_id);

let state = if buttons.contains(button.into()) {
ElementState::Pressed
Expand Down Expand Up @@ -398,7 +394,7 @@ impl ActiveEventLoop {
let runner = self.runner.clone();
let modifiers = self.modifiers.clone();

move |active_modifiers, pointer_id, position, button| {
move |active_modifiers, device_id, position, button| {
let modifiers = (modifiers.get() != active_modifiers).then(|| {
modifiers.set(active_modifiers);
Event::WindowEvent {
Expand All @@ -407,7 +403,7 @@ impl ActiveEventLoop {
}
});

let device_id: RootDeviceId = RootDeviceId(DeviceId(pointer_id));
let device_id: RootDeviceId = RootDeviceId(device_id);

// A mouse down event may come in without any prior CursorMoved events,
// therefore we should send a CursorMoved event to make sure that the
Expand Down Expand Up @@ -445,8 +441,8 @@ impl ActiveEventLoop {
Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::Touch(Touch {
id: device_id as u64,
device_id: RootDeviceId(DeviceId(device_id)),
id: device_id.id.unwrap_or(0).into(),
device_id: RootDeviceId(device_id),
phase: TouchPhase::Started,
force: Some(force),
location,
Expand Down Expand Up @@ -478,7 +474,7 @@ impl ActiveEventLoop {
let has_focus = has_focus.clone();
let modifiers = self.modifiers.clone();

move |active_modifiers, pointer_id, position, button| {
move |active_modifiers, device_id, position, button| {
let modifiers =
(has_focus.get() && modifiers.get() != active_modifiers).then(|| {
modifiers.set(active_modifiers);
Expand All @@ -488,7 +484,7 @@ impl ActiveEventLoop {
}
});

let device_id: RootDeviceId = RootDeviceId(DeviceId(pointer_id));
let device_id: RootDeviceId = RootDeviceId(device_id);

// A mouse up event may come in without any prior CursorMoved events,
// therefore we should send a CursorMoved event to make sure that the
Expand Down Expand Up @@ -528,8 +524,8 @@ impl ActiveEventLoop {
Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::Touch(Touch {
id: device_id as u64,
device_id: RootDeviceId(DeviceId(device_id)),
id: device_id.id.unwrap_or(0).into(),
device_id: RootDeviceId(device_id),
phase: TouchPhase::Ended,
force: Some(force),
location,
Expand All @@ -542,7 +538,7 @@ impl ActiveEventLoop {

let runner = self.runner.clone();
let modifiers = self.modifiers.clone();
canvas.on_mouse_wheel(move |pointer_id, delta, active_modifiers| {
canvas.on_mouse_wheel(move |delta, active_modifiers| {
let modifiers_changed =
(has_focus.get() && modifiers.get() != active_modifiers).then(|| {
modifiers.set(active_modifiers);
Expand All @@ -556,7 +552,7 @@ impl ActiveEventLoop {
Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::MouseWheel {
device_id: RootDeviceId(DeviceId(pointer_id)),
device_id: RootDeviceId(DeviceId::dummy()),
delta,
phase: TouchPhase::Moved,
},
Expand All @@ -569,8 +565,8 @@ impl ActiveEventLoop {
runner.send_event(Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::Touch(Touch {
id: device_id as u64,
device_id: RootDeviceId(DeviceId(device_id)),
id: device_id.id.unwrap_or(0).into(),
device_id: RootDeviceId(device_id),
phase: TouchPhase::Cancelled,
force: Some(force),
location,
Expand Down
31 changes: 19 additions & 12 deletions src/platform_impl/web/web_sys/canvas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use web_sys::{
};

use super::super::cursor::CursorHandler;
use super::super::device::DeviceId;
use super::super::main_thread::MainThreadMarker;
use super::super::WindowId;
use super::animation_frame::AnimationFrameHandler;
Expand Down Expand Up @@ -316,14 +317,14 @@ impl Canvas {

pub fn on_cursor_leave<F>(&mut self, handler: F)
where
F: 'static + FnMut(ModifiersState, Option<i32>),
F: 'static + FnMut(ModifiersState, Option<DeviceId>),
{
self.pointer_handler.on_cursor_leave(&self.common, handler)
}

pub fn on_cursor_enter<F>(&mut self, handler: F)
where
F: 'static + FnMut(ModifiersState, Option<i32>),
F: 'static + FnMut(ModifiersState, Option<DeviceId>),
{
self.pointer_handler.on_cursor_enter(&self.common, handler)
}
Expand All @@ -335,8 +336,8 @@ impl Canvas {
touch_handler: T,
) where
MOD: 'static + FnMut(ModifiersState),
M: 'static + FnMut(ModifiersState, i32, PhysicalPosition<f64>, MouseButton),
T: 'static + FnMut(ModifiersState, i32, PhysicalPosition<f64>, Force),
M: 'static + FnMut(ModifiersState, DeviceId, PhysicalPosition<f64>, MouseButton),
T: 'static + FnMut(ModifiersState, DeviceId, PhysicalPosition<f64>, Force),
{
self.pointer_handler.on_mouse_release(
&self.common,
Expand All @@ -353,8 +354,8 @@ impl Canvas {
touch_handler: T,
) where
MOD: 'static + FnMut(ModifiersState),
M: 'static + FnMut(ModifiersState, i32, PhysicalPosition<f64>, MouseButton),
T: 'static + FnMut(ModifiersState, i32, PhysicalPosition<f64>, Force),
M: 'static + FnMut(ModifiersState, DeviceId, PhysicalPosition<f64>, MouseButton),
T: 'static + FnMut(ModifiersState, DeviceId, PhysicalPosition<f64>, Force),
{
self.pointer_handler.on_mouse_press(
&self.common,
Expand All @@ -373,10 +374,16 @@ impl Canvas {
button_handler: B,
) where
MOD: 'static + FnMut(ModifiersState),
M: 'static + FnMut(ModifiersState, i32, &mut dyn Iterator<Item = PhysicalPosition<f64>>),
M: 'static
+ FnMut(ModifiersState, DeviceId, &mut dyn Iterator<Item = PhysicalPosition<f64>>),
T: 'static
+ FnMut(ModifiersState, i32, &mut dyn Iterator<Item = (PhysicalPosition<f64>, Force)>),
B: 'static + FnMut(ModifiersState, i32, PhysicalPosition<f64>, ButtonsState, MouseButton),
+ FnMut(
ModifiersState,
DeviceId,
&mut dyn Iterator<Item = (PhysicalPosition<f64>, Force)>,
),
B: 'static
+ FnMut(ModifiersState, DeviceId, PhysicalPosition<f64>, ButtonsState, MouseButton),
{
self.pointer_handler.on_cursor_move(
&self.common,
Expand All @@ -390,14 +397,14 @@ impl Canvas {

pub fn on_touch_cancel<F>(&mut self, handler: F)
where
F: 'static + FnMut(i32, PhysicalPosition<f64>, Force),
F: 'static + FnMut(DeviceId, PhysicalPosition<f64>, Force),
{
self.pointer_handler.on_touch_cancel(&self.common, handler)
}

pub fn on_mouse_wheel<F>(&mut self, mut handler: F)
where
F: 'static + FnMut(i32, MouseScrollDelta, ModifiersState),
F: 'static + FnMut(MouseScrollDelta, ModifiersState),
{
let window = self.common.window.clone();
let prevent_default = Rc::clone(&self.prevent_default);
Expand All @@ -408,7 +415,7 @@ impl Canvas {

if let Some(delta) = event::mouse_scroll_delta(&window, &event) {
let modifiers = event::mouse_modifiers(&event);
handler(0, delta, modifiers);
handler(delta, modifiers);
}
}));
}
Expand Down
Loading

0 comments on commit 196bd82

Please sign in to comment.