From fafa90dae35b6c4dc5150f2642f4eeafb51301be Mon Sep 17 00:00:00 2001 From: daxpedda Date: Sat, 17 Aug 2024 00:09:15 +0200 Subject: [PATCH] Implement the pointer event overhaul - Rename `CursorMoved` to `PointerMoved`. - Rename `CursorEntered` to `PointerEntered`. - Rename `CursorLeft` to `PointerLeft`. - Rename `MouseInput` to `PointerButton`. - Add `position` to every `PointerEvent`. - Remove `Touch`, which is folded into the `Pointer*` events. - New `PointerType` added to `PointerEntered` and `PointerLeft`, signifying which pointer type is the source of this event. - New `PointerSource` added to `PointerMoved`, similar to `PointerType` but holding additional data. - New `ButtonSource` added to `PointerButton`, similar to `PointerType` but holding pointer type specific buttons. Use `ButtonSource::mouse_button()` to easily normalize any pointer button type to a generic mouse button. - In the same spirit rename `DeviceEvent::MouseMotion` to `PointerMotion`. - Remove `Force::Calibrated::altitude_angle`. --- examples/child_window.rs | 2 +- examples/window.rs | 15 +- src/changelog/unreleased.md | 32 +- src/event.rs | 341 ++++++++++------ src/platform/web.rs | 11 +- src/platform_impl/android/mod.rs | 58 ++- src/platform_impl/apple/appkit/app.rs | 2 +- src/platform_impl/apple/appkit/view.rs | 57 ++- src/platform_impl/apple/uikit/view.rs | 119 ++++-- src/platform_impl/linux/common/xkb/keymap.rs | 2 +- .../linux/wayland/seat/pointer/mod.rs | 36 +- .../wayland/seat/pointer/relative_pointer.rs | 2 +- .../linux/wayland/seat/touch/mod.rs | 89 +++-- .../linux/x11/event_processor.rs | 166 +++++--- src/platform_impl/orbital/event_loop.rs | 22 +- src/platform_impl/web/event.rs | 8 + src/platform_impl/web/event_loop/runner.rs | 8 +- .../web/event_loop/window_target.rs | 303 ++++---------- src/platform_impl/web/web_sys/canvas.rs | 65 ++- src/platform_impl/web/web_sys/event.rs | 15 +- src/platform_impl/web/web_sys/mod.rs | 1 - src/platform_impl/web/web_sys/pointer.rs | 252 ++++++------ src/platform_impl/windows/event_loop.rs | 377 ++++++++++++------ src/platform_impl/windows/util.rs | 7 +- 24 files changed, 1153 insertions(+), 837 deletions(-) diff --git a/examples/child_window.rs b/examples/child_window.rs index 7b5914133d..0b2e2dc329 100644 --- a/examples/child_window.rs +++ b/examples/child_window.rs @@ -44,7 +44,7 @@ fn main() -> Result<(), impl std::error::Error> { self.windows.clear(); event_loop.exit(); }, - WindowEvent::CursorEntered { device_id: _ } => { + WindowEvent::PointerEntered { device_id: _, .. } => { // On x11, println when the cursor entered in a window even if the child window // is created by some key inputs. // the child windows are always placed at (0, 0) with size (200, 200) in the diff --git a/examples/window.rs b/examples/window.rs index 61bd51bd72..d9d23f91f3 100644 --- a/examples/window.rs +++ b/examples/window.rs @@ -446,19 +446,21 @@ impl ApplicationHandler for Application { } } }, - WindowEvent::MouseInput { button, state, .. } => { + WindowEvent::PointerButton { button, state, .. } => { let mods = window.modifiers; - if let Some(action) = - state.is_pressed().then(|| Self::process_mouse_binding(button, &mods)).flatten() + if let Some(action) = state + .is_pressed() + .then(|| Self::process_mouse_binding(button.mouse_button(), &mods)) + .flatten() { self.handle_action_with_window(event_loop, window_id, action); } }, - WindowEvent::CursorLeft { .. } => { + WindowEvent::PointerLeft { .. } => { info!("Cursor left Window={window_id:?}"); window.cursor_left(); }, - WindowEvent::CursorMoved { position, .. } => { + WindowEvent::PointerMoved { position, .. } => { info!("Moved cursor to {position:?}"); window.cursor_moved(position); }, @@ -510,11 +512,10 @@ impl ApplicationHandler for Application { WindowEvent::TouchpadPressure { .. } | WindowEvent::HoveredFileCancelled | WindowEvent::KeyboardInput { .. } - | WindowEvent::CursorEntered { .. } + | WindowEvent::PointerEntered { .. } | WindowEvent::DroppedFile(_) | WindowEvent::HoveredFile(_) | WindowEvent::Destroyed - | WindowEvent::Touch(_) | WindowEvent::Moved(_) => (), } } diff --git a/src/changelog/unreleased.md b/src/changelog/unreleased.md index 5d797b034d..a39018bde4 100644 --- a/src/changelog/unreleased.md +++ b/src/changelog/unreleased.md @@ -56,12 +56,11 @@ changelog entry. Keep in mind that handles do not auto-upgrade after permissions are granted and have to be re-created to make full use of this feature. -- Add `Touch::finger_id` with a new type `FingerId`. -- On Web and Windows, add `FingerIdExt*::is_primary()`, exposing a way to determine - the primary finger in a multi-touch interaction. - Implement `Clone`, `Copy`, `Debug`, `Deserialize`, `Eq`, `Hash`, `Ord`, `PartialEq`, `PartialOrd` and `Serialize` on many types. - Add `MonitorHandle::current_video_mode()`. +- Add `PointerType`, `PointerSource`, `ButtonSource`, `FingerId` and `position` to all pointer + events as part of the pointer event overhaul. ### Changed @@ -101,6 +100,29 @@ changelog entry. application delegate yourself. - On iOS, no longer act as-if the application successfully open all URLs. Override `application:didFinishLaunchingWithOptions:` and provide the desired behaviour yourself. +- Pointer `WindowEvent`s were overhauled. The new events can handle any type of pointer, serving as + a single pointer input source. Now your application can handle any pointer type without having to + explicitly handle e.g. `Touch`! + + - Rename `CursorMoved` to `PointerMoved`. + - Rename `CursorEntered` to `PointerEntered`. + - Rename `CursorLeft` to `PointerLeft`. + - Rename `MouseInput` to `PointerButton`. + - Add `position` to every `PointerEvent`. + - Remove `Touch`, which is folded into the `Pointer*` events. + - New `PointerType` added to `PointerEntered` and `PointerLeft`, signifying which pointer type is + the source of this event. + - New `PointerSource` added to `PointerMoved`, similar to `PointerType` but holding additional + data. + - New `ButtonSource` added to `PointerButton`, similar to `PointerType` but holding pointer type + specific buttons. Use `ButtonSource::mouse_button()` to easily normalize any pointer button + type to a generic mouse button. + - New `FingerId` added to `PointerType::Touch` and `PointerSource::Touch` able to uniquely + identify a finger in a multi-touch interaction. Replaces the old `Touch::id`. + - On Web and Windows, add `FingerIdExt*::is_primary()`, exposing a way to determine + the primary finger in a multi-touch interaction. + - In the same spirit rename `DeviceEvent::MouseMotion` to `PointerMotion`. + - Remove `Force::Calibrated::altitude_angle`. ### Removed @@ -123,10 +145,12 @@ changelog entry. v0.5 support. v0.6 remains in place and is enabled by default. - Remove `DeviceEvent::Added` and `DeviceEvent::Removed`. - Remove `DeviceEvent::Motion` and `WindowEvent::AxisMotion`. -- Remove `Touch::id` in favor of `Touch::finger_id`. - Remove `MonitorHandle::size()` and `refresh_rate_millihertz()` in favor of `MonitorHandle::current_video_mode()`. - On Android, remove all `MonitorHandle` support instead of emitting false data. +- Remove `WindowEvent::Touch` and `Touch` in favor of the new `PointerType`, `PointerSource` and + `ButtonSource` as part of the new pointer event overhaul. +- Remove `Force::altitude_angle`. ### Fixed diff --git a/src/event.rs b/src/event.rs index ec7fd97569..0888aaaa3f 100644 --- a/src/event.rs +++ b/src/event.rs @@ -222,51 +222,86 @@ pub enum WindowEvent { Ime(Ime), /// The cursor has moved on the window. - /// - /// ## Platform-specific - /// - /// - **Web:** Doesn't take into account CSS [`border`], [`padding`], or [`transform`]. - /// - /// [`border`]: https://developer.mozilla.org/en-US/docs/Web/CSS/border - /// [`padding`]: https://developer.mozilla.org/en-US/docs/Web/CSS/padding - /// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform - CursorMoved { + PointerMoved { device_id: DeviceId, /// (x,y) coords in pixels relative to the top-left corner of the window. Because the range /// of this data is limited by the display area and it may have been transformed by /// the OS to implement effects such as cursor acceleration, it should not be used /// to implement non-cursor-like interactions such as 3D camera control. + /// + /// ## Platform-specific + /// + /// **Web:** Doesn't take into account CSS [`border`], [`padding`], or [`transform`]. + /// + /// [`border`]: https://developer.mozilla.org/en-US/docs/Web/CSS/border + /// [`padding`]: https://developer.mozilla.org/en-US/docs/Web/CSS/padding + /// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform position: PhysicalPosition, + + source: PointerSource, }, /// The cursor has entered the window. - /// - /// ## Platform-specific - /// - /// - **Web:** Doesn't take into account CSS [`border`], [`padding`], or [`transform`]. - /// - /// [`border`]: https://developer.mozilla.org/en-US/docs/Web/CSS/border - /// [`padding`]: https://developer.mozilla.org/en-US/docs/Web/CSS/padding - /// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform - CursorEntered { device_id: DeviceId }, + PointerEntered { + device_id: DeviceId, + + /// The position of the cursor when it entered the window. + /// + /// ## Platform-specific + /// + /// **Orbital: Always emits `(0., 0.)`. + /// **Web:** Doesn't take into account CSS [`border`], [`padding`], or [`transform`]. + /// + /// [`border`]: https://developer.mozilla.org/en-US/docs/Web/CSS/border + /// [`padding`]: https://developer.mozilla.org/en-US/docs/Web/CSS/padding + /// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform + position: PhysicalPosition, + + ty: PointerType, + }, /// The cursor has left the window. - /// - /// ## Platform-specific - /// - /// - **Web:** Doesn't take into account CSS [`border`], [`padding`], or [`transform`]. - /// - /// [`border`]: https://developer.mozilla.org/en-US/docs/Web/CSS/border - /// [`padding`]: https://developer.mozilla.org/en-US/docs/Web/CSS/padding - /// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform - CursorLeft { device_id: DeviceId }, + PointerLeft { + device_id: DeviceId, + + /// The position of the cursor when it left the window. + /// + /// ## Platform-specific + /// + /// **Orbital/Windows:** Always emits [`None`]. + /// **Web:** Doesn't take into account CSS [`border`], [`padding`], or [`transform`]. + /// + /// [`border`]: https://developer.mozilla.org/en-US/docs/Web/CSS/border + /// [`padding`]: https://developer.mozilla.org/en-US/docs/Web/CSS/padding + /// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform + position: Option>, + + ty: PointerType, + }, /// A mouse wheel movement or touchpad scroll occurred. MouseWheel { device_id: DeviceId, delta: MouseScrollDelta, phase: TouchPhase }, /// An mouse button press has been received. - MouseInput { device_id: DeviceId, state: ElementState, button: MouseButton }, + PointerButton { + device_id: DeviceId, + state: ElementState, + + /// The position of the pointer when the button was pressed. + /// + /// ## Platform-specific + /// + /// - **Orbital: Always emits `(0., 0.)`. + /// - **Web:** Doesn't take into account CSS [`border`], [`padding`], or [`transform`]. + /// + /// [`border`]: https://developer.mozilla.org/en-US/docs/Web/CSS/border + /// [`padding`]: https://developer.mozilla.org/en-US/docs/Web/CSS/padding + /// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform + position: PhysicalPosition, + + button: ButtonSource, + }, /// Two-finger pinch gesture, often used for magnification. /// @@ -340,18 +375,6 @@ pub enum WindowEvent { /// touchpad is being pressed) and stage (integer representing the click level). TouchpadPressure { device_id: DeviceId, pressure: f32, stage: i64 }, - /// Touch event has been received - /// - /// ## Platform-specific - /// - /// - **Web:** Doesn't take into account CSS [`border`], [`padding`], or [`transform`]. - /// - **macOS:** Unsupported. - /// - /// [`border`]: https://developer.mozilla.org/en-US/docs/Web/CSS/border - /// [`padding`]: https://developer.mozilla.org/en-US/docs/Web/CSS/padding - /// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform - Touch(Touch), - /// The window's scale factor has changed. /// /// The following user actions can cause DPI changes: @@ -425,6 +448,118 @@ pub enum WindowEvent { RedrawRequested, } +/// Represents the pointer type of a pointer event. +/// +/// ## Platform-specific +/// +/// **Wayland/X11:** Can only identify [`Touch`](Self::Touch), any other pointer is identified as +/// [`Mouse`](Self::Mouse). +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum PointerType { + Mouse, + /// See [`PointerSource::Touch`] for more details. + /// + /// ## Platform-specific + /// + /// **macOS:** Unsupported. + Touch(FingerId), + Unknown, +} + +/// Represents the pointer type and its data for a pointer event. +/// +/// ## Platform-specific +/// +/// **Wayland/X11:** Can only identify [`Touch`](Self::Touch), any other pointer is identified as +/// [`Mouse`](Self::Mouse). +#[derive(Clone, Debug, PartialEq)] +pub enum PointerSource { + Mouse, + /// Represents a touch event + /// + /// Every time the user touches the screen, a [`WindowEvent::PointerEntered`] and a + /// [`WindowEvent::PointerButton`] with [`ElementState::Pressed`] event with an unique + /// identifier for the finger is emitted. When a finger is lifted, a + /// [`WindowEvent::PointerButton`] with [`ElementState::Released`] and a + /// [`WindowEvent::PointerLeft`] event is generated with the same [`FingerId`]. + /// + /// After a [`WindowEvent::PointerEntered`] event has been emitted, there may be zero or more + /// [`WindowEvent::PointerMoved`] events when the finger is moved or the touch pressure + /// changes. + /// + /// A [`WindowEvent::PointerLeft`] without a [`WindowEvent::PointerButton`] with + /// [`ElementState::Released`] event is emitted when the system has canceled tracking this + /// touch, such as when the window loses focus, or on mobile devices if the user moves the + /// device against their face. + /// + /// The [`FingerId`] may be reused by the system after a [`WindowEvent::PointerLeft`] event. + /// The user should assume that a new [`WindowEvent::PointerEntered`] event received with the + /// same ID has nothing to do with the old finger and is a new finger. + /// + /// ## Platform-specific + /// + /// **macOS:** Unsupported. + Touch { + finger_id: FingerId, + force: Option, + }, + Unknown, +} + +impl From for PointerType { + fn from(source: PointerSource) -> Self { + match source { + PointerSource::Mouse => Self::Mouse, + PointerSource::Touch { finger_id, .. } => Self::Touch(finger_id), + PointerSource::Unknown => Self::Unknown, + } + } +} + +/// Represents the pointer type of a [`WindowEvent::PointerButton`]. +/// +/// ## Platform-specific +/// +/// **Wayland/X11:** Can only identify [`Touch`](Self::Touch), any other pointer is identified as +/// [`Mouse`](Self::Mouse). +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum ButtonSource { + Mouse(MouseButton), + /// See [`PointerSource::Touch`] for more details. + /// + /// ## Platform-specific + /// + /// **macOS:** Unsupported. + Touch { + finger_id: FingerId, + force: Option, + }, + Unknown(u16), +} + +impl ButtonSource { + pub fn mouse_button(self) -> MouseButton { + match self { + ButtonSource::Mouse(mouse) => mouse, + ButtonSource::Touch { .. } => MouseButton::Left, + ButtonSource::Unknown(button) => match button { + 0 => MouseButton::Left, + 1 => MouseButton::Middle, + 2 => MouseButton::Right, + 3 => MouseButton::Back, + 4 => MouseButton::Forward, + _ => MouseButton::Other(button), + }, + } + } +} + +impl From for ButtonSource { + fn from(mouse: MouseButton) -> Self { + Self::Mouse(mouse) + } +} + /// Identifier of an input device. /// /// Whenever you receive an event arising from a particular input device, this event contains a @@ -486,7 +621,7 @@ pub enum DeviceEvent { /// Change in physical position of a pointing device. /// /// This represents raw, unfiltered physical motion. Not to be confused with - /// [`WindowEvent::CursorMoved`]. + /// [`WindowEvent::PointerMoved`]. /// /// ## Platform-specific /// @@ -503,7 +638,7 @@ pub enum DeviceEvent { /// #[rustfmt::skip] /// [`CursorGrabMode::Locked`]: crate::window::CursorGrabMode::Locked - MouseMotion { + PointerMotion { /// (x, y) change in position in unspecified units. /// /// Different devices may use different units. @@ -832,50 +967,6 @@ pub enum TouchPhase { Cancelled, } -/// Represents a touch event -/// -/// Every time the user touches the screen, a new [`TouchPhase::Started`] event with an unique -/// identifier for the finger is generated. When the finger is lifted, an [`TouchPhase::Ended`] -/// event is generated with the same finger id. -/// -/// After a `Started` event has been emitted, there may be zero or more `Move` -/// events when the finger is moved or the touch pressure changes. -/// -/// The finger id may be reused by the system after an `Ended` event. The user -/// should assume that a new `Started` event received with the same id has nothing -/// to do with the old finger and is a new finger. -/// -/// A [`TouchPhase::Cancelled`] event is emitted when the system has canceled tracking this -/// touch, such as when the window loses focus, or on iOS if the user moves the -/// device against their face. -/// -/// ## Platform-specific -/// -/// - **Web:** Doesn't take into account CSS [`border`], [`padding`], or [`transform`]. -/// - **macOS:** Unsupported. -/// -/// [`border`]: https://developer.mozilla.org/en-US/docs/Web/CSS/border -/// [`padding`]: https://developer.mozilla.org/en-US/docs/Web/CSS/padding -/// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct Touch { - pub device_id: DeviceId, - pub phase: TouchPhase, - pub location: PhysicalPosition, - /// Describes how hard the screen was pressed. May be `None` if the platform - /// does not support pressure sensitivity. - /// - /// ## Platform-specific - /// - /// - Only available on **iOS** 9.0+, **Windows** 8+, **Web**, and **Android**. - /// - **Android**: This will never be [None]. If the device doesn't support pressure - /// sensitivity, force will either be 0.0 or 1.0. Also see the - /// [android documentation](https://developer.android.com/reference/android/view/MotionEvent#AXIS_PRESSURE). - pub force: Option, - /// Unique identifier of a finger. - pub finger_id: FingerId, -} - /// Describes the force of a touch event #[derive(Debug, Clone, Copy, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] @@ -896,12 +987,6 @@ pub enum Force { /// The value of this field is sufficiently high to provide a wide /// dynamic range for values of the `force` field. max_possible_force: f64, - /// The altitude (in radians) of the stylus. - /// - /// A value of 0 radians indicates that the stylus is parallel to the - /// surface. The value of this property is Pi/2 when the stylus is - /// perpendicular to the surface. - altitude_angle: Option, }, /// If the platform reports the force as normalized, we have no way of /// knowing how much pressure 1.0 corresponds to – we know it's the maximum @@ -918,13 +1003,7 @@ impl Force { /// consistent across devices. pub fn normalized(&self) -> f64 { match self { - Force::Calibrated { force, max_possible_force, altitude_angle } => { - let force = match altitude_angle { - Some(altitude_angle) => force / altitude_angle.sin(), - None => *force, - }; - force / max_possible_force - }, + Force::Calibrated { force, max_possible_force } => force / max_possible_force, Force::Normalized(force) => *force, } } @@ -1049,6 +1128,7 @@ mod tests { use crate::event::Event::*; use crate::event::Ime::Enabled; use crate::event::WindowEvent::*; + use crate::event::{PointerSource, PointerType}; use crate::window::WindowId; // Mainline events. @@ -1071,19 +1151,41 @@ mod tests { with_window_event(HoveredFile("x.txt".into())); with_window_event(HoveredFileCancelled); with_window_event(Ime(Enabled)); - with_window_event(CursorMoved { device_id: did, position: (0, 0).into() }); + with_window_event(PointerMoved { + device_id: did, + position: (0, 0).into(), + source: PointerSource::Mouse, + }); with_window_event(ModifiersChanged(event::Modifiers::default())); - with_window_event(CursorEntered { device_id: did }); - with_window_event(CursorLeft { device_id: did }); + with_window_event(PointerEntered { + device_id: did, + position: (0, 0).into(), + ty: PointerType::Mouse, + }); + with_window_event(PointerLeft { + device_id: did, + position: Some((0, 0).into()), + ty: PointerType::Mouse, + }); with_window_event(MouseWheel { device_id: did, delta: event::MouseScrollDelta::LineDelta(0.0, 0.0), phase: event::TouchPhase::Started, }); - with_window_event(MouseInput { + with_window_event(PointerButton { device_id: did, state: event::ElementState::Pressed, - button: event::MouseButton::Other(0), + position: (0, 0).into(), + button: event::MouseButton::Other(0).into(), + }); + with_window_event(PointerButton { + device_id: did, + state: event::ElementState::Released, + position: (0, 0).into(), + button: event::ButtonSource::Touch { + finger_id: fid, + force: Some(event::Force::Normalized(0.0)), + }, }); with_window_event(PinchGesture { device_id: did, @@ -1102,13 +1204,6 @@ mod tests { phase: event::TouchPhase::Started, }); with_window_event(TouchpadPressure { device_id: did, pressure: 0.0, stage: 0 }); - with_window_event(Touch(event::Touch { - device_id: did, - phase: event::TouchPhase::Started, - location: (0.0, 0.0).into(), - finger_id: fid, - force: Some(event::Force::Normalized(0.0)), - })); with_window_event(ThemeChanged(crate::window::Theme::Light)); with_window_event(Occluded(true)); } @@ -1120,7 +1215,7 @@ mod tests { let with_device_event = |dev_ev| x(event::Event::DeviceEvent { device_id: did, event: dev_ev }); - with_device_event(MouseMotion { delta: (0.0, 0.0).into() }); + with_device_event(PointerMotion { delta: (0.0, 0.0).into() }); with_device_event(MouseWheel { delta: event::MouseScrollDelta::LineDelta(0.0, 0.0), }); @@ -1143,15 +1238,10 @@ mod tests { let force = event::Force::Normalized(0.0); assert_eq!(force.normalized(), 0.0); - let force2 = - event::Force::Calibrated { force: 5.0, max_possible_force: 2.5, altitude_angle: None }; + let force2 = event::Force::Calibrated { force: 5.0, max_possible_force: 2.5 }; assert_eq!(force2.normalized(), 2.0); - let force3 = event::Force::Calibrated { - force: 5.0, - max_possible_force: 2.5, - altitude_angle: Some(std::f64::consts::PI / 2.0), - }; + let force3 = event::Force::Calibrated { force: 5.0, max_possible_force: 2.5 }; assert_eq!(force3.normalized(), 2.0); } @@ -1164,7 +1254,6 @@ 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(); @@ -1176,16 +1265,6 @@ mod tests { HashSet::new().insert(event::MouseButton::Left.clone()); HashSet::new().insert(event::Ime::Enabled); - let _ = event::Touch { - device_id: did, - phase: event::TouchPhase::Started, - location: (0.0, 0.0).into(), - finger_id: fid, - force: Some(event::Force::Normalized(0.0)), - } - .clone(); - let _ = - event::Force::Calibrated { force: 0.0, max_possible_force: 0.0, altitude_angle: None } - .clone(); + let _ = event::Force::Calibrated { force: 0.0, max_possible_force: 0.0 }.clone(); } } diff --git a/src/platform/web.rs b/src/platform/web.rs index fc70d8b4aa..d1316730e5 100644 --- a/src/platform/web.rs +++ b/src/platform/web.rs @@ -29,17 +29,16 @@ //! The following APIs can't take them into account and will therefore provide inaccurate results: //! - [`WindowEvent::Resized`] and [`Window::(set_)inner_size()`] //! - [`WindowEvent::Occluded`] -//! - [`WindowEvent::CursorMoved`], [`WindowEvent::CursorEntered`], [`WindowEvent::CursorLeft`], and -//! [`WindowEvent::Touch`]. +//! - [`WindowEvent::PointerMoved`], [`WindowEvent::PointerEntered`] and +//! [`WindowEvent::PointerLeft`]. //! - [`Window::set_outer_position()`] //! //! [`WindowEvent::Resized`]: crate::event::WindowEvent::Resized //! [`Window::(set_)inner_size()`]: crate::window::Window::inner_size //! [`WindowEvent::Occluded`]: crate::event::WindowEvent::Occluded -//! [`WindowEvent::CursorMoved`]: crate::event::WindowEvent::CursorMoved -//! [`WindowEvent::CursorEntered`]: crate::event::WindowEvent::CursorEntered -//! [`WindowEvent::CursorLeft`]: crate::event::WindowEvent::CursorLeft -//! [`WindowEvent::Touch`]: crate::event::WindowEvent::Touch +//! [`WindowEvent::PointerMoved`]: crate::event::WindowEvent::PointerMoved +//! [`WindowEvent::PointerEntered`]: crate::event::WindowEvent::PointerEntered +//! [`WindowEvent::PointerLeft`]: crate::event::WindowEvent::PointerLeft //! [`Window::set_outer_position()`]: crate::window::Window::set_outer_position use std::cell::Ref; diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index b3425ea339..18efb54612 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -344,22 +344,58 @@ impl EventLoop { }; for pointer in pointers { - let location = + let position = PhysicalPosition { x: pointer.x() as _, y: pointer.y() as _ }; trace!( - "Input event {device_id:?}, {phase:?}, loc={location:?}, \ + "Input event {device_id:?}, {phase:?}, loc={position:?}, \ pointer={pointer:?}" ); + let finger_id = event::FingerId(FingerId(pointer.pointer_id())); + let force = Some(Force::Normalized(pointer.pressure() as f64)); - let event = event::WindowEvent::Touch(event::Touch { - device_id, - phase, - location, - finger_id: event::FingerId(FingerId(pointer.pointer_id())), - force: Some(Force::Normalized(pointer.pressure() as f64)), - }); - - app.window_event(&self.window_target, window_id, event); + match phase { + event::TouchPhase::Started => { + let event = event::WindowEvent::PointerEntered { + device_id, + position, + ty: event::PointerType::Touch(finger_id), + }; + app.window_event(&self.window_target, window_id, event); + let event = event::WindowEvent::PointerButton { + device_id, + state: event::ElementState::Pressed, + position, + button: event::ButtonSource::Touch { finger_id, force }, + }; + app.window_event(&self.window_target, window_id, event); + }, + event::TouchPhase::Moved => { + let event = event::WindowEvent::PointerMoved { + device_id, + position, + source: event::PointerSource::Touch { finger_id, force }, + }; + app.window_event(&self.window_target, window_id, event); + }, + event::TouchPhase::Ended | event::TouchPhase::Cancelled => { + if let event::TouchPhase::Ended = phase { + let event = event::WindowEvent::PointerButton { + device_id, + state: event::ElementState::Released, + position, + button: event::ButtonSource::Touch { finger_id, force }, + }; + app.window_event(&self.window_target, window_id, event); + } + + let event = event::WindowEvent::PointerLeft { + device_id, + position: Some(position), + ty: event::PointerType::Touch(finger_id), + }; + app.window_event(&self.window_target, window_id, event); + }, + } } } }, diff --git a/src/platform_impl/apple/appkit/app.rs b/src/platform_impl/apple/appkit/app.rs index 5313640131..bd4f6fa5ce 100644 --- a/src/platform_impl/apple/appkit/app.rs +++ b/src/platform_impl/apple/appkit/app.rs @@ -61,7 +61,7 @@ fn maybe_dispatch_device_event(app_state: &Rc, event: &NSEvent) { if delta_x != 0.0 || delta_y != 0.0 { app_state.maybe_queue_with_handler(move |app, event_loop| { - app.device_event(event_loop, DEVICE_ID, DeviceEvent::MouseMotion { + app.device_event(event_loop, DEVICE_ID, DeviceEvent::PointerMotion { delta: (delta_x, delta_y), }); }); diff --git a/src/platform_impl/apple/appkit/view.rs b/src/platform_impl/apple/appkit/view.rs index 9392a283fc..21bc0b2336 100644 --- a/src/platform_impl/apple/appkit/view.rs +++ b/src/platform_impl/apple/appkit/view.rs @@ -25,10 +25,10 @@ use super::event::{ }; use super::window::WinitWindow; use super::DEVICE_ID; -use crate::dpi::{LogicalPosition, LogicalSize}; +use crate::dpi::{LogicalPosition, LogicalSize, PhysicalPosition}; use crate::event::{ - DeviceEvent, ElementState, Ime, Modifiers, MouseButton, MouseScrollDelta, TouchPhase, - WindowEvent, + DeviceEvent, ElementState, Ime, Modifiers, MouseButton, MouseScrollDelta, PointerSource, + PointerType, TouchPhase, WindowEvent, }; use crate::keyboard::{Key, KeyCode, KeyLocation, ModifiersState, NamedKey}; use crate::platform::macos::OptionAsAlt; @@ -639,19 +639,32 @@ declare_class!( } #[method(mouseEntered:)] - fn mouse_entered(&self, _event: &NSEvent) { + fn mouse_entered(&self, event: &NSEvent) { trace_scope!("mouseEntered:"); - self.queue_event(WindowEvent::CursorEntered { + + let Some(position) = self.mouse_view_point(event) else { + return + }; + + self.queue_event(WindowEvent::PointerEntered { device_id: DEVICE_ID, + position, + ty: PointerType::Mouse, }); } #[method(mouseExited:)] - fn mouse_exited(&self, _event: &NSEvent) { + fn mouse_exited(&self, event: &NSEvent) { trace_scope!("mouseExited:"); - self.queue_event(WindowEvent::CursorLeft { + let Some(position) = self.mouse_view_point(event) else { + return + }; + + self.queue_event(WindowEvent::PointerLeft { device_id: DEVICE_ID, + position: Some(position), + ty: PointerType::Mouse, }); } @@ -1038,14 +1051,29 @@ impl WinitView { self.update_modifiers(event, false); - self.queue_event(WindowEvent::MouseInput { + let Some(position) = self.mouse_view_point(event) else { return }; + + self.queue_event(WindowEvent::PointerButton { device_id: DEVICE_ID, state: button_state, - button, + position, + button: button.into(), }); } fn mouse_motion(&self, event: &NSEvent) { + self.update_modifiers(event, false); + + let Some(position) = self.mouse_view_point(event) else { return }; + + self.queue_event(WindowEvent::PointerMoved { + device_id: DEVICE_ID, + position, + source: PointerSource::Mouse, + }); + } + + fn mouse_view_point(&self, event: &NSEvent) -> Option> { let window_point = unsafe { event.locationInWindow() }; let view_point = self.convertPoint_fromView(window_point, None); let frame = self.frame(); @@ -1058,18 +1086,11 @@ impl WinitView { let mouse_buttons_down = unsafe { NSEvent::pressedMouseButtons() }; if mouse_buttons_down == 0 { // Point is outside of the client area (view) and no buttons are pressed - return; + return None; } } - let view_point = LogicalPosition::new(view_point.x, view_point.y); - - self.update_modifiers(event, false); - - self.queue_event(WindowEvent::CursorMoved { - device_id: DEVICE_ID, - position: view_point.to_physical(self.scale_factor()), - }); + Some(LogicalPosition::new(view_point.x, view_point.y).to_physical(self.scale_factor())) } } diff --git a/src/platform_impl/apple/uikit/view.rs b/src/platform_impl/apple/uikit/view.rs index d946445eda..525a7c45bd 100644 --- a/src/platform_impl/apple/uikit/view.rs +++ b/src/platform_impl/apple/uikit/view.rs @@ -16,7 +16,10 @@ use super::app_state::{self, EventWrapper}; use super::window::WinitUIWindow; use super::{FingerId, DEVICE_ID}; use crate::dpi::PhysicalPosition; -use crate::event::{Event, FingerId as RootFingerId, Force, Touch, TouchPhase, WindowEvent}; +use crate::event::{ + ButtonSource, ElementState, Event, FingerId as RootFingerId, Force, PointerSource, PointerType, + TouchPhase, WindowEvent, +}; use crate::window::{WindowAttributes, WindowId as RootWindowId}; pub struct WinitViewState { @@ -454,25 +457,18 @@ impl WinitView { for touch in touches { let logical_location = touch.locationInView(None); let touch_type = touch.r#type(); - let force = if os_supports_force { + let force = if let UITouchType::Pencil = touch_type { + None + } else if os_supports_force { let trait_collection = self.traitCollection(); let touch_capability = trait_collection.forceTouchCapability(); // Both the OS _and_ the device need to be checked for force touch support. - if touch_capability == UIForceTouchCapability::Available - || touch_type == UITouchType::Pencil - { + if touch_capability == UIForceTouchCapability::Available { let force = touch.force(); let max_possible_force = touch.maximumPossibleForce(); - let altitude_angle: Option = if touch_type == UITouchType::Pencil { - let angle = touch.altitudeAngle(); - Some(angle as _) - } else { - None - }; Some(Force::Calibrated { force: force as _, max_possible_force: max_possible_force as _, - altitude_angle, }) } else { None @@ -482,32 +478,91 @@ impl WinitView { }; let touch_id = touch as *const UITouch as usize; let phase = touch.phase(); - let phase = match phase { - UITouchPhase::Began => TouchPhase::Started, - UITouchPhase::Moved => TouchPhase::Moved, - // 2 is UITouchPhase::Stationary and is not expected here - UITouchPhase::Ended => TouchPhase::Ended, - UITouchPhase::Cancelled => TouchPhase::Cancelled, - _ => panic!("unexpected touch phase: {phase:?}"), - }; - - let physical_location = { + let position = { let scale_factor = self.contentScaleFactor(); PhysicalPosition::from_logical::<(f64, f64), f64>( (logical_location.x as _, logical_location.y as _), scale_factor as f64, ) }; - touch_events.push(EventWrapper::StaticEvent(Event::WindowEvent { - window_id: RootWindowId(window.id()), - event: WindowEvent::Touch(Touch { - device_id: DEVICE_ID, - finger_id: RootFingerId(FingerId(touch_id)), - location: physical_location, - force, - phase, - }), - })); + let window_id = RootWindowId(window.id()); + let finger_id = RootFingerId(FingerId(touch_id)); + + match phase { + UITouchPhase::Began => { + touch_events.push(EventWrapper::StaticEvent(Event::WindowEvent { + window_id, + event: WindowEvent::PointerEntered { + device_id: DEVICE_ID, + position, + ty: if let UITouchType::Pencil = touch_type { + PointerType::Unknown + } else { + PointerType::Touch(finger_id) + }, + }, + })); + touch_events.push(EventWrapper::StaticEvent(Event::WindowEvent { + window_id, + event: WindowEvent::PointerButton { + device_id: DEVICE_ID, + state: ElementState::Pressed, + position, + button: if let UITouchType::Pencil = touch_type { + ButtonSource::Unknown(0) + } else { + ButtonSource::Touch { finger_id, force } + }, + }, + })); + }, + UITouchPhase::Moved => { + touch_events.push(EventWrapper::StaticEvent(Event::WindowEvent { + window_id, + event: WindowEvent::PointerMoved { + device_id: DEVICE_ID, + position, + source: if let UITouchType::Pencil = touch_type { + PointerSource::Unknown + } else { + PointerSource::Touch { finger_id, force } + }, + }, + })); + }, + // 2 is UITouchPhase::Stationary and is not expected here + UITouchPhase::Ended | UITouchPhase::Cancelled => { + if let UITouchPhase::Ended = phase { + touch_events.push(EventWrapper::StaticEvent(Event::WindowEvent { + window_id, + event: WindowEvent::PointerButton { + device_id: DEVICE_ID, + state: ElementState::Released, + position, + button: if let UITouchType::Pencil = touch_type { + ButtonSource::Unknown(0) + } else { + ButtonSource::Touch { finger_id, force } + }, + }, + })); + } + + touch_events.push(EventWrapper::StaticEvent(Event::WindowEvent { + window_id, + event: WindowEvent::PointerLeft { + device_id: DEVICE_ID, + position: Some(position), + ty: if let UITouchType::Pencil = touch_type { + PointerType::Unknown + } else { + PointerType::Touch(finger_id) + }, + }, + })); + }, + _ => panic!("unexpected touch phase: {phase:?}"), + } } let mtm = MainThreadMarker::new().unwrap(); app_state::handle_nonuser_events(mtm, touch_events); diff --git a/src/platform_impl/linux/common/xkb/keymap.rs b/src/platform_impl/linux/common/xkb/keymap.rs index 32a942820e..168b8b25e7 100644 --- a/src/platform_impl/linux/common/xkb/keymap.rs +++ b/src/platform_impl/linux/common/xkb/keymap.rs @@ -638,7 +638,7 @@ pub fn keysym_to_key(keysym: u32) -> Key { // keysyms::ISO_Release_Margin_Left => NamedKey::IsoReleaseMarginLeft, // keysyms::ISO_Release_Margin_Right => NamedKey::IsoReleaseMarginRight, // keysyms::ISO_Release_Both_Margins => NamedKey::IsoReleaseBothMargins, - // keysyms::ISO_Fast_Cursor_Left => NamedKey::IsoFastCursorLeft, + // keysyms::ISO_Fast_Cursor_Left => NamedKey::IsoFastPointerLeft, // keysyms::ISO_Fast_Cursor_Right => NamedKey::IsoFastCursorRight, // keysyms::ISO_Fast_Cursor_Up => NamedKey::IsoFastCursorUp, // keysyms::ISO_Fast_Cursor_Down => NamedKey::IsoFastCursorDown, diff --git a/src/platform_impl/linux/wayland/seat/pointer/mod.rs b/src/platform_impl/linux/wayland/seat/pointer/mod.rs index fcca59343b..2ed2f8e8ed 100644 --- a/src/platform_impl/linux/wayland/seat/pointer/mod.rs +++ b/src/platform_impl/linux/wayland/seat/pointer/mod.rs @@ -27,7 +27,7 @@ use sctk::seat::pointer::{ use sctk::seat::SeatState; use crate::dpi::{LogicalPosition, PhysicalPosition}; -use crate::event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase, WindowEvent}; +use crate::event::{ElementState, MouseButton, MouseScrollDelta, PointerSource, PointerType, TouchPhase, WindowEvent}; use crate::platform_impl::wayland::state::WinitState; use crate::platform_impl::wayland::{self, DeviceId, WindowId}; @@ -124,18 +124,15 @@ impl PointerHandler for WinitState { }, // Regular events on the main surface. PointerEventKind::Enter { .. } => { - self.events_sink - .push_window_event(WindowEvent::CursorEntered { device_id }, window_id); + self.events_sink.push_window_event( + WindowEvent::PointerEntered { device_id, position, ty: PointerType::Mouse }, + window_id, + ); window.pointer_entered(Arc::downgrade(themed_pointer)); // Set the currently focused surface. pointer.winit_data().inner.lock().unwrap().surface = Some(window_id); - - self.events_sink.push_window_event( - WindowEvent::CursorMoved { device_id, position }, - window_id, - ); }, PointerEventKind::Leave { .. } => { window.pointer_left(Arc::downgrade(themed_pointer)); @@ -143,12 +140,22 @@ impl PointerHandler for WinitState { // Remove the active surface. pointer.winit_data().inner.lock().unwrap().surface = None; - self.events_sink - .push_window_event(WindowEvent::CursorLeft { device_id }, window_id); + self.events_sink.push_window_event( + WindowEvent::PointerLeft { + device_id, + position: Some(position), + ty: PointerType::Mouse, + }, + window_id, + ); }, PointerEventKind::Motion { .. } => { self.events_sink.push_window_event( - WindowEvent::CursorMoved { device_id, position }, + WindowEvent::PointerMoved { + device_id, + position, + source: PointerSource::Mouse, + }, window_id, ); }, @@ -164,7 +171,12 @@ impl PointerHandler for WinitState { ElementState::Released }; self.events_sink.push_window_event( - WindowEvent::MouseInput { device_id, state, button }, + WindowEvent::PointerButton { + device_id, + state, + position, + button: button.into(), + }, window_id, ); }, diff --git a/src/platform_impl/linux/wayland/seat/pointer/relative_pointer.rs b/src/platform_impl/linux/wayland/seat/pointer/relative_pointer.rs index 33fc9e91e3..e92b41750d 100644 --- a/src/platform_impl/linux/wayland/seat/pointer/relative_pointer.rs +++ b/src/platform_impl/linux/wayland/seat/pointer/relative_pointer.rs @@ -67,7 +67,7 @@ impl Dispatch for RelativePointerS _ => return, }; state.events_sink.push_device_event( - DeviceEvent::MouseMotion { delta: (dx_unaccel, dy_unaccel) }, + DeviceEvent::PointerMotion { delta: (dx_unaccel, dy_unaccel) }, super::DeviceId, ); } diff --git a/src/platform_impl/linux/wayland/seat/touch/mod.rs b/src/platform_impl/linux/wayland/seat/touch/mod.rs index 665279f019..eff671ab8e 100644 --- a/src/platform_impl/linux/wayland/seat/touch/mod.rs +++ b/src/platform_impl/linux/wayland/seat/touch/mod.rs @@ -8,7 +8,7 @@ use sctk::seat::touch::{TouchData, TouchHandler}; use tracing::warn; use crate::dpi::LogicalPosition; -use crate::event::{Touch, TouchPhase, WindowEvent}; +use crate::event::{ButtonSource, ElementState, PointerSource, PointerType, WindowEvent}; use crate::platform_impl::wayland::state::WinitState; use crate::platform_impl::wayland::{self, DeviceId, FingerId}; @@ -42,18 +42,22 @@ impl TouchHandler for WinitState { let location = LogicalPosition::::from(position); seat_state.touch_map.insert(id, TouchPoint { surface, location }); + let device_id = crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId)); + let position = location.to_physical(scale_factor); + let finger_id = + crate::event::FingerId(crate::platform_impl::FingerId::Wayland(FingerId(id))); + self.events_sink.push_window_event( - WindowEvent::Touch(Touch { - device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland( - DeviceId, - )), - phase: TouchPhase::Started, - location: location.to_physical(scale_factor), - force: None, - finger_id: crate::event::FingerId(crate::platform_impl::FingerId::Wayland( - FingerId(id), - )), - }), + WindowEvent::PointerEntered { device_id, position, ty: PointerType::Touch(finger_id) }, + window_id, + ); + self.events_sink.push_window_event( + WindowEvent::PointerButton { + device_id, + state: ElementState::Pressed, + position, + button: ButtonSource::Touch { finger_id, force: None }, + }, window_id, ); } @@ -87,18 +91,26 @@ impl TouchHandler for WinitState { None => return, }; + let position = touch_point.location.to_physical(scale_factor); + let device_id = crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId)); + let finger_id = + crate::event::FingerId(crate::platform_impl::FingerId::Wayland(FingerId(id))); + self.events_sink.push_window_event( - WindowEvent::Touch(Touch { - device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland( - DeviceId, - )), - phase: TouchPhase::Ended, - location: touch_point.location.to_physical(scale_factor), - force: None, - finger_id: crate::event::FingerId(crate::platform_impl::FingerId::Wayland( - FingerId(id), - )), - }), + WindowEvent::PointerButton { + device_id, + state: ElementState::Released, + position, + button: ButtonSource::Touch { finger_id, force: None }, + }, + window_id, + ); + self.events_sink.push_window_event( + WindowEvent::PointerLeft { + device_id, + position: Some(position), + ty: PointerType::Touch(finger_id), + }, window_id, ); } @@ -135,17 +147,18 @@ impl TouchHandler for WinitState { touch_point.location = LogicalPosition::::from(position); self.events_sink.push_window_event( - WindowEvent::Touch(Touch { + WindowEvent::PointerMoved { device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland( DeviceId, )), - phase: TouchPhase::Moved, - location: touch_point.location.to_physical(scale_factor), - force: None, - finger_id: crate::event::FingerId(crate::platform_impl::FingerId::Wayland( - FingerId(id), - )), - }), + position: touch_point.location.to_physical(scale_factor), + source: PointerSource::Touch { + finger_id: crate::event::FingerId(crate::platform_impl::FingerId::Wayland( + FingerId(id), + )), + force: None, + }, + }, window_id, ); } @@ -166,20 +179,18 @@ impl TouchHandler for WinitState { None => return, }; - let location = touch_point.location.to_physical(scale_factor); + let position = touch_point.location.to_physical(scale_factor); self.events_sink.push_window_event( - WindowEvent::Touch(Touch { + WindowEvent::PointerLeft { device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland( DeviceId, )), - phase: TouchPhase::Cancelled, - location, - force: None, - finger_id: crate::event::FingerId(crate::platform_impl::FingerId::Wayland( - FingerId(id), + position: Some(position), + ty: PointerType::Touch(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 09bb02912c..80e552cc05 100644 --- a/src/platform_impl/linux/x11/event_processor.rs +++ b/src/platform_impl/linux/x11/event_processor.rs @@ -22,8 +22,8 @@ use xkbcommon_dl::xkb_mod_mask_t; use crate::dpi::{PhysicalPosition, PhysicalSize}; use crate::event::{ - DeviceEvent, ElementState, Event, Ime, InnerSizeWriter, MouseButton, MouseScrollDelta, - RawKeyEvent, Touch, TouchPhase, WindowEvent, + ButtonSource, DeviceEvent, ElementState, Event, Ime, InnerSizeWriter, MouseButton, + MouseScrollDelta, PointerSource, PointerType, RawKeyEvent, TouchPhase, WindowEvent, }; use crate::keyboard::ModifiersState; use crate::platform_impl::common::xkb::{self, XkbState}; @@ -238,15 +238,8 @@ impl EventProcessor { self.xinput2_unfocused(xev, &mut callback); }, xinput2::XI_TouchBegin | xinput2::XI_TouchUpdate | xinput2::XI_TouchEnd => { - let phase = match evtype { - xinput2::XI_TouchBegin => TouchPhase::Started, - xinput2::XI_TouchUpdate => TouchPhase::Moved, - xinput2::XI_TouchEnd => TouchPhase::Ended, - _ => unreachable!(), - }; - let xev: &XIDeviceEvent = unsafe { xev.as_event() }; - self.xinput2_touch(xev, phase, &mut callback); + self.xinput2_touch(xev, evtype, &mut callback); }, xinput2::XI_RawButtonPress | xinput2::XI_RawButtonRelease => { let state = match evtype { @@ -1019,16 +1012,27 @@ impl EventProcessor { return; } + let position = PhysicalPosition::new(event.event_x, event.event_y); + let event = match event.detail as u32 { - xlib::Button1 => { - WindowEvent::MouseInput { device_id, state, button: MouseButton::Left } + xlib::Button1 => WindowEvent::PointerButton { + device_id, + state, + position, + button: MouseButton::Left.into(), }, - xlib::Button2 => { - WindowEvent::MouseInput { device_id, state, button: MouseButton::Middle } + xlib::Button2 => WindowEvent::PointerButton { + device_id, + state, + position, + button: MouseButton::Middle.into(), }, - xlib::Button3 => { - WindowEvent::MouseInput { device_id, state, button: MouseButton::Right } + xlib::Button3 => WindowEvent::PointerButton { + device_id, + state, + position, + button: MouseButton::Right.into(), }, // Suppress emulated scroll wheel clicks, since we handle the real motion events for @@ -1046,10 +1050,25 @@ impl EventProcessor { }, phase: TouchPhase::Moved, }, - 8 => WindowEvent::MouseInput { device_id, state, button: MouseButton::Back }, + 8 => WindowEvent::PointerButton { + device_id, + state, + position, + button: MouseButton::Back.into(), + }, - 9 => WindowEvent::MouseInput { device_id, state, button: MouseButton::Forward }, - x => WindowEvent::MouseInput { device_id, state, button: MouseButton::Other(x as u16) }, + 9 => WindowEvent::PointerButton { + device_id, + state, + position, + button: MouseButton::Forward.into(), + }, + x => WindowEvent::PointerButton { + device_id, + state, + position, + button: MouseButton::Other(x as u16).into(), + }, }; let event = Event::WindowEvent { window_id, event }; @@ -1078,7 +1097,11 @@ impl EventProcessor { let event = Event::WindowEvent { window_id, - event: WindowEvent::CursorMoved { device_id, position }, + event: WindowEvent::PointerMoved { + device_id, + position, + source: PointerSource::Mouse, + }, }; callback(&self.target, event); } else if cursor_moved.is_none() { @@ -1160,13 +1183,9 @@ impl EventProcessor { if self.window_exists(window) { let position = PhysicalPosition::new(event.event_x, event.event_y); - let event = - Event::WindowEvent { window_id, event: WindowEvent::CursorEntered { device_id } }; - callback(&self.target, event); - let event = Event::WindowEvent { window_id, - event: WindowEvent::CursorMoved { device_id, position }, + event: WindowEvent::PointerEntered { device_id, position, ty: PointerType::Mouse }, }; callback(&self.target, event); } @@ -1186,8 +1205,10 @@ impl EventProcessor { if self.window_exists(window) { let event = Event::WindowEvent { window_id: mkwid(window), - event: WindowEvent::CursorLeft { + event: WindowEvent::PointerLeft { device_id: mkdid(event.deviceid as xinput::DeviceId), + position: Some(PhysicalPosition::new(event.event_x, event.event_y)), + ty: PointerType::Mouse, }, }; callback(&self.target, event); @@ -1247,7 +1268,11 @@ impl EventProcessor { let event = Event::WindowEvent { window_id, - event: WindowEvent::CursorMoved { device_id: mkdid(pointer_id as _), position }, + event: WindowEvent::PointerMoved { + device_id: mkdid(pointer_id as _), + position, + source: PointerSource::Mouse, + }, }; callback(&self.target, event); } @@ -1303,7 +1328,7 @@ impl EventProcessor { } } - fn xinput2_touch(&mut self, xev: &XIDeviceEvent, phase: TouchPhase, mut callback: F) + fn xinput2_touch(&mut self, xev: &XIDeviceEvent, phase: i32, mut callback: F) where F: FnMut(&ActiveEventLoop, Event), { @@ -1314,32 +1339,81 @@ impl EventProcessor { if self.window_exists(window) { let window_id = mkwid(window); let id = xev.detail as u32; - let location = PhysicalPosition::new(xev.event_x, xev.event_y); + let position = PhysicalPosition::new(xev.event_x, xev.event_y); // Mouse cursor position changes when touch events are received. // Only the first concurrently active touch ID moves the mouse cursor. if is_first_touch(&mut self.first_touch, &mut self.num_touch, id, phase) { let event = Event::WindowEvent { window_id, - event: WindowEvent::CursorMoved { + event: WindowEvent::PointerMoved { device_id: mkdid(util::VIRTUAL_CORE_POINTER), - position: location.cast(), + position: position.cast(), + source: PointerSource::Mouse, }, }; callback(&self.target, event); } - let event = Event::WindowEvent { - window_id, - event: WindowEvent::Touch(Touch { - device_id: mkdid(xev.deviceid as xinput::DeviceId), - phase, - location, - force: None, // TODO - finger_id: mkfid(id), - }), - }; - callback(&self.target, event) + let device_id = mkdid(xev.deviceid as xinput::DeviceId); + let finger_id = mkfid(id); + + match phase { + xinput2::XI_TouchBegin => { + let event = Event::WindowEvent { + window_id, + event: WindowEvent::PointerEntered { + device_id, + position, + ty: PointerType::Touch(finger_id), + }, + }; + callback(&self.target, event); + let event = Event::WindowEvent { + window_id, + event: WindowEvent::PointerButton { + device_id, + state: ElementState::Pressed, + position, + button: ButtonSource::Touch { finger_id, force: None }, + }, + }; + callback(&self.target, event); + }, + xinput2::XI_TouchUpdate => { + let event = Event::WindowEvent { + window_id, + event: WindowEvent::PointerMoved { + device_id, + position, + source: PointerSource::Touch { finger_id, force: None }, + }, + }; + callback(&self.target, event); + }, + xinput2::XI_TouchEnd => { + let event = Event::WindowEvent { + window_id, + event: WindowEvent::PointerButton { + device_id, + state: ElementState::Released, + position, + button: ButtonSource::Touch { finger_id, force: None }, + }, + }; + callback(&self.target, event); + let event = Event::WindowEvent { + window_id, + event: WindowEvent::PointerLeft { + device_id: mkdid(xev.deviceid as xinput::DeviceId), + position: Some(position), + ty: PointerType::Touch(finger_id), + }, + }; + callback(&self.target, event); + }, + _ => unreachable!(), + } } } @@ -1395,7 +1469,7 @@ impl EventProcessor { if let Some(mouse_delta) = mouse_delta.consume() { let event = Event::DeviceEvent { device_id: did, - event: DeviceEvent::MouseMotion { delta: mouse_delta }, + event: DeviceEvent::PointerMotion { delta: mouse_delta }, }; callback(&self.target, event); } @@ -1761,15 +1835,15 @@ impl EventProcessor { } } -fn is_first_touch(first: &mut Option, num: &mut u32, id: u32, phase: TouchPhase) -> bool { +fn is_first_touch(first: &mut Option, num: &mut u32, id: u32, phase: i32) -> bool { match phase { - TouchPhase::Started => { + xinput2::XI_TouchBegin => { if *num == 0 { *first = Some(id); } *num += 1; }, - TouchPhase::Cancelled | TouchPhase::Ended => { + xinput2::XI_TouchEnd => { if *first == Some(id) { *first = None; } diff --git a/src/platform_impl/orbital/event_loop.rs b/src/platform_impl/orbital/event_loop.rs index d0c77fcccc..6b7ffef7a8 100644 --- a/src/platform_impl/orbital/event_loop.rs +++ b/src/platform_impl/orbital/event_loop.rs @@ -412,9 +412,10 @@ impl EventLoop { app.window_event( window_target, RootWindowId(window_id), - event::WindowEvent::CursorMoved { + event::WindowEvent::PointerMoved { device_id: event::DeviceId(DeviceId), position: (x, y).into(), + source: event::PointerSource::Mouse, }, ); }, @@ -422,7 +423,7 @@ impl EventLoop { app.device_event( window_target, event::DeviceId(DeviceId), - event::DeviceEvent::MouseMotion { delta: (dx as f64, dy as f64) }, + event::DeviceEvent::PointerMotion { delta: (dx as f64, dy as f64) }, ); }, EventOption::Button(ButtonEvent { left, middle, right }) => { @@ -430,10 +431,11 @@ impl EventLoop { app.window_event( window_target, RootWindowId(window_id), - event::WindowEvent::MouseInput { + event::WindowEvent::PointerButton { device_id: event::DeviceId(DeviceId), state, - button, + position: dpi::PhysicalPosition::default(), + button: button.into(), }, ); } @@ -483,9 +485,17 @@ impl EventLoop { // TODO: Screen, Clipboard, Drop EventOption::Hover(HoverEvent { entered }) => { let event = if entered { - event::WindowEvent::CursorEntered { device_id: event::DeviceId(DeviceId) } + event::WindowEvent::PointerEntered { + device_id: event::DeviceId(DeviceId), + position: dpi::PhysicalPosition::default(), + ty: event::PointerType::Mouse, + } } else { - event::WindowEvent::CursorLeft { device_id: event::DeviceId(DeviceId) } + event::WindowEvent::PointerLeft { + device_id: event::DeviceId(DeviceId), + position: None, + ty: event::PointerType::Mouse, + } }; app.window_event(window_target, RootWindowId(window_id), event); diff --git a/src/platform_impl/web/event.rs b/src/platform_impl/web/event.rs index 937702b118..6774234ee9 100644 --- a/src/platform_impl/web/event.rs +++ b/src/platform_impl/web/event.rs @@ -1,3 +1,5 @@ +use crate::event::FingerId as RootFingerId; + #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct DeviceId(i32); @@ -30,3 +32,9 @@ impl FingerId { self.primary } } + +impl From for RootFingerId { + fn from(id: FingerId) -> Self { + Self(id) + } +} diff --git a/src/platform_impl/web/event_loop/runner.rs b/src/platform_impl/web/event_loop/runner.rs index 64c65a34eb..90a5d7ece6 100644 --- a/src/platform_impl/web/event_loop/runner.rs +++ b/src/platform_impl/web/event_loop/runner.rs @@ -297,7 +297,7 @@ impl Shared { runner.send_event(Event::DeviceEvent { device_id, - event: DeviceEvent::Button { button: button.to_id(), state }, + event: DeviceEvent::Button { button: button.to_id().into(), state }, }); return; @@ -310,7 +310,7 @@ impl Shared { Event::DeviceEvent { device_id, - event: DeviceEvent::MouseMotion { delta: (delta.x, delta.y) }, + event: DeviceEvent::PointerMotion { delta: (delta.x, delta.y) }, } })); }), @@ -346,7 +346,7 @@ impl Shared { runner.send_event(Event::DeviceEvent { device_id: RootDeviceId(DeviceId::new(event.pointer_id())), event: DeviceEvent::Button { - button: button.to_id(), + button: button.to_id().into(), state: ElementState::Pressed, }, }); @@ -365,7 +365,7 @@ impl Shared { runner.send_event(Event::DeviceEvent { device_id: RootDeviceId(DeviceId::new(event.pointer_id())), event: DeviceEvent::Button { - button: button.to_id(), + button: button.to_id().into(), 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 878ab03e31..bc175c1b7b 100644 --- a/src/platform_impl/web/event_loop/window_target.rs +++ b/src/platform_impl/web/event_loop/window_target.rs @@ -13,8 +13,7 @@ use super::window::WindowId; use super::{backend, runner, EventLoopProxy}; use crate::error::{ExternalError, NotSupportedError}; use crate::event::{ - DeviceId as RootDeviceId, ElementState, Event, FingerId as RootFingerId, KeyEvent, Touch, - TouchPhase, WindowEvent, + DeviceId as RootDeviceId, ElementState, Event, KeyEvent, TouchPhase, WindowEvent, }; use crate::event_loop::{ ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents, @@ -206,12 +205,12 @@ impl ActiveEventLoop { ); let has_focus = canvas.has_focus.clone(); - canvas.on_cursor_leave({ + canvas.on_pointer_leave({ let runner = self.runner.clone(); let has_focus = has_focus.clone(); let modifiers = self.modifiers.clone(); - move |active_modifiers, pointer_id| { + move |active_modifiers, device_id, position, ty| { let focus = (has_focus.get() && modifiers.get() != active_modifiers).then(|| { modifiers.set(active_modifiers); Event::WindowEvent { @@ -220,23 +219,23 @@ impl ActiveEventLoop { } }); - let pointer = pointer_id.map(|device_id| Event::WindowEvent { + runner.send_events(focus.into_iter().chain(iter::once(Event::WindowEvent { window_id: RootWindowId(id), - event: WindowEvent::CursorLeft { device_id: RootDeviceId(device_id) }, - }); - - if focus.is_some() || pointer.is_some() { - runner.send_events(focus.into_iter().chain(pointer)) - } + event: WindowEvent::PointerLeft { + device_id: RootDeviceId(device_id), + position: Some(position), + ty, + }, + }))) } }); - canvas.on_cursor_enter({ + canvas.on_pointer_enter({ let runner = self.runner.clone(); let has_focus = has_focus.clone(); let modifiers = self.modifiers.clone(); - move |active_modifiers, pointer_id| { + move |active_modifiers, device_id, position, ty| { let focus = (has_focus.get() && modifiers.get() != active_modifiers).then(|| { modifiers.set(active_modifiers); Event::WindowEvent { @@ -245,70 +244,41 @@ impl ActiveEventLoop { } }); - let pointer = pointer_id.map(|device_id| Event::WindowEvent { + runner.send_events(focus.into_iter().chain(iter::once(Event::WindowEvent { window_id: RootWindowId(id), - event: WindowEvent::CursorEntered { device_id: RootDeviceId(device_id) }, - }); - - if focus.is_some() || pointer.is_some() { - runner.send_events(focus.into_iter().chain(pointer)) - } + event: WindowEvent::PointerEntered { + device_id: RootDeviceId(device_id), + position, + ty, + }, + }))) } }); - canvas.on_cursor_move( + canvas.on_pointer_move( { let runner = self.runner.clone(); let has_focus = has_focus.clone(); let modifiers = self.modifiers.clone(); - move |active_modifiers, pointer_id, events| { - let modifiers = - (has_focus.get() && modifiers.get() != active_modifiers).then(|| { - modifiers.set(active_modifiers); - Event::WindowEvent { - window_id: RootWindowId(id), - event: WindowEvent::ModifiersChanged(active_modifiers.into()), - } - }); - - runner.send_events(modifiers.into_iter().chain(events.flat_map(|position| { + move |pointer_id, events| { + runner.send_events(events.flat_map(|(active_modifiers, position, source)| { let device_id = RootDeviceId(pointer_id); - iter::once(Event::WindowEvent { - window_id: RootWindowId(id), - event: WindowEvent::CursorMoved { device_id, position }, - }) - }))); - } - }, - { - let runner = self.runner.clone(); - let has_focus = has_focus.clone(); - let modifiers = self.modifiers.clone(); - - move |active_modifiers, device_id, finger_id, events| { - let modifiers = - (has_focus.get() && modifiers.get() != active_modifiers).then(|| { - modifiers.set(active_modifiers); - Event::WindowEvent { - window_id: RootWindowId(id), - event: WindowEvent::ModifiersChanged(active_modifiers.into()), - } - }); + let modifiers = (has_focus.get() && modifiers.get() != active_modifiers) + .then(|| { + modifiers.set(active_modifiers); + Event::WindowEvent { + window_id: RootWindowId(id), + event: WindowEvent::ModifiersChanged(active_modifiers.into()), + } + }); - runner.send_events(modifiers.into_iter().chain(events.map( - |(location, force)| Event::WindowEvent { + modifiers.into_iter().chain(iter::once(Event::WindowEvent { window_id: RootWindowId(id), - event: WindowEvent::Touch(Touch { - finger_id: RootFingerId(finger_id), - device_id: RootDeviceId(device_id), - phase: TouchPhase::Moved, - force: Some(force), - location, - }), - }, - ))); + event: WindowEvent::PointerMoved { device_id, position, source }, + })) + })); } }, { @@ -316,11 +286,7 @@ impl ActiveEventLoop { let has_focus = has_focus.clone(); let modifiers = self.modifiers.clone(); - move |active_modifiers, - device_id, - position: crate::dpi::PhysicalPosition, - buttons, - button| { + move |active_modifiers, device_id, position, state, button| { let modifiers = (has_focus.get() && modifiers.get() != active_modifiers).then(|| { modifiers.set(active_modifiers); @@ -332,70 +298,49 @@ impl ActiveEventLoop { let device_id = RootDeviceId(device_id); - let state = if buttons.contains(button.into()) { - ElementState::Pressed - } else { - ElementState::Released - }; - - // A chorded button event may come in without any prior CursorMoved events, - // therefore we should send a CursorMoved event to make sure that the - // user code has the correct cursor position. - runner.send_events(modifiers.into_iter().chain([ - Event::WindowEvent { - window_id: RootWindowId(id), - event: WindowEvent::CursorMoved { device_id, position }, - }, - Event::WindowEvent { - window_id: RootWindowId(id), - event: WindowEvent::MouseInput { device_id, state, button }, - }, - ])); + runner.send_events(modifiers.into_iter().chain([Event::WindowEvent { + window_id: RootWindowId(id), + event: WindowEvent::PointerButton { device_id, state, position, button }, + }])); } }, ); - canvas.on_mouse_press( - { - let runner = self.runner.clone(); - let modifiers = self.modifiers.clone(); + canvas.on_pointer_press({ + let runner = self.runner.clone(); + let modifiers = self.modifiers.clone(); - move |active_modifiers, pointer_id, position, button| { - let modifiers = (modifiers.get() != active_modifiers).then(|| { - modifiers.set(active_modifiers); - Event::WindowEvent { - window_id: RootWindowId(id), - event: WindowEvent::ModifiersChanged(active_modifiers.into()), - } - }); + move |active_modifiers, pointer_id, position, button| { + let modifiers = (modifiers.get() != active_modifiers).then(|| { + modifiers.set(active_modifiers); + Event::WindowEvent { + window_id: RootWindowId(id), + event: WindowEvent::ModifiersChanged(active_modifiers.into()), + } + }); - let device_id: RootDeviceId = RootDeviceId(pointer_id); + let device_id: RootDeviceId = RootDeviceId(pointer_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 - // user code has the correct cursor position. - runner.send_events(modifiers.into_iter().chain([ - Event::WindowEvent { - window_id: RootWindowId(id), - event: WindowEvent::CursorMoved { device_id, position }, - }, - Event::WindowEvent { - window_id: RootWindowId(id), - event: WindowEvent::MouseInput { - device_id, - state: ElementState::Pressed, - button, - }, - }, - ])); - } - }, - { - let runner = self.runner.clone(); - let modifiers = self.modifiers.clone(); + runner.send_events(modifiers.into_iter().chain(iter::once(Event::WindowEvent { + window_id: RootWindowId(id), + event: WindowEvent::PointerButton { + device_id, + state: ElementState::Pressed, + position, + button, + }, + }))); + } + }); + + canvas.on_pointer_release({ + let runner = self.runner.clone(); + let has_focus = has_focus.clone(); + let modifiers = self.modifiers.clone(); - move |active_modifiers, device_id, finger_id, location, force| { - let modifiers = (modifiers.get() != active_modifiers).then(|| { + move |active_modifiers, pointer_id, position, button| { + let modifiers = + (has_focus.get() && modifiers.get() != active_modifiers).then(|| { modifiers.set(active_modifiers); Event::WindowEvent { window_id: RootWindowId(id), @@ -403,89 +348,19 @@ impl ActiveEventLoop { } }); - runner.send_events(modifiers.into_iter().chain(iter::once( - Event::WindowEvent { - window_id: RootWindowId(id), - event: WindowEvent::Touch(Touch { - finger_id: RootFingerId(finger_id), - device_id: RootDeviceId(device_id), - phase: TouchPhase::Started, - force: Some(force), - location, - }), - }, - ))) - } - }, - ); - - canvas.on_mouse_release( - { - let runner = self.runner.clone(); - let has_focus = has_focus.clone(); - let modifiers = self.modifiers.clone(); - - move |active_modifiers, pointer_id, position, button| { - let modifiers = - (has_focus.get() && modifiers.get() != active_modifiers).then(|| { - modifiers.set(active_modifiers); - Event::WindowEvent { - window_id: RootWindowId(id), - event: WindowEvent::ModifiersChanged(active_modifiers.into()), - } - }); - - let device_id: RootDeviceId = RootDeviceId(pointer_id); + let device_id: RootDeviceId = RootDeviceId(pointer_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 - // user code has the correct cursor position. - runner.send_events(modifiers.into_iter().chain([ - Event::WindowEvent { - window_id: RootWindowId(id), - event: WindowEvent::CursorMoved { device_id, position }, - }, - Event::WindowEvent { - window_id: RootWindowId(id), - event: WindowEvent::MouseInput { - device_id, - state: ElementState::Released, - button, - }, - }, - ])); - } - }, - { - let runner_touch = self.runner.clone(); - let has_focus = has_focus.clone(); - let modifiers = self.modifiers.clone(); - - move |active_modifiers, device_id, finger_id, location, force| { - let modifiers = - (has_focus.get() && modifiers.get() != active_modifiers).then(|| { - modifiers.set(active_modifiers); - Event::WindowEvent { - window_id: RootWindowId(id), - event: WindowEvent::ModifiersChanged(active_modifiers.into()), - } - }); - - runner_touch.send_events(modifiers.into_iter().chain(iter::once( - Event::WindowEvent { - window_id: RootWindowId(id), - event: WindowEvent::Touch(Touch { - finger_id: RootFingerId(finger_id), - device_id: RootDeviceId(device_id), - phase: TouchPhase::Ended, - force: Some(force), - location, - }), - }, - ))); - } - }, - ); + runner.send_events(modifiers.into_iter().chain(iter::once(Event::WindowEvent { + window_id: RootWindowId(id), + event: WindowEvent::PointerButton { + device_id, + state: ElementState::Released, + position, + button, + }, + }))); + } + }); let runner = self.runner.clone(); let modifiers = self.modifiers.clone(); @@ -511,20 +386,6 @@ impl ActiveEventLoop { ))); }); - let runner = self.runner.clone(); - canvas.on_touch_cancel(move |device_id, finger_id, location, force| { - runner.send_event(Event::WindowEvent { - window_id: RootWindowId(id), - event: WindowEvent::Touch(Touch { - finger_id: RootFingerId(finger_id), - device_id: RootDeviceId(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 { Theme::Dark } else { Theme::Light }; diff --git a/src/platform_impl/web/web_sys/canvas.rs b/src/platform_impl/web/web_sys/canvas.rs index e7d95d84dc..e31a22753f 100644 --- a/src/platform_impl/web/web_sys/canvas.rs +++ b/src/platform_impl/web/web_sys/canvas.rs @@ -12,7 +12,7 @@ use web_sys::{ }; use super::super::cursor::CursorHandler; -use super::super::event::{DeviceId, FingerId}; +use super::super::event::DeviceId; use super::super::main_thread::MainThreadMarker; use super::super::WindowId; use super::animation_frame::AnimationFrameHandler; @@ -20,10 +20,12 @@ use super::event_handle::EventListenerHandle; use super::intersection_handle::IntersectionObserverHandle; use super::media_query_handle::MediaQueryListHandle; use super::pointer::PointerHandler; -use super::{event, fullscreen, ButtonsState, ResizeScaleHandle}; +use super::{event, fullscreen, ResizeScaleHandle}; use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize}; use crate::error::OsError as RootOE; -use crate::event::{Force, InnerSizeWriter, MouseButton, MouseScrollDelta}; +use crate::event::{ + ButtonSource, ElementState, InnerSizeWriter, MouseScrollDelta, PointerSource, PointerType, +}; use crate::keyboard::{Key, KeyLocation, ModifiersState, PhysicalKey}; use crate::platform_impl::{Fullscreen, OsError}; use crate::window::{WindowAttributes, WindowId as RootWindowId}; @@ -328,75 +330,56 @@ impl Canvas { })); } - pub fn on_cursor_leave(&self, handler: F) + pub fn on_pointer_leave(&self, handler: F) where - F: 'static + FnMut(ModifiersState, Option), + F: 'static + FnMut(ModifiersState, DeviceId, PhysicalPosition, PointerType), { - self.handlers.borrow_mut().pointer_handler.on_cursor_leave(&self.common, handler) + self.handlers.borrow_mut().pointer_handler.on_pointer_leave(&self.common, handler) } - pub fn on_cursor_enter(&self, handler: F) + pub fn on_pointer_enter(&self, handler: F) where - F: 'static + FnMut(ModifiersState, Option), + F: 'static + FnMut(ModifiersState, DeviceId, PhysicalPosition, PointerType), { - self.handlers.borrow_mut().pointer_handler.on_cursor_enter(&self.common, handler) + self.handlers.borrow_mut().pointer_handler.on_pointer_enter(&self.common, handler) } - pub fn on_mouse_release(&self, mouse_handler: M, touch_handler: T) + pub fn on_pointer_release(&self, handler: C) where - M: 'static + FnMut(ModifiersState, DeviceId, PhysicalPosition, MouseButton), - T: 'static + FnMut(ModifiersState, DeviceId, FingerId, PhysicalPosition, Force), + C: 'static + FnMut(ModifiersState, DeviceId, PhysicalPosition, ButtonSource), { - self.handlers.borrow_mut().pointer_handler.on_mouse_release( - &self.common, - mouse_handler, - touch_handler, - ) + self.handlers.borrow_mut().pointer_handler.on_pointer_release(&self.common, handler) } - pub fn on_mouse_press(&self, mouse_handler: M, touch_handler: T) + pub fn on_pointer_press(&self, handler: C) where - M: 'static + FnMut(ModifiersState, DeviceId, PhysicalPosition, MouseButton), - T: 'static + FnMut(ModifiersState, DeviceId, FingerId, PhysicalPosition, Force), + C: 'static + FnMut(ModifiersState, DeviceId, PhysicalPosition, ButtonSource), { - self.handlers.borrow_mut().pointer_handler.on_mouse_press( + self.handlers.borrow_mut().pointer_handler.on_pointer_press( &self.common, - mouse_handler, - touch_handler, + handler, Rc::clone(&self.prevent_default), ) } - pub fn on_cursor_move(&self, mouse_handler: M, touch_handler: T, button_handler: B) + pub fn on_pointer_move(&self, cursor_handler: C, button_handler: B) where - M: 'static - + FnMut(ModifiersState, DeviceId, &mut dyn Iterator>), - T: 'static + C: 'static + FnMut( - ModifiersState, DeviceId, - FingerId, - &mut dyn Iterator, Force)>, + &mut dyn Iterator, PointerSource)>, ), B: 'static - + FnMut(ModifiersState, DeviceId, PhysicalPosition, ButtonsState, MouseButton), + + FnMut(ModifiersState, DeviceId, PhysicalPosition, ElementState, ButtonSource), { - self.handlers.borrow_mut().pointer_handler.on_cursor_move( + self.handlers.borrow_mut().pointer_handler.on_pointer_move( &self.common, - mouse_handler, - touch_handler, + cursor_handler, button_handler, Rc::clone(&self.prevent_default), ) } - pub fn on_touch_cancel(&self, handler: F) - where - F: 'static + FnMut(DeviceId, FingerId, PhysicalPosition, Force), - { - self.handlers.borrow_mut().pointer_handler.on_touch_cancel(&self.common, handler) - } - pub fn on_mouse_wheel(&self, mut handler: F) where F: 'static + FnMut(MouseScrollDelta, ModifiersState), diff --git a/src/platform_impl/web/web_sys/event.rs b/src/platform_impl/web/web_sys/event.rs index 46456d075c..2552b7a3c8 100644 --- a/src/platform_impl/web/web_sys/event.rs +++ b/src/platform_impl/web/web_sys/event.rs @@ -6,8 +6,9 @@ use wasm_bindgen::prelude::wasm_bindgen; use wasm_bindgen::{JsCast, JsValue}; use web_sys::{KeyboardEvent, MouseEvent, Navigator, PointerEvent, WheelEvent}; +use super::super::FingerId; use super::Engine; -use crate::event::{MouseButton, MouseScrollDelta}; +use crate::event::{MouseButton, MouseScrollDelta, PointerType}; use crate::keyboard::{Key, KeyLocation, ModifiersState, NamedKey, PhysicalKey}; bitflags::bitflags! { @@ -68,14 +69,14 @@ pub fn mouse_button(event: &MouseEvent) -> Option { } impl MouseButton { - pub fn to_id(self) -> u32 { + pub fn to_id(self) -> u16 { match self { MouseButton::Left => 0, MouseButton::Right => 1, MouseButton::Middle => 2, MouseButton::Back => 3, MouseButton::Forward => 4, - MouseButton::Other(value) => value.into(), + MouseButton::Other(value) => value, } } } @@ -160,6 +161,14 @@ pub fn mouse_scroll_delta( } } +pub fn pointer_type(event: &PointerEvent, pointer_id: i32) -> PointerType { + match event.pointer_type().as_str() { + "mouse" => PointerType::Mouse, + "touch" => PointerType::Touch(FingerId::new(pointer_id, event.is_primary()).into()), + _ => PointerType::Unknown, + } +} + pub fn key_code(event: &KeyboardEvent) -> PhysicalKey { let code = event.code(); PhysicalKey::from_key_code_attribute_value(&code) diff --git a/src/platform_impl/web/web_sys/mod.rs b/src/platform_impl/web/web_sys/mod.rs index e6d19077a9..df54b2bf36 100644 --- a/src/platform_impl/web/web_sys/mod.rs +++ b/src/platform_impl/web/web_sys/mod.rs @@ -18,7 +18,6 @@ use wasm_bindgen::JsCast; use web_sys::{Document, HtmlCanvasElement, Navigator, PageTransitionEvent, VisibilityState}; pub use self::canvas::{Canvas, Style}; -pub use self::event::ButtonsState; pub use self::event_handle::EventListenerHandle; pub use self::resize_scaling::ResizeScaleHandle; pub use self::schedule::Schedule; diff --git a/src/platform_impl/web/web_sys/pointer.rs b/src/platform_impl/web/web_sys/pointer.rs index 6679cbd2b0..2eaa787505 100644 --- a/src/platform_impl/web/web_sys/pointer.rs +++ b/src/platform_impl/web/web_sys/pointer.rs @@ -1,15 +1,14 @@ use std::cell::Cell; use std::rc::Rc; -use event::ButtonsState; use web_sys::PointerEvent; -use super::super::event::{DeviceId, FingerId}; +use super::super::event::DeviceId; use super::canvas::Common; use super::event; use super::event_handle::EventListenerHandle; use crate::dpi::PhysicalPosition; -use crate::event::{Force, MouseButton}; +use crate::event::{ButtonSource, ElementState, Force, PointerSource, PointerType}; use crate::keyboard::ModifiersState; #[allow(dead_code)] @@ -34,86 +33,78 @@ impl PointerHandler { } } - pub fn on_cursor_leave(&mut self, canvas_common: &Common, mut handler: F) + pub fn on_pointer_leave(&mut self, canvas_common: &Common, mut handler: F) where - F: 'static + FnMut(ModifiersState, Option), + F: 'static + FnMut(ModifiersState, DeviceId, PhysicalPosition, PointerType), { + let window = canvas_common.window.clone(); self.on_cursor_leave = Some(canvas_common.add_event("pointerout", move |event: PointerEvent| { let modifiers = event::mouse_modifiers(&event); - - // touch events are handled separately - // handling them here would produce duplicate mouse events, inconsistent with - // other platforms. - let device_id = - (event.pointer_type() != "touch").then(|| DeviceId::new(event.pointer_id())); - - handler(modifiers, device_id); + let pointer_id = event.pointer_id(); + let device_id = DeviceId::new(pointer_id); + let position = + event::mouse_position(&event).to_physical(super::scale_factor(&window)); + let ty = event::pointer_type(&event, pointer_id); + handler(modifiers, device_id, position, ty); })); } - pub fn on_cursor_enter(&mut self, canvas_common: &Common, mut handler: F) + pub fn on_pointer_enter(&mut self, canvas_common: &Common, mut handler: F) where - F: 'static + FnMut(ModifiersState, Option), + F: 'static + FnMut(ModifiersState, DeviceId, PhysicalPosition, PointerType), { + let window = canvas_common.window.clone(); self.on_cursor_enter = Some(canvas_common.add_event("pointerover", move |event: PointerEvent| { let modifiers = event::mouse_modifiers(&event); - - // touch events are handled separately - // handling them here would produce duplicate mouse events, inconsistent with - // other platforms. - let device_id = - (event.pointer_type() != "touch").then(|| DeviceId::new(event.pointer_id())); - - handler(modifiers, device_id); + let pointer_id = event.pointer_id(); + let device_id = DeviceId::new(pointer_id); + let position = + event::mouse_position(&event).to_physical(super::scale_factor(&window)); + let ty = event::pointer_type(&event, pointer_id); + handler(modifiers, device_id, position, ty); })); } - pub fn on_mouse_release( - &mut self, - canvas_common: &Common, - mut mouse_handler: M, - mut touch_handler: T, - ) where - M: 'static + FnMut(ModifiersState, DeviceId, PhysicalPosition, MouseButton), - T: 'static + FnMut(ModifiersState, DeviceId, FingerId, PhysicalPosition, Force), + pub fn on_pointer_release(&mut self, canvas_common: &Common, mut handler: C) + where + C: 'static + FnMut(ModifiersState, DeviceId, PhysicalPosition, ButtonSource), { let window = canvas_common.window.clone(); self.on_pointer_release = Some(canvas_common.add_event("pointerup", move |event: PointerEvent| { let modifiers = event::mouse_modifiers(&event); + let pointer_id = event.pointer_id(); + let ty = event::pointer_type(&event, pointer_id); - match event.pointer_type().as_str() { - "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), - ) + let button = event::mouse_button(&event).expect("no mouse button pressed"); + + let source = match ty { + PointerType::Mouse => ButtonSource::Mouse(button), + PointerType::Touch(finger_id) => ButtonSource::Touch { + finger_id, + force: Some(Force::Normalized(event.pressure().into())), }, - _ => mouse_handler( - modifiers, - DeviceId::new(event.pointer_id()), - event::mouse_position(&event).to_physical(super::scale_factor(&window)), - event::mouse_button(&event).expect("no mouse button released"), - ), - } + PointerType::Unknown => ButtonSource::Unknown(button.to_id()), + }; + + handler( + modifiers, + DeviceId::new(pointer_id), + event::mouse_position(&event).to_physical(super::scale_factor(&window)), + source, + ) })); } - pub fn on_mouse_press( + pub fn on_pointer_press( &mut self, canvas_common: &Common, - mut mouse_handler: M, - mut touch_handler: T, + mut handler: C, prevent_default: Rc>, ) where - M: 'static + FnMut(ModifiersState, DeviceId, PhysicalPosition, MouseButton), - T: 'static + FnMut(ModifiersState, DeviceId, FingerId, PhysicalPosition, Force), + C: 'static + FnMut(ModifiersState, DeviceId, PhysicalPosition, ButtonSource), { let window = canvas_common.window.clone(); let canvas = canvas_common.raw().clone(); @@ -127,69 +118,59 @@ impl PointerHandler { } let modifiers = event::mouse_modifiers(&event); - let pointer_type = &event.pointer_type(); - - match pointer_type.as_str() { - "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), - ); + let pointer_id = event.pointer_id(); + let ty = event::pointer_type(&event, pointer_id); + let button = event::mouse_button(&event).expect("no mouse button pressed"); + + let source = match ty { + PointerType::Mouse => { + // Error is swallowed here since the error would occur every time the + // mouse is clicked when the cursor is + // grabbed, and there is probably not a + // situation where this could fail, that we + // care if it fails. + let _e = canvas.set_pointer_capture(pointer_id); + + ButtonSource::Mouse(button) }, - _ => { - let pointer_id = event.pointer_id(); - - mouse_handler( - modifiers, - DeviceId::new(pointer_id), - event::mouse_position(&event).to_physical(super::scale_factor(&window)), - event::mouse_button(&event).expect("no mouse button pressed"), - ); - - if pointer_type == "mouse" { - // Error is swallowed here since the error would occur every time the - // mouse is clicked when the cursor is - // grabbed, and there is probably not a - // situation where this could fail, that we - // care if it fails. - let _e = canvas.set_pointer_capture(pointer_id); - } + PointerType::Touch(finger_id) => ButtonSource::Touch { + finger_id, + force: Some(Force::Normalized(event.pressure().into())), }, - } + PointerType::Unknown => ButtonSource::Unknown(button.to_id()), + }; + + handler( + modifiers, + DeviceId::new(pointer_id), + event::mouse_position(&event).to_physical(super::scale_factor(&window)), + source, + ) })); } - pub fn on_cursor_move( + pub fn on_pointer_move( &mut self, canvas_common: &Common, - mut mouse_handler: M, - mut touch_handler: T, + mut cursor_handler: C, mut button_handler: B, prevent_default: Rc>, ) where - M: 'static - + FnMut(ModifiersState, DeviceId, &mut dyn Iterator>), - T: 'static + C: 'static + FnMut( - ModifiersState, DeviceId, - FingerId, - &mut dyn Iterator, Force)>, + &mut dyn Iterator, PointerSource)>, ), B: 'static - + FnMut(ModifiersState, DeviceId, PhysicalPosition, ButtonsState, MouseButton), + + FnMut(ModifiersState, DeviceId, PhysicalPosition, ElementState, ButtonSource), { let window = canvas_common.window.clone(); let canvas = canvas_common.raw().clone(); self.on_cursor_move = Some(canvas_common.add_event("pointermove", move |event: PointerEvent| { - let modifiers = event::mouse_modifiers(&event); let pointer_id = event.pointer_id(); let device_id = DeviceId::new(pointer_id); + let ty = event::pointer_type(&event, pointer_id); // chorded button event if let Some(button) = event::mouse_button(&event) { @@ -200,11 +181,34 @@ impl PointerHandler { let _ = canvas.focus(); } + let state = if event::mouse_buttons(&event).contains(button.into()) { + ElementState::Pressed + } else { + ElementState::Released + }; + + let button = match ty { + PointerType::Mouse => ButtonSource::Mouse(button), + PointerType::Touch(finger_id) => { + let button_id = button.to_id(); + + if button_id != 1 { + tracing::error!("unexpected touch button id: {button_id}"); + } + + ButtonSource::Touch { + finger_id, + force: Some(Force::Normalized(event.pressure().into())), + } + }, + PointerType::Unknown => todo!(), + }; + button_handler( - modifiers, + event::mouse_modifiers(&event), device_id, event::mouse_position(&event).to_physical(super::scale_factor(&window)), - event::mouse_buttons(&event), + state, button, ); @@ -213,44 +217,24 @@ impl PointerHandler { // pointer move event let scale = super::scale_factor(&window); - match event.pointer_type().as_str() { - "touch" => touch_handler( - modifiers, - device_id, - FingerId::new(pointer_id, event.is_primary()), - &mut event::pointer_move_event(event).map(|event| { - ( - event::mouse_position(&event).to_physical(scale), - Force::Normalized(event.pressure() as f64), - ) - }), - ), - _ => mouse_handler( - modifiers, - device_id, - &mut event::pointer_move_event(event) - .map(|event| event::mouse_position(&event).to_physical(scale)), - ), - }; - })); - } - pub fn on_touch_cancel(&mut self, canvas_common: &Common, mut handler: F) - where - 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( - 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), - ); - } + cursor_handler( + device_id, + &mut event::pointer_move_event(event).map(|event| { + ( + event::mouse_modifiers(&event), + event::mouse_position(&event).to_physical(scale), + match ty { + PointerType::Mouse => PointerSource::Mouse, + PointerType::Touch(finger_id) => PointerSource::Touch { + finger_id, + force: Some(Force::Normalized(event.pressure().into())), + }, + PointerType::Unknown => PointerSource::Unknown, + }, + ) + }), + ); })); } diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 5a4cadc464..c25e83468d 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -37,9 +37,9 @@ use windows_sys::Win32::UI::WindowsAndMessaging::{ GetMenu, GetMessageW, KillTimer, LoadCursorW, PeekMessageW, PostMessageW, RegisterClassExW, RegisterWindowMessageA, SetCursor, SetTimer, SetWindowPos, TranslateMessage, CREATESTRUCTW, GWL_STYLE, GWL_USERDATA, HTCAPTION, HTCLIENT, MINMAXINFO, MNC_CLOSE, MSG, NCCALCSIZE_PARAMS, - PM_REMOVE, PT_PEN, PT_TOUCH, RI_MOUSE_HWHEEL, RI_MOUSE_WHEEL, SC_MINIMIZE, SC_RESTORE, - SIZE_MAXIMIZED, SWP_NOACTIVATE, SWP_NOMOVE, SWP_NOSIZE, SWP_NOZORDER, WHEEL_DELTA, WINDOWPOS, - WMSZ_BOTTOM, WMSZ_BOTTOMLEFT, WMSZ_BOTTOMRIGHT, WMSZ_LEFT, WMSZ_RIGHT, WMSZ_TOP, WMSZ_TOPLEFT, + PM_REMOVE, PT_TOUCH, RI_MOUSE_HWHEEL, RI_MOUSE_WHEEL, SC_MINIMIZE, SC_RESTORE, SIZE_MAXIMIZED, + SWP_NOACTIVATE, SWP_NOMOVE, SWP_NOSIZE, SWP_NOZORDER, WHEEL_DELTA, WINDOWPOS, WMSZ_BOTTOM, + WMSZ_BOTTOMLEFT, WMSZ_BOTTOMRIGHT, WMSZ_LEFT, WMSZ_RIGHT, WMSZ_TOP, WMSZ_TOPLEFT, WMSZ_TOPRIGHT, WM_CAPTURECHANGED, WM_CLOSE, WM_CREATE, WM_DESTROY, WM_DPICHANGED, WM_ENTERSIZEMOVE, WM_EXITSIZEMOVE, WM_GETMINMAXINFO, WM_IME_COMPOSITION, WM_IME_ENDCOMPOSITION, WM_IME_SETCONTEXT, WM_IME_STARTCOMPOSITION, WM_INPUT, WM_KEYDOWN, WM_KEYUP, WM_KILLFOCUS, @@ -58,7 +58,7 @@ use crate::application::ApplicationHandler; use crate::dpi::{PhysicalPosition, PhysicalSize}; use crate::error::{EventLoopError, ExternalError, OsError}; use crate::event::{ - Event, FingerId as RootFingerId, Force, Ime, InnerSizeWriter, RawKeyEvent, Touch, TouchPhase, + Event, FingerId as RootFingerId, Force, Ime, InnerSizeWriter, RawKeyEvent, TouchPhase, WindowEvent, }; use crate::event_loop::{ @@ -1518,7 +1518,8 @@ unsafe fn public_window_callback_inner( }, WM_MOUSEMOVE => { - use crate::event::WindowEvent::{CursorEntered, CursorLeft, CursorMoved}; + use crate::event::WindowEvent::{PointerEntered, PointerLeft, PointerMoved}; + use crate::event::{PointerSource, PointerType}; let x = super::get_x_lparam(lparam as u32) as i32; let y = super::get_y_lparam(lparam as u32) as i32; @@ -1539,7 +1540,11 @@ unsafe fn public_window_callback_inner( drop(w); userdata.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: CursorEntered { device_id: DEVICE_ID }, + event: PointerEntered { + device_id: DEVICE_ID, + position, + ty: PointerType::Mouse, + }, }); // Calling TrackMouseEvent in order to receive mouse leave events. @@ -1560,7 +1565,11 @@ unsafe fn public_window_callback_inner( drop(w); userdata.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: CursorLeft { device_id: DEVICE_ID }, + event: PointerLeft { + device_id: DEVICE_ID, + position: Some(position), + ty: PointerType::Mouse, + }, }); }, PointerMoveKind::None => drop(w), @@ -1579,7 +1588,11 @@ unsafe fn public_window_callback_inner( userdata.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: CursorMoved { device_id: DEVICE_ID, position }, + event: PointerMoved { + device_id: DEVICE_ID, + position, + source: PointerSource::Mouse, + }, }); } @@ -1587,7 +1600,9 @@ unsafe fn public_window_callback_inner( }, WM_MOUSELEAVE => { - use crate::event::WindowEvent::CursorLeft; + use crate::event::PointerType::Mouse; + use crate::event::WindowEvent::PointerLeft; + { let mut w = userdata.window_state_lock(); w.mouse.set_cursor_flags(window, |f| f.set(CursorFlags::IN_WINDOW, false)).ok(); @@ -1595,7 +1610,7 @@ unsafe fn public_window_callback_inner( userdata.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: CursorLeft { device_id: DEVICE_ID }, + event: PointerLeft { device_id: DEVICE_ID, position: None, ty: Mouse }, }); result = ProcResult::Value(0); @@ -1658,15 +1673,24 @@ unsafe fn public_window_callback_inner( WM_LBUTTONDOWN => { use crate::event::ElementState::Pressed; use crate::event::MouseButton::Left; - use crate::event::WindowEvent::MouseInput; + use crate::event::WindowEvent::PointerButton; unsafe { capture_mouse(window, &mut userdata.window_state_lock()) }; update_modifiers(window, userdata); + let x = super::get_x_lparam(lparam as u32) as i32; + let y = super::get_y_lparam(lparam as u32) as i32; + let position = PhysicalPosition::new(x as f64, y as f64); + userdata.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Left }, + event: PointerButton { + device_id: DEVICE_ID, + state: Pressed, + position, + button: Left.into(), + }, }); result = ProcResult::Value(0); }, @@ -1674,15 +1698,24 @@ unsafe fn public_window_callback_inner( WM_LBUTTONUP => { use crate::event::ElementState::Released; use crate::event::MouseButton::Left; - use crate::event::WindowEvent::MouseInput; + use crate::event::WindowEvent::PointerButton; unsafe { release_mouse(userdata.window_state_lock()) }; update_modifiers(window, userdata); + let x = super::get_x_lparam(lparam as u32) as i32; + let y = super::get_y_lparam(lparam as u32) as i32; + let position = PhysicalPosition::new(x as f64, y as f64); + userdata.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: MouseInput { device_id: DEVICE_ID, state: Released, button: Left }, + event: PointerButton { + device_id: DEVICE_ID, + state: Released, + position, + button: Left.into(), + }, }); result = ProcResult::Value(0); }, @@ -1690,15 +1723,24 @@ unsafe fn public_window_callback_inner( WM_RBUTTONDOWN => { use crate::event::ElementState::Pressed; use crate::event::MouseButton::Right; - use crate::event::WindowEvent::MouseInput; + use crate::event::WindowEvent::PointerButton; unsafe { capture_mouse(window, &mut userdata.window_state_lock()) }; update_modifiers(window, userdata); + let x = super::get_x_lparam(lparam as u32) as i32; + let y = super::get_y_lparam(lparam as u32) as i32; + let position = PhysicalPosition::new(x as f64, y as f64); + userdata.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Right }, + event: PointerButton { + device_id: DEVICE_ID, + state: Pressed, + position, + button: Right.into(), + }, }); result = ProcResult::Value(0); }, @@ -1706,15 +1748,24 @@ unsafe fn public_window_callback_inner( WM_RBUTTONUP => { use crate::event::ElementState::Released; use crate::event::MouseButton::Right; - use crate::event::WindowEvent::MouseInput; + use crate::event::WindowEvent::PointerButton; unsafe { release_mouse(userdata.window_state_lock()) }; update_modifiers(window, userdata); + let x = super::get_x_lparam(lparam as u32) as i32; + let y = super::get_y_lparam(lparam as u32) as i32; + let position = PhysicalPosition::new(x as f64, y as f64); + userdata.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: MouseInput { device_id: DEVICE_ID, state: Released, button: Right }, + event: PointerButton { + device_id: DEVICE_ID, + state: Released, + position, + button: Right.into(), + }, }); result = ProcResult::Value(0); }, @@ -1722,15 +1773,24 @@ unsafe fn public_window_callback_inner( WM_MBUTTONDOWN => { use crate::event::ElementState::Pressed; use crate::event::MouseButton::Middle; - use crate::event::WindowEvent::MouseInput; + use crate::event::WindowEvent::PointerButton; unsafe { capture_mouse(window, &mut userdata.window_state_lock()) }; update_modifiers(window, userdata); + let x = super::get_x_lparam(lparam as u32) as i32; + let y = super::get_y_lparam(lparam as u32) as i32; + let position = PhysicalPosition::new(x as f64, y as f64); + userdata.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Middle }, + event: PointerButton { + device_id: DEVICE_ID, + state: Pressed, + position, + button: Middle.into(), + }, }); result = ProcResult::Value(0); }, @@ -1738,15 +1798,24 @@ unsafe fn public_window_callback_inner( WM_MBUTTONUP => { use crate::event::ElementState::Released; use crate::event::MouseButton::Middle; - use crate::event::WindowEvent::MouseInput; + use crate::event::WindowEvent::PointerButton; unsafe { release_mouse(userdata.window_state_lock()) }; update_modifiers(window, userdata); + let x = super::get_x_lparam(lparam as u32) as i32; + let y = super::get_y_lparam(lparam as u32) as i32; + let position = PhysicalPosition::new(x as f64, y as f64); + userdata.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: MouseInput { device_id: DEVICE_ID, state: Released, button: Middle }, + event: PointerButton { + device_id: DEVICE_ID, + state: Released, + position, + button: Middle.into(), + }, }); result = ProcResult::Value(0); }, @@ -1754,23 +1823,29 @@ unsafe fn public_window_callback_inner( WM_XBUTTONDOWN => { use crate::event::ElementState::Pressed; use crate::event::MouseButton::{Back, Forward, Other}; - use crate::event::WindowEvent::MouseInput; + use crate::event::WindowEvent::PointerButton; let xbutton = super::get_xbutton_wparam(wparam as u32); unsafe { capture_mouse(window, &mut userdata.window_state_lock()) }; update_modifiers(window, userdata); + let x = super::get_x_lparam(lparam as u32) as i32; + let y = super::get_y_lparam(lparam as u32) as i32; + let position = PhysicalPosition::new(x as f64, y as f64); + userdata.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: MouseInput { + event: PointerButton { device_id: DEVICE_ID, state: Pressed, + position, button: match xbutton { 1 => Back, 2 => Forward, _ => Other(xbutton), - }, + } + .into(), }, }); result = ProcResult::Value(0); @@ -1779,23 +1854,29 @@ unsafe fn public_window_callback_inner( WM_XBUTTONUP => { use crate::event::ElementState::Released; use crate::event::MouseButton::{Back, Forward, Other}; - use crate::event::WindowEvent::MouseInput; + use crate::event::WindowEvent::PointerButton; let xbutton = super::get_xbutton_wparam(wparam as u32); unsafe { release_mouse(userdata.window_state_lock()) }; update_modifiers(window, userdata); + let x = super::get_x_lparam(lparam as u32) as i32; + let y = super::get_y_lparam(lparam as u32) as i32; + let position = PhysicalPosition::new(x as f64, y as f64); + userdata.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: MouseInput { + event: PointerButton { device_id: DEVICE_ID, state: Released, + position, button: match xbutton { 1 => Back, 2 => Forward, _ => Other(xbutton), - }, + } + .into(), }, }); result = ProcResult::Value(0); @@ -1813,6 +1894,10 @@ unsafe fn public_window_callback_inner( }, WM_TOUCH => { + use crate::event::ButtonSource::Touch; + use crate::event::ElementState::{Pressed, Released}; + use crate::event::{PointerSource, PointerType}; + let pcount = super::loword(wparam as u32) as usize; let mut inputs = Vec::with_capacity(pcount); let htouch = lparam; @@ -1826,36 +1911,70 @@ unsafe fn public_window_callback_inner( } { unsafe { inputs.set_len(pcount) }; for input in &inputs { - let mut location = POINT { x: input.x / 100, y: input.y / 100 }; + let mut position = POINT { x: input.x / 100, y: input.y / 100 }; - if unsafe { ScreenToClient(window, &mut location) } == false.into() { + if unsafe { ScreenToClient(window, &mut position) } == false.into() { continue; } - let x = location.x as f64 + (input.x % 100) as f64 / 100f64; - let y = location.y as f64 + (input.y % 100) as f64 / 100f64; - let location = PhysicalPosition::new(x, y); - userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), - event: WindowEvent::Touch(Touch { - phase: if util::has_flag(input.dwFlags, TOUCHEVENTF_DOWN) { - TouchPhase::Started - } else if util::has_flag(input.dwFlags, TOUCHEVENTF_UP) { - TouchPhase::Ended - } else if util::has_flag(input.dwFlags, TOUCHEVENTF_MOVE) { - TouchPhase::Moved - } else { - continue; - }, - location, - force: None, // WM_TOUCH doesn't support pressure information - finger_id: RootFingerId(FingerId { - id: input.dwID, - primary: util::has_flag(input.dwFlags, TOUCHEVENTF_PRIMARY), - }), - device_id: DEVICE_ID, - }), + let x = position.x as f64 + (input.x % 100) as f64 / 100f64; + let y = position.y as f64 + (input.y % 100) as f64 / 100f64; + let position = PhysicalPosition::new(x, y); + + let window_id = RootWindowId(WindowId(window)); + let finger_id = RootFingerId(FingerId { + id: input.dwID, + primary: util::has_flag(input.dwFlags, TOUCHEVENTF_PRIMARY), }); + + if util::has_flag(input.dwFlags, TOUCHEVENTF_DOWN) { + userdata.send_event(Event::WindowEvent { + window_id, + event: WindowEvent::PointerEntered { + device_id: DEVICE_ID, + position, + ty: PointerType::Touch(finger_id), + }, + }); + userdata.send_event(Event::WindowEvent { + window_id, + event: WindowEvent::PointerButton { + device_id: DEVICE_ID, + state: Pressed, + position, + button: Touch { finger_id, force: None }, + }, + }); + } else if util::has_flag(input.dwFlags, TOUCHEVENTF_UP) { + userdata.send_event(Event::WindowEvent { + window_id, + event: WindowEvent::PointerButton { + device_id: DEVICE_ID, + state: Released, + position, + button: Touch { finger_id, force: None }, + }, + }); + userdata.send_event(Event::WindowEvent { + window_id, + event: WindowEvent::PointerLeft { + device_id: DEVICE_ID, + position: Some(position), + ty: PointerType::Touch(finger_id), + }, + }); + } else if util::has_flag(input.dwFlags, TOUCHEVENTF_MOVE) { + userdata.send_event(Event::WindowEvent { + window_id, + event: WindowEvent::PointerMoved { + device_id: DEVICE_ID, + position, + source: PointerSource::Touch { finger_id, force: None }, + }, + }); + } else { + continue; + } } } unsafe { CloseTouchInputHandle(htouch) }; @@ -1863,6 +1982,9 @@ unsafe fn public_window_callback_inner( }, WM_POINTERDOWN | WM_POINTERUPDATE | WM_POINTERUP => { + use crate::event::ElementState::{Pressed, Released}; + use crate::event::{ButtonSource, PointerSource, PointerType}; + if let ( Some(GetPointerFrameInfoHistory), Some(SkipPointerFrameMessages), @@ -1947,67 +2069,100 @@ unsafe fn public_window_callback_inner( continue; } - let force = match pointer_info.pointerType { - PT_TOUCH => { - let mut touch_info = mem::MaybeUninit::uninit(); - util::GET_POINTER_TOUCH_INFO.and_then(|GetPointerTouchInfo| { - match unsafe { - GetPointerTouchInfo( - pointer_info.pointerId, - touch_info.as_mut_ptr(), - ) - } { - 0 => None, - _ => normalize_pointer_pressure(unsafe { - touch_info.assume_init().pressure - }), - } - }) - }, - PT_PEN => { - let mut pen_info = mem::MaybeUninit::uninit(); - util::GET_POINTER_PEN_INFO.and_then(|GetPointerPenInfo| { - match unsafe { - GetPointerPenInfo(pointer_info.pointerId, pen_info.as_mut_ptr()) - } { - 0 => None, - _ => normalize_pointer_pressure(unsafe { - pen_info.assume_init().pressure - }), - } - }) - }, - _ => None, + let force = if let PT_TOUCH = pointer_info.pointerType { + let mut touch_info = mem::MaybeUninit::uninit(); + util::GET_POINTER_TOUCH_INFO.and_then(|GetPointerTouchInfo| { + match unsafe { + GetPointerTouchInfo(pointer_info.pointerId, touch_info.as_mut_ptr()) + } { + 0 => None, + _ => normalize_pointer_pressure(unsafe { + touch_info.assume_init().pressure + }), + } + }) + } else { + None }; let x = location.x as f64 + x.fract(); let y = location.y as f64 + y.fract(); - let location = PhysicalPosition::new(x, y); - userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), - event: WindowEvent::Touch(Touch { - phase: if util::has_flag(pointer_info.pointerFlags, POINTER_FLAG_DOWN) { - TouchPhase::Started - } else if util::has_flag(pointer_info.pointerFlags, POINTER_FLAG_UP) { - TouchPhase::Ended - } else if util::has_flag(pointer_info.pointerFlags, POINTER_FLAG_UPDATE) - { - TouchPhase::Moved - } else { - continue; - }, - location, - force, - finger_id: RootFingerId(FingerId { - id: pointer_info.pointerId, - primary: util::has_flag( - pointer_info.pointerFlags, - POINTER_FLAG_PRIMARY, - ), - }), - device_id: DEVICE_ID, - }), + let position = PhysicalPosition::new(x, y); + + let window_id = RootWindowId(WindowId(window)); + let finger_id = RootFingerId(FingerId { + id: pointer_info.pointerId, + primary: util::has_flag(pointer_info.pointerFlags, POINTER_FLAG_PRIMARY), }); + + if util::has_flag(pointer_info.pointerFlags, POINTER_FLAG_DOWN) { + userdata.send_event(Event::WindowEvent { + window_id, + event: WindowEvent::PointerEntered { + device_id: DEVICE_ID, + position, + ty: if let PT_TOUCH = pointer_info.pointerType { + PointerType::Touch(finger_id) + } else { + PointerType::Unknown + }, + }, + }); + userdata.send_event(Event::WindowEvent { + window_id, + event: WindowEvent::PointerButton { + device_id: DEVICE_ID, + state: Pressed, + position, + button: if let PT_TOUCH = pointer_info.pointerType { + ButtonSource::Touch { finger_id, force } + } else { + ButtonSource::Unknown(0) + }, + }, + }); + } else if util::has_flag(pointer_info.pointerFlags, POINTER_FLAG_UP) { + userdata.send_event(Event::WindowEvent { + window_id, + event: WindowEvent::PointerButton { + device_id: DEVICE_ID, + state: Released, + position, + button: if let PT_TOUCH = pointer_info.pointerType { + ButtonSource::Touch { finger_id, force } + } else { + ButtonSource::Unknown(0) + }, + }, + }); + userdata.send_event(Event::WindowEvent { + window_id, + event: WindowEvent::PointerLeft { + device_id: DEVICE_ID, + position: Some(position), + ty: if let PT_TOUCH = pointer_info.pointerType { + PointerType::Touch(finger_id) + } else { + PointerType::Unknown + }, + }, + }); + } else if util::has_flag(pointer_info.pointerFlags, POINTER_FLAG_UPDATE) { + userdata.send_event(Event::WindowEvent { + window_id, + event: WindowEvent::PointerMoved { + device_id: DEVICE_ID, + position, + source: if let PT_TOUCH = pointer_info.pointerType { + PointerSource::Touch { finger_id, force } + } else { + PointerSource::Unknown + }, + }, + }); + } else { + continue; + } } unsafe { SkipPointerFrameMessages(pointer_id) }; @@ -2429,7 +2584,7 @@ unsafe extern "system" fn thread_event_target_callback( } unsafe fn handle_raw_input(userdata: &ThreadMsgTargetData, data: RAWINPUT) { - use crate::event::DeviceEvent::{Button, Key, MouseMotion, MouseWheel}; + use crate::event::DeviceEvent::{Button, Key, MouseWheel, PointerMotion}; use crate::event::ElementState::{Pressed, Released}; use crate::event::MouseScrollDelta::LineDelta; @@ -2445,7 +2600,7 @@ unsafe fn handle_raw_input(userdata: &ThreadMsgTargetData, data: RAWINPUT) { if x != 0.0 || y != 0.0 { userdata.send_event(Event::DeviceEvent { device_id, - event: MouseMotion { delta: (x, y) }, + event: PointerMotion { delta: (x, y) }, }); } } diff --git a/src/platform_impl/windows/util.rs b/src/platform_impl/windows/util.rs index c7a337e791..89288d1bba 100644 --- a/src/platform_impl/windows/util.rs +++ b/src/platform_impl/windows/util.rs @@ -14,7 +14,7 @@ use windows_sys::Win32::UI::HiDpi::{ DPI_AWARENESS_CONTEXT, MONITOR_DPI_TYPE, PROCESS_DPI_AWARENESS, }; use windows_sys::Win32::UI::Input::KeyboardAndMouse::GetActiveWindow; -use windows_sys::Win32::UI::Input::Pointer::{POINTER_INFO, POINTER_PEN_INFO, POINTER_TOUCH_INFO}; +use windows_sys::Win32::UI::Input::Pointer::{POINTER_INFO, POINTER_TOUCH_INFO}; use windows_sys::Win32::UI::WindowsAndMessaging::{ ClipCursor, GetClientRect, GetClipCursor, GetSystemMetrics, GetWindowPlacement, GetWindowRect, IsIconic, ShowCursor, IDC_APPSTARTING, IDC_ARROW, IDC_CROSS, IDC_HAND, IDC_HELP, IDC_IBEAM, @@ -244,9 +244,6 @@ pub type GetPointerDeviceRects = unsafe extern "system" fn( pub type GetPointerTouchInfo = unsafe extern "system" fn(pointerId: u32, touchInfo: *mut POINTER_TOUCH_INFO) -> BOOL; -pub type GetPointerPenInfo = - unsafe extern "system" fn(pointId: u32, penInfo: *mut POINTER_PEN_INFO) -> BOOL; - pub(crate) static GET_DPI_FOR_WINDOW: Lazy> = Lazy::new(|| get_function!("user32.dll", GetDpiForWindow)); pub(crate) static ADJUST_WINDOW_RECT_EX_FOR_DPI: Lazy> = @@ -269,5 +266,3 @@ pub(crate) static GET_POINTER_DEVICE_RECTS: Lazy> Lazy::new(|| get_function!("user32.dll", GetPointerDeviceRects)); pub(crate) static GET_POINTER_TOUCH_INFO: Lazy> = Lazy::new(|| get_function!("user32.dll", GetPointerTouchInfo)); -pub(crate) static GET_POINTER_PEN_INFO: Lazy> = - Lazy::new(|| get_function!("user32.dll", GetPointerPenInfo));