From 1029c8d50337dc48528d508e66d4d2b6fa21ce3f Mon Sep 17 00:00:00 2001 From: daxpedda Date: Sun, 14 Jul 2024 22:19:05 +0200 Subject: [PATCH] Introduce `FingerId` --- src/changelog/unreleased.md | 4 + src/event.rs | 28 ++++++- src/platform/web.rs | 13 ++++ src/platform/windows.rs | 15 +++- src/platform_impl/android/mod.rs | 11 ++- src/platform_impl/apple/appkit/mod.rs | 9 +++ src/platform_impl/apple/uikit/mod.rs | 9 +++ src/platform_impl/apple/uikit/view.rs | 8 +- src/platform_impl/linux/mod.rs | 17 ++++ src/platform_impl/linux/wayland/mod.rs | 9 +++ .../linux/wayland/seat/touch/mod.rs | 18 +++-- .../linux/x11/event_processor.rs | 12 +-- src/platform_impl/linux/x11/mod.rs | 14 ++++ src/platform_impl/orbital/mod.rs | 9 +++ src/platform_impl/web/device.rs | 8 -- src/platform_impl/web/event.rs | 32 ++++++++ src/platform_impl/web/event_loop/mod.rs | 2 +- src/platform_impl/web/event_loop/runner.rs | 8 +- .../web/event_loop/window_target.rs | 61 +++++++-------- src/platform_impl/web/mod.rs | 4 +- src/platform_impl/web/web_sys/canvas.rs | 32 +++++--- src/platform_impl/web/web_sys/pointer.rs | 77 ++++++++++++------- src/platform_impl/windows/event_loop.rs | 24 ++++-- src/platform_impl/windows/mod.rs | 18 +++++ 24 files changed, 327 insertions(+), 115 deletions(-) delete mode 100644 src/platform_impl/web/device.rs create mode 100644 src/platform_impl/web/event.rs diff --git a/src/changelog/unreleased.md b/src/changelog/unreleased.md index 85bb63da6f..d62bd64b1c 100644 --- a/src/changelog/unreleased.md +++ b/src/changelog/unreleased.md @@ -43,6 +43,9 @@ changelog entry. ### Added - Add `ActiveEventLoop::create_proxy()`. +- Add `Touch::finger_id` with a new type `FingerId`. +- On Web and Windows, add `FingerIdExt*::primary()`, exposing a way to determine the + primary finger in a multi-touch interaction. ### Changed @@ -80,6 +83,7 @@ changelog entry. This feature was incomplete, and the equivalent functionality can be trivially achieved outside of `winit` using `objc2-ui-kit` and calling `UIDevice::currentDevice().userInterfaceIdiom()`. +- Remove `Touch::id` in favor of `Touch::finger_id`. ### Fixed diff --git a/src/event.rs b/src/event.rs index e0a6d4376d..8dce0d528e 100644 --- a/src/event.rs +++ b/src/event.rs @@ -450,6 +450,26 @@ impl DeviceId { } } +/// Identifier of a finger in a touch event. +/// +/// Whenever a touch event is received it contains a `FingerId` which uniquely identifies the finger +/// used. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct FingerId(pub(crate) platform_impl::FingerId); + +impl FingerId { + /// Returns a dummy id, useful for unit testing. + /// + /// # Notes + /// + /// The only guarantee made about the return value of this function is that + /// it will always be equal to itself and to future values returned by this function. + /// No other guarantees are made. This may be equal to a real `FingerId`. + pub const fn dummy() -> Self { + FingerId(platform_impl::FingerId::dummy()) + } +} + /// Represents raw hardware events that are not associated with any particular window. /// /// Useful for interactions that diverge significantly from a conventional 2D GUI, such as 3D camera @@ -845,7 +865,7 @@ pub struct Touch { /// [android documentation](https://developer.android.com/reference/android/view/MotionEvent#AXIS_PRESSURE). pub force: Option, /// Unique identifier of a finger. - pub id: u64, + pub finger_id: FingerId, } /// Describes the force of a touch event @@ -1011,6 +1031,7 @@ mod tests { #[allow(unused_mut)] let mut x = $closure; let did = event::DeviceId::dummy(); + let fid = event::FingerId::dummy(); #[allow(deprecated)] { @@ -1075,7 +1096,7 @@ mod tests { device_id: did, phase: event::TouchPhase::Started, location: (0.0, 0.0).into(), - id: 0, + finger_id: fid, force: Some(event::Force::Normalized(0.0)), })); with_window_event(ThemeChanged(crate::window::Theme::Light)); @@ -1136,6 +1157,7 @@ mod tests { let _ = event::StartCause::Init.clone(); let did = crate::event::DeviceId::dummy().clone(); + let fid = crate::event::FingerId::dummy().clone(); HashSet::new().insert(did); let mut set = [did, did, did]; set.sort_unstable(); @@ -1151,7 +1173,7 @@ mod tests { device_id: did, phase: event::TouchPhase::Started, location: (0.0, 0.0).into(), - id: 0, + finger_id: fid, force: Some(event::Force::Normalized(0.0)), } .clone(); diff --git a/src/platform/web.rs b/src/platform/web.rs index 1dd612ce24..451f19748e 100644 --- a/src/platform/web.rs +++ b/src/platform/web.rs @@ -54,6 +54,7 @@ use web_sys::HtmlCanvasElement; use crate::application::ApplicationHandler; use crate::cursor::CustomCursorSource; +use crate::event::FingerId; use crate::event_loop::{ActiveEventLoop, EventLoop}; #[cfg(web_platform)] use crate::platform_impl::CustomCursorFuture as PlatformCustomCursorFuture; @@ -437,3 +438,15 @@ impl Display for CustomCursorError { } } } + +/// Additional methods on [`FingerId`] that are specific to Web. +pub trait FingerIdExtWeb { + /// Indicates if the finger represents the first contact in a multi-touch interaction. + fn primary(self) -> bool; +} + +impl FingerIdExtWeb for FingerId { + fn primary(self) -> bool { + self.0.primary() + } +} diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 664be87ed0..217ec21d21 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -7,7 +7,7 @@ use std::ffi::c_void; use std::path::Path; use crate::dpi::PhysicalSize; -use crate::event::DeviceId; +use crate::event::{DeviceId, FingerId}; use crate::event_loop::EventLoopBuilder; use crate::monitor::MonitorHandle; use crate::window::{BadIcon, Icon, Window, WindowAttributes}; @@ -660,6 +660,19 @@ impl DeviceIdExtWindows for DeviceId { } } +/// Additional methods on `FingerId` that are specific to Windows. +pub trait FingerIdExtWindows { + /// Indicates if the finger represents the first contact in a multi-touch interaction. + fn primary(self) -> bool; +} + +impl FingerIdExtWindows for FingerId { + #[inline] + fn primary(self) -> bool { + self.0.primary() + } +} + /// Additional methods on `Icon` that are specific to Windows. pub trait IconExtWindows: Sized { /// Create an icon from a file path. diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index 9bb7830262..760dc33e0d 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -358,7 +358,7 @@ impl EventLoop { device_id, phase, location, - id: pointer.pointer_id() as u64, + finger_id: event::FingerId(FingerId(pointer.pointer_id())), force: Some(Force::Normalized(pointer.pressure() as f64)), }); @@ -692,6 +692,15 @@ impl DeviceId { } } +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct FingerId(i32); + +impl FingerId { + pub const fn dummy() -> Self { + FingerId(0) + } +} + #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] pub struct PlatformSpecificWindowAttributes; diff --git a/src/platform_impl/apple/appkit/mod.rs b/src/platform_impl/apple/appkit/mod.rs index 2867814932..607f17e271 100644 --- a/src/platform_impl/apple/appkit/mod.rs +++ b/src/platform_impl/apple/appkit/mod.rs @@ -43,6 +43,15 @@ impl DeviceId { // Constant device ID; to be removed when if backend is updated to report real device IDs. pub(crate) const DEVICE_ID: RootDeviceId = RootDeviceId(DeviceId); +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct FingerId; + +impl FingerId { + pub const fn dummy() -> Self { + FingerId + } +} + #[derive(Debug)] pub enum OsError { CGError(core_graphics::base::CGError), diff --git a/src/platform_impl/apple/uikit/mod.rs b/src/platform_impl/apple/uikit/mod.rs index 2c3221e041..417587e7db 100644 --- a/src/platform_impl/apple/uikit/mod.rs +++ b/src/platform_impl/apple/uikit/mod.rs @@ -38,6 +38,15 @@ impl DeviceId { pub(crate) const DEVICE_ID: RootDeviceId = RootDeviceId(DeviceId); +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct FingerId(usize); + +impl FingerId { + pub const fn dummy() -> Self { + FingerId(0) + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct KeyEventExtra {} diff --git a/src/platform_impl/apple/uikit/view.rs b/src/platform_impl/apple/uikit/view.rs index 0c7fd39c0a..d946445eda 100644 --- a/src/platform_impl/apple/uikit/view.rs +++ b/src/platform_impl/apple/uikit/view.rs @@ -14,9 +14,9 @@ use objc2_ui_kit::{ use super::app_state::{self, EventWrapper}; use super::window::WinitUIWindow; -use super::DEVICE_ID; +use super::{FingerId, DEVICE_ID}; use crate::dpi::PhysicalPosition; -use crate::event::{Event, Force, Touch, TouchPhase, WindowEvent}; +use crate::event::{Event, FingerId as RootFingerId, Force, Touch, TouchPhase, WindowEvent}; use crate::window::{WindowAttributes, WindowId as RootWindowId}; pub struct WinitViewState { @@ -480,7 +480,7 @@ impl WinitView { } else { None }; - let touch_id = touch as *const UITouch as u64; + let touch_id = touch as *const UITouch as usize; let phase = touch.phase(); let phase = match phase { UITouchPhase::Began => TouchPhase::Started, @@ -502,7 +502,7 @@ impl WinitView { window_id: RootWindowId(window.id()), event: WindowEvent::Touch(Touch { device_id: DEVICE_ID, - id: touch_id, + finger_id: RootFingerId(FingerId(touch_id)), location: physical_location, force, phase, diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index b7e612c4b5..f2750a71a8 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -177,6 +177,23 @@ impl DeviceId { } } +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum FingerId { + #[cfg(x11_platform)] + X(x11::FingerId), + #[cfg(wayland_platform)] + Wayland(wayland::FingerId), +} + +impl FingerId { + pub const fn dummy() -> Self { + #[cfg(wayland_platform)] + return FingerId::Wayland(wayland::FingerId::dummy()); + #[cfg(all(not(wayland_platform), x11_platform))] + return FingerId::X(x11::FingerId::dummy()); + } +} + #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub enum MonitorHandle { #[cfg(x11_platform)] diff --git a/src/platform_impl/linux/wayland/mod.rs b/src/platform_impl/linux/wayland/mod.rs index 67e6e90d1e..18de24277d 100644 --- a/src/platform_impl/linux/wayland/mod.rs +++ b/src/platform_impl/linux/wayland/mod.rs @@ -71,6 +71,15 @@ impl DeviceId { } } +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct FingerId(i32); + +impl FingerId { + pub const fn dummy() -> Self { + FingerId(0) + } +} + /// Get the WindowId out of the surface. #[inline] fn make_wid(surface: &WlSurface) -> WindowId { diff --git a/src/platform_impl/linux/wayland/seat/touch/mod.rs b/src/platform_impl/linux/wayland/seat/touch/mod.rs index f4d2c14de5..665279f019 100644 --- a/src/platform_impl/linux/wayland/seat/touch/mod.rs +++ b/src/platform_impl/linux/wayland/seat/touch/mod.rs @@ -10,7 +10,7 @@ use tracing::warn; use crate::dpi::LogicalPosition; use crate::event::{Touch, TouchPhase, WindowEvent}; use crate::platform_impl::wayland::state::WinitState; -use crate::platform_impl::wayland::{self, DeviceId}; +use crate::platform_impl::wayland::{self, DeviceId, FingerId}; impl TouchHandler for WinitState { fn down( @@ -50,7 +50,9 @@ impl TouchHandler for WinitState { phase: TouchPhase::Started, location: location.to_physical(scale_factor), force: None, - id: id as u64, + finger_id: crate::event::FingerId(crate::platform_impl::FingerId::Wayland( + FingerId(id), + )), }), window_id, ); @@ -93,7 +95,9 @@ impl TouchHandler for WinitState { phase: TouchPhase::Ended, location: touch_point.location.to_physical(scale_factor), force: None, - id: id as u64, + finger_id: crate::event::FingerId(crate::platform_impl::FingerId::Wayland( + FingerId(id), + )), }), window_id, ); @@ -138,7 +142,9 @@ impl TouchHandler for WinitState { phase: TouchPhase::Moved, location: touch_point.location.to_physical(scale_factor), force: None, - id: id as u64, + finger_id: crate::event::FingerId(crate::platform_impl::FingerId::Wayland( + FingerId(id), + )), }), window_id, ); @@ -170,7 +176,9 @@ impl TouchHandler for WinitState { phase: TouchPhase::Cancelled, location, force: None, - id: id as u64, + finger_id: crate::event::FingerId(crate::platform_impl::FingerId::Wayland( + FingerId(id), + )), }), window_id, ); diff --git a/src/platform_impl/linux/x11/event_processor.rs b/src/platform_impl/linux/x11/event_processor.rs index 424464ce77..fa2c97013d 100644 --- a/src/platform_impl/linux/x11/event_processor.rs +++ b/src/platform_impl/linux/x11/event_processor.rs @@ -34,8 +34,8 @@ use crate::platform_impl::platform::ActiveEventLoop as PlatformActiveEventLoop; use crate::platform_impl::x11::atoms::*; use crate::platform_impl::x11::util::cookie::GenericEventCookie; use crate::platform_impl::x11::{ - mkdid, mkwid, util, CookieResultExt, Device, DeviceId, DeviceInfo, Dnd, DndState, ImeReceiver, - ScrollOrientation, UnownedWindow, WindowId, + mkdid, mkfid, mkwid, util, CookieResultExt, Device, DeviceId, DeviceInfo, Dnd, DndState, + ImeReceiver, ScrollOrientation, UnownedWindow, WindowId, }; /// The maximum amount of X modifiers to replay. @@ -61,7 +61,7 @@ pub struct EventProcessor { // // Used to detect key repeats. pub held_key_press: Option, - pub first_touch: Option, + pub first_touch: Option, // Currently focused window belonging to this process pub active_window: Option, /// Latest modifiers we've sent for the user to trigger change in event. @@ -1340,7 +1340,7 @@ impl EventProcessor { let window = xev.event as xproto::Window; if self.window_exists(window) { let window_id = mkwid(window); - let id = xev.detail as u64; + let id = xev.detail as u32; let location = PhysicalPosition::new(xev.event_x, xev.event_y); // Mouse cursor position changes when touch events are received. @@ -1363,7 +1363,7 @@ impl EventProcessor { phase, location, force: None, // TODO - id, + finger_id: mkfid(id), }), }; callback(&self.target, event) @@ -1817,7 +1817,7 @@ impl EventProcessor { } } -fn is_first_touch(first: &mut Option, num: &mut u32, id: u64, phase: TouchPhase) -> bool { +fn is_first_touch(first: &mut Option, num: &mut u32, id: u32, phase: TouchPhase) -> bool { match phase { TouchPhase::Started => { if *num == 0 { diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index e39228f243..555e790487 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -773,6 +773,16 @@ impl DeviceId { } } +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct FingerId(u32); + +impl FingerId { + #[allow(unused)] + pub const fn dummy() -> Self { + FingerId(0) + } +} + pub(crate) struct Window(Arc); impl Deref for Window { @@ -978,6 +988,10 @@ fn mkdid(w: xinput::DeviceId) -> crate::event::DeviceId { crate::event::DeviceId(crate::platform_impl::DeviceId::X(DeviceId(w))) } +fn mkfid(w: u32) -> crate::event::FingerId { + crate::event::FingerId(crate::platform_impl::FingerId::X(FingerId(w))) +} + #[derive(Debug)] pub struct Device { _name: String, diff --git a/src/platform_impl/orbital/mod.rs b/src/platform_impl/orbital/mod.rs index 2cfdd370de..34a8555309 100644 --- a/src/platform_impl/orbital/mod.rs +++ b/src/platform_impl/orbital/mod.rs @@ -127,6 +127,15 @@ impl DeviceId { } } +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct FingerId; + +impl FingerId { + pub const fn dummy() -> Self { + FingerId + } +} + #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] pub struct PlatformSpecificWindowAttributes; diff --git a/src/platform_impl/web/device.rs b/src/platform_impl/web/device.rs deleted file mode 100644 index 91d08586c8..0000000000 --- a/src/platform_impl/web/device.rs +++ /dev/null @@ -1,8 +0,0 @@ -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct DeviceId(pub i32); - -impl DeviceId { - pub const fn dummy() -> Self { - Self(0) - } -} diff --git a/src/platform_impl/web/event.rs b/src/platform_impl/web/event.rs new file mode 100644 index 0000000000..f55e5fe152 --- /dev/null +++ b/src/platform_impl/web/event.rs @@ -0,0 +1,32 @@ +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct DeviceId(i32); + +impl DeviceId { + pub fn new(pointer_id: i32) -> Self { + Self(pointer_id) + } + + pub const fn dummy() -> Self { + Self(-1) + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct FingerId { + pointer_id: i32, + primary: bool, +} + +impl FingerId { + pub fn new(pointer_id: i32, primary: bool) -> Self { + Self { pointer_id, primary } + } + + pub const fn dummy() -> Self { + Self { pointer_id: -1, primary: false } + } + + pub fn primary(self) -> bool { + self.primary + } +} diff --git a/src/platform_impl/web/event_loop/mod.rs b/src/platform_impl/web/event_loop/mod.rs index 6daa220b20..6aacc9b472 100644 --- a/src/platform_impl/web/event_loop/mod.rs +++ b/src/platform_impl/web/event_loop/mod.rs @@ -1,6 +1,6 @@ use std::marker::PhantomData; -use super::{backend, device, window}; +use super::{backend, event, window}; use crate::application::ApplicationHandler; use crate::error::EventLoopError; use crate::event::Event; diff --git a/src/platform_impl/web/event_loop/runner.rs b/src/platform_impl/web/event_loop/runner.rs index 317ff077fa..849dc446e5 100644 --- a/src/platform_impl/web/event_loop/runner.rs +++ b/src/platform_impl/web/event_loop/runner.rs @@ -251,7 +251,7 @@ impl Shared { } // chorded button event - let device_id = RootDeviceId(DeviceId(event.pointer_id())); + let device_id = RootDeviceId(DeviceId::new(event.pointer_id())); if let Some(button) = backend::event::mouse_button(&event) { debug_assert_eq!( @@ -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 }, }); } @@ -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.pointer_id())), event: DeviceEvent::Button { button: button.to_id(), state: ElementState::Pressed, @@ -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.pointer_id())), event: DeviceEvent::Button { button: button.to_id(), state: ElementState::Released, diff --git a/src/platform_impl/web/event_loop/window_target.rs b/src/platform_impl/web/event_loop/window_target.rs index 6a44a614cb..06e670f84d 100644 --- a/src/platform_impl/web/event_loop/window_target.rs +++ b/src/platform_impl/web/event_loop/window_target.rs @@ -9,12 +9,13 @@ use web_sys::Element; use super::super::monitor::MonitorHandle; use super::super::KeyEventExtra; -use super::device::DeviceId; +use super::event::DeviceId; use super::runner::{EventWrapper, Execution}; use super::window::WindowId; use super::{backend, runner, EventLoopProxy}; use crate::event::{ - DeviceId as RootDeviceId, ElementState, Event, KeyEvent, Touch, TouchPhase, WindowEvent, + DeviceId as RootDeviceId, ElementState, Event, FingerId as RootFingerId, KeyEvent, Touch, + TouchPhase, WindowEvent, }; use crate::event_loop::{ControlFlow, DeviceEvents}; use crate::keyboard::ModifiersState; @@ -225,11 +226,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() { @@ -252,11 +251,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() { @@ -286,7 +283,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); @@ -297,7 +294,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), @@ -311,7 +308,7 @@ impl ActiveEventLoop { let has_focus = has_focus.clone(); let modifiers = self.modifiers.clone(); - move |active_modifiers, device_id, events| { + move |active_modifiers, device_id, finger_id, events| { let modifiers = (has_focus.get() && modifiers.get() != active_modifiers).then(|| { modifiers.set(active_modifiers); @@ -325,8 +322,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)), + finger_id: RootFingerId(finger_id), + device_id: RootDeviceId(device_id), phase: TouchPhase::Moved, force: Some(force), location, @@ -341,7 +338,7 @@ impl ActiveEventLoop { let modifiers = self.modifiers.clone(); move |active_modifiers, - pointer_id, + device_id, position: crate::dpi::PhysicalPosition, buttons, button| { @@ -354,7 +351,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 @@ -398,7 +395,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 { @@ -407,7 +404,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 @@ -432,7 +429,7 @@ impl ActiveEventLoop { let runner = self.runner.clone(); let modifiers = self.modifiers.clone(); - move |active_modifiers, device_id, location, force| { + move |active_modifiers, device_id, finger_id, location, force| { let modifiers = (modifiers.get() != active_modifiers).then(|| { modifiers.set(active_modifiers); Event::WindowEvent { @@ -445,8 +442,8 @@ impl ActiveEventLoop { Event::WindowEvent { window_id: RootWindowId(id), event: WindowEvent::Touch(Touch { - id: device_id as u64, - device_id: RootDeviceId(DeviceId(device_id)), + finger_id: RootFingerId(finger_id), + device_id: RootDeviceId(device_id), phase: TouchPhase::Started, force: Some(force), location, @@ -478,7 +475,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); @@ -488,7 +485,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 @@ -514,7 +511,7 @@ impl ActiveEventLoop { let has_focus = has_focus.clone(); let modifiers = self.modifiers.clone(); - move |active_modifiers, device_id, location, force| { + move |active_modifiers, device_id, finger_id, location, force| { let modifiers = (has_focus.get() && modifiers.get() != active_modifiers).then(|| { modifiers.set(active_modifiers); @@ -528,8 +525,8 @@ impl ActiveEventLoop { Event::WindowEvent { window_id: RootWindowId(id), event: WindowEvent::Touch(Touch { - id: device_id as u64, - device_id: RootDeviceId(DeviceId(device_id)), + finger_id: RootFingerId(finger_id), + device_id: RootDeviceId(device_id), phase: TouchPhase::Ended, force: Some(force), location, @@ -542,7 +539,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); @@ -556,7 +553,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, }, @@ -565,12 +562,12 @@ impl ActiveEventLoop { }); let runner = self.runner.clone(); - canvas.on_touch_cancel(move |device_id, location, force| { + canvas.on_touch_cancel(move |device_id, finger_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)), + finger_id: RootFingerId(finger_id), + device_id: RootDeviceId(device_id), phase: TouchPhase::Cancelled, force: Some(force), location, diff --git a/src/platform_impl/web/mod.rs b/src/platform_impl/web/mod.rs index 9a8e3c6f95..11299da704 100644 --- a/src/platform_impl/web/mod.rs +++ b/src/platform_impl/web/mod.rs @@ -22,8 +22,8 @@ mod r#async; mod cursor; -mod device; mod error; +mod event; mod event_loop; mod keyboard; mod main_thread; @@ -36,8 +36,8 @@ pub(crate) use cursor::{ CustomCursorSource as PlatformCustomCursorSource, }; -pub use self::device::DeviceId; pub use self::error::OsError; +pub use self::event::{DeviceId, FingerId}; pub(crate) use self::event_loop::{ ActiveEventLoop, EventLoop, EventLoopProxy, OwnedDisplayHandle, PlatformSpecificEventLoopAttributes, diff --git a/src/platform_impl/web/web_sys/canvas.rs b/src/platform_impl/web/web_sys/canvas.rs index f515bbf5ce..5760df8359 100644 --- a/src/platform_impl/web/web_sys/canvas.rs +++ b/src/platform_impl/web/web_sys/canvas.rs @@ -12,6 +12,7 @@ use web_sys::{ }; use super::super::cursor::CursorHandler; +use super::super::event::{DeviceId, FingerId}; use super::super::main_thread::MainThreadMarker; use super::super::WindowId; use super::animation_frame::AnimationFrameHandler; @@ -316,14 +317,14 @@ impl Canvas { pub fn on_cursor_leave(&mut self, handler: F) where - F: 'static + FnMut(ModifiersState, Option), + F: 'static + FnMut(ModifiersState, Option), { self.pointer_handler.on_cursor_leave(&self.common, handler) } pub fn on_cursor_enter(&mut self, handler: F) where - F: 'static + FnMut(ModifiersState, Option), + F: 'static + FnMut(ModifiersState, Option), { self.pointer_handler.on_cursor_enter(&self.common, handler) } @@ -335,8 +336,8 @@ impl Canvas { touch_handler: T, ) where MOD: 'static + FnMut(ModifiersState), - M: 'static + FnMut(ModifiersState, i32, PhysicalPosition, MouseButton), - T: 'static + FnMut(ModifiersState, i32, PhysicalPosition, Force), + M: 'static + FnMut(ModifiersState, DeviceId, PhysicalPosition, MouseButton), + T: 'static + FnMut(ModifiersState, DeviceId, FingerId, PhysicalPosition, Force), { self.pointer_handler.on_mouse_release( &self.common, @@ -353,8 +354,8 @@ impl Canvas { touch_handler: T, ) where MOD: 'static + FnMut(ModifiersState), - M: 'static + FnMut(ModifiersState, i32, PhysicalPosition, MouseButton), - T: 'static + FnMut(ModifiersState, i32, PhysicalPosition, Force), + M: 'static + FnMut(ModifiersState, DeviceId, PhysicalPosition, MouseButton), + T: 'static + FnMut(ModifiersState, DeviceId, FingerId, PhysicalPosition, Force), { self.pointer_handler.on_mouse_press( &self.common, @@ -373,10 +374,17 @@ impl Canvas { button_handler: B, ) where MOD: 'static + FnMut(ModifiersState), - M: 'static + FnMut(ModifiersState, i32, &mut dyn Iterator>), + M: 'static + + FnMut(ModifiersState, DeviceId, &mut dyn Iterator>), T: 'static - + FnMut(ModifiersState, i32, &mut dyn Iterator, Force)>), - B: 'static + FnMut(ModifiersState, i32, PhysicalPosition, ButtonsState, MouseButton), + + FnMut( + ModifiersState, + DeviceId, + FingerId, + &mut dyn Iterator, Force)>, + ), + B: 'static + + FnMut(ModifiersState, DeviceId, PhysicalPosition, ButtonsState, MouseButton), { self.pointer_handler.on_cursor_move( &self.common, @@ -390,14 +398,14 @@ impl Canvas { pub fn on_touch_cancel(&mut self, handler: F) where - F: 'static + FnMut(i32, PhysicalPosition, Force), + F: 'static + FnMut(DeviceId, FingerId, PhysicalPosition, Force), { self.pointer_handler.on_touch_cancel(&self.common, handler) } pub fn on_mouse_wheel(&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); @@ -408,7 +416,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); } })); } diff --git a/src/platform_impl/web/web_sys/pointer.rs b/src/platform_impl/web/web_sys/pointer.rs index f5e9365d5c..2c8a2d9948 100644 --- a/src/platform_impl/web/web_sys/pointer.rs +++ b/src/platform_impl/web/web_sys/pointer.rs @@ -4,6 +4,7 @@ use std::rc::Rc; use event::ButtonsState; use web_sys::PointerEvent; +use super::super::event::{DeviceId, FingerId}; use super::canvas::Common; use super::event; use super::event_handle::EventListenerHandle; @@ -35,7 +36,7 @@ impl PointerHandler { pub fn on_cursor_leave(&mut self, canvas_common: &Common, mut handler: F) where - F: 'static + FnMut(ModifiersState, Option), + F: 'static + FnMut(ModifiersState, Option), { self.on_cursor_leave = Some(canvas_common.add_event("pointerout", move |event: PointerEvent| { @@ -44,15 +45,16 @@ impl PointerHandler { // touch events are handled separately // handling them here would produce duplicate mouse events, inconsistent with // other platforms. - let pointer_id = (event.pointer_type() == "mouse").then(|| event.pointer_id()); + let device_id = + (event.pointer_type() == "mouse").then(|| DeviceId::new(event.pointer_id())); - handler(modifiers, pointer_id); + handler(modifiers, device_id); })); } pub fn on_cursor_enter(&mut self, canvas_common: &Common, mut handler: F) where - F: 'static + FnMut(ModifiersState, Option), + F: 'static + FnMut(ModifiersState, Option), { self.on_cursor_enter = Some(canvas_common.add_event("pointerover", move |event: PointerEvent| { @@ -61,9 +63,10 @@ impl PointerHandler { // touch events are handled separately // handling them here would produce duplicate mouse events, inconsistent with // other platforms. - let pointer_id = (event.pointer_type() == "mouse").then(|| event.pointer_id()); + let device_id = + (event.pointer_type() == "mouse").then(|| DeviceId::new(event.pointer_id())); - handler(modifiers, pointer_id); + handler(modifiers, device_id); })); } @@ -75,8 +78,8 @@ impl PointerHandler { mut touch_handler: T, ) where MOD: 'static + FnMut(ModifiersState), - M: 'static + FnMut(ModifiersState, i32, PhysicalPosition, MouseButton), - T: 'static + FnMut(ModifiersState, i32, PhysicalPosition, Force), + M: 'static + FnMut(ModifiersState, DeviceId, PhysicalPosition, MouseButton), + T: 'static + FnMut(ModifiersState, DeviceId, FingerId, PhysicalPosition, Force), { let window = canvas_common.window.clone(); self.on_pointer_release = @@ -84,15 +87,19 @@ impl PointerHandler { let modifiers = event::mouse_modifiers(&event); match event.pointer_type().as_str() { - "touch" => touch_handler( - modifiers, - event.pointer_id(), - event::mouse_position(&event).to_physical(super::scale_factor(&window)), - Force::Normalized(event.pressure() as f64), - ), + "touch" => { + let pointer_id = event.pointer_id(); + touch_handler( + modifiers, + DeviceId::new(pointer_id), + FingerId::new(pointer_id, event.is_primary()), + event::mouse_position(&event).to_physical(super::scale_factor(&window)), + Force::Normalized(event.pressure() as f64), + ) + }, "mouse" => mouse_handler( modifiers, - event.pointer_id(), + DeviceId::new(event.pointer_id()), event::mouse_position(&event).to_physical(super::scale_factor(&window)), event::mouse_button(&event).expect("no mouse button released"), ), @@ -110,8 +117,8 @@ impl PointerHandler { prevent_default: Rc>, ) where MOD: 'static + FnMut(ModifiersState), - M: 'static + FnMut(ModifiersState, i32, PhysicalPosition, MouseButton), - T: 'static + FnMut(ModifiersState, i32, PhysicalPosition, Force), + M: 'static + FnMut(ModifiersState, DeviceId, PhysicalPosition, MouseButton), + T: 'static + FnMut(ModifiersState, DeviceId, FingerId, PhysicalPosition, Force), { let window = canvas_common.window.clone(); let canvas = canvas_common.raw().clone(); @@ -128,9 +135,11 @@ impl PointerHandler { match event.pointer_type().as_str() { "touch" => { + let pointer_id = event.pointer_id(); touch_handler( modifiers, - event.pointer_id(), + DeviceId::new(pointer_id), + FingerId::new(pointer_id, event.is_primary()), event::mouse_position(&event).to_physical(super::scale_factor(&window)), Force::Normalized(event.pressure() as f64), ); @@ -138,7 +147,7 @@ impl PointerHandler { "mouse" => { mouse_handler( modifiers, - event.pointer_id(), + DeviceId::new(event.pointer_id()), event::mouse_position(&event).to_physical(super::scale_factor(&window)), event::mouse_button(&event).expect("no mouse button pressed"), ); @@ -164,10 +173,17 @@ impl PointerHandler { prevent_default: Rc>, ) where MOD: 'static + FnMut(ModifiersState), - M: 'static + FnMut(ModifiersState, i32, &mut dyn Iterator>), + M: 'static + + FnMut(ModifiersState, DeviceId, &mut dyn Iterator>), T: 'static - + FnMut(ModifiersState, i32, &mut dyn Iterator, Force)>), - B: 'static + FnMut(ModifiersState, i32, PhysicalPosition, ButtonsState, MouseButton), + + FnMut( + ModifiersState, + DeviceId, + FingerId, + &mut dyn Iterator, Force)>, + ), + B: 'static + + FnMut(ModifiersState, DeviceId, PhysicalPosition, ButtonsState, MouseButton), { let window = canvas_common.window.clone(); let canvas = canvas_common.raw().clone(); @@ -182,8 +198,8 @@ impl PointerHandler { modifier_handler(modifiers); return; } - - let id = event.pointer_id(); + let pointer_id = event.pointer_id(); + let device_id = DeviceId::new(pointer_id); // chorded button event if let Some(button) = event::mouse_button(&event) { @@ -201,7 +217,7 @@ impl PointerHandler { button_handler( modifiers, - id, + device_id, event::mouse_position(&event).to_physical(super::scale_factor(&window)), event::mouse_buttons(&event), button, @@ -215,13 +231,14 @@ impl PointerHandler { match pointer_type.as_str() { "mouse" => mouse_handler( modifiers, - id, + device_id, &mut event::pointer_move_event(event) .map(|event| event::mouse_position(&event).to_physical(scale)), ), "touch" => touch_handler( modifiers, - id, + device_id, + FingerId::new(pointer_id, event.is_primary()), &mut event::pointer_move_event(event).map(|event| { ( event::mouse_position(&event).to_physical(scale), @@ -236,14 +253,16 @@ impl PointerHandler { pub fn on_touch_cancel(&mut self, canvas_common: &Common, mut handler: F) where - F: 'static + FnMut(i32, PhysicalPosition, Force), + F: 'static + FnMut(DeviceId, FingerId, PhysicalPosition, Force), { let window = canvas_common.window.clone(); self.on_touch_cancel = Some(canvas_common.add_event("pointercancel", move |event: PointerEvent| { if event.pointer_type() == "touch" { + let pointer_id = event.pointer_id(); handler( - event.pointer_id(), + DeviceId::new(pointer_id), + FingerId::new(pointer_id, event.is_primary()), event::mouse_position(&event).to_physical(super::scale_factor(&window)), Force::Normalized(event.pressure() as f64), ); diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index f9ad3fad8c..5e9a7e016c 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -27,11 +27,11 @@ use windows_sys::Win32::UI::Input::KeyboardAndMouse::{ ReleaseCapture, SetCapture, TrackMouseEvent, TME_LEAVE, TRACKMOUSEEVENT, }; use windows_sys::Win32::UI::Input::Pointer::{ - POINTER_FLAG_DOWN, POINTER_FLAG_UP, POINTER_FLAG_UPDATE, + POINTER_FLAG_DOWN, POINTER_FLAG_PRIMARY, POINTER_FLAG_UP, POINTER_FLAG_UPDATE, }; use windows_sys::Win32::UI::Input::Touch::{ - CloseTouchInputHandle, GetTouchInputInfo, TOUCHEVENTF_DOWN, TOUCHEVENTF_MOVE, TOUCHEVENTF_UP, - TOUCHINPUT, + CloseTouchInputHandle, GetTouchInputInfo, TOUCHEVENTF_DOWN, TOUCHEVENTF_MOVE, + TOUCHEVENTF_PRIMARY, TOUCHEVENTF_UP, TOUCHINPUT, }; use windows_sys::Win32::UI::Input::{RAWINPUT, RIM_TYPEKEYBOARD, RIM_TYPEMOUSE}; use windows_sys::Win32::UI::WindowsAndMessaging::{ @@ -61,7 +61,8 @@ use crate::application::ApplicationHandler; use crate::dpi::{PhysicalPosition, PhysicalSize}; use crate::error::EventLoopError; use crate::event::{ - DeviceEvent, Event, Force, Ime, InnerSizeWriter, RawKeyEvent, Touch, TouchPhase, WindowEvent, + DeviceEvent, Event, FingerId as RootFingerId, Force, Ime, InnerSizeWriter, RawKeyEvent, Touch, + TouchPhase, WindowEvent, }; use crate::event_loop::{ActiveEventLoop as RootAEL, ControlFlow, DeviceEvents}; use crate::keyboard::ModifiersState; @@ -79,7 +80,7 @@ use crate::platform_impl::platform::window_state::{ CursorFlags, ImeState, WindowFlags, WindowState, }; use crate::platform_impl::platform::{ - raw_input, util, wrap_device_id, Fullscreen, WindowId, DEVICE_ID, + raw_input, util, wrap_device_id, FingerId, Fullscreen, WindowId, DEVICE_ID, }; use crate::utils::Lazy; use crate::window::{ @@ -1822,7 +1823,10 @@ unsafe fn public_window_callback_inner( }, location, force: None, // WM_TOUCH doesn't support pressure information - id: input.dwID as u64, + finger_id: RootFingerId(FingerId { + id: input.dwID, + primary: util::has_flag(input.dwFlags, TOUCHEVENTF_PRIMARY), + }), device_id: DEVICE_ID, }), }); @@ -1968,7 +1972,13 @@ unsafe fn public_window_callback_inner( }, location, force, - id: pointer_info.pointerId as u64, + finger_id: RootFingerId(FingerId { + id: pointer_info.pointerId, + primary: util::has_flag( + pointer_info.pointerFlags, + POINTER_FLAG_PRIMARY, + ), + }), device_id: DEVICE_ID, }), }); diff --git a/src/platform_impl/windows/mod.rs b/src/platform_impl/windows/mod.rs index 4b3255c4dd..34fc7bbdcc 100644 --- a/src/platform_impl/windows/mod.rs +++ b/src/platform_impl/windows/mod.rs @@ -79,6 +79,24 @@ impl DeviceId { } } +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct FingerId { + id: u32, + primary: bool, +} + +impl FingerId { + pub const fn dummy() -> Self { + FingerId { id: 0, primary: false } + } +} + +impl FingerId { + pub fn primary(self) -> bool { + self.primary + } +} + // Constant device ID, to be removed when this backend is updated to report real device IDs. const DEVICE_ID: RootDeviceId = RootDeviceId(DeviceId(0));