diff --git a/examples/child_window.rs b/examples/child_window.rs index c16d323766..43ed75c9b1 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 3b1a73802c..f9f3c8b84c 100644 --- a/examples/window.rs +++ b/examples/window.rs @@ -446,20 +446,23 @@ impl ApplicationHandler for Application { } } }, - WindowEvent::MouseInput { button, state, .. } => { + WindowEvent::PointerButton { button, state, .. } => { + info!("Pointer button {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 { .. } => { - info!("Cursor left Window={window_id:?}"); + WindowEvent::PointerLeft { .. } => { + info!("Pointer left Window={window_id:?}"); window.cursor_left(); }, - WindowEvent::CursorMoved { position, .. } => { - info!("Moved cursor to {position:?}"); + WindowEvent::PointerMoved { position, .. } => { + info!("Moved pointer to {position:?}"); window.cursor_moved(position); }, WindowEvent::ActivationTokenDone { token: _token, .. } => { @@ -510,11 +513,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 2a89a131cd..440c93691f 100644 --- a/src/changelog/unreleased.md +++ b/src/changelog/unreleased.md @@ -56,9 +56,6 @@ 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()`. @@ -66,6 +63,8 @@ changelog entry. - On macOS, add `WindowExtMacOS::set_borderless_game` and `WindowAttributesExtMacOS::with_borderless_game` to fully disable the menu bar and dock in Borderless Fullscreen as commonly done in games. - Add `WindowId::into_raw()` and `from_raw()`. +- Add `PointerKind`, `PointerSource`, `ButtonSource`, `FingerId` and `position` to all pointer + events as part of the pointer event overhaul. ### Changed @@ -127,6 +126,29 @@ changelog entry. To migrate, you can probably just replace all instances of `inner_size` with `surface_size` in your codebase. - Every event carrying a `DeviceId` now uses `Option` instead. A `None` value signifies that the device can't be uniquely identified. +- 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`. + - `PointerMoved` is **not sent** after `PointerEntered` anymore. + - Remove `Touch`, which is folded into the `Pointer*` events. + - New `PointerKind` added to `PointerEntered` and `PointerLeft`, signifying which pointer type is + the source of this event. + - New `PointerSource` added to `PointerMoved`, similar to `PointerKind` but holding additional + data. + - New `ButtonSource` added to `PointerButton`, similar to `PointerKind` 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 `PointerKind::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 @@ -149,13 +171,15 @@ 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 `impl From for WindowId` and `impl From for u64`. Replaced with `WindowId::into_raw()` and `from_raw()`. - Remove `dummy()` from `WindowId` and `DeviceId`. +- Remove `WindowEvent::Touch` and `Touch` in favor of the new `PointerKind`, `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 3742596d5d..393ef38b2b 100644 --- a/src/event.rs +++ b/src/event.rs @@ -226,53 +226,89 @@ pub enum WindowEvent { /// - **iOS / Android / Web / Orbital:** Unsupported. 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 { + /// The pointer has moved on the window. + PointerMoved { device_id: Option, - /// (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. For that, - /// consider [`DeviceEvent::MouseMotion`]. + /// (x,y) coordinates 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 pointer acceleration, it + /// should not be used to implement non-pointer-like interactions such as 3D camera + /// control. For that, consider [`DeviceEvent::PointerMotion`]. + /// + /// ## 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: Option }, + /// The pointer has entered the window. + PointerEntered { + device_id: Option, - /// 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: Option }, + /// The position of the pointer 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, + + kind: PointerKind, + }, + + /// The pointer has left the window. + PointerLeft { + device_id: Option, + + /// The position of the pointer when it left the window. The position reported can be + /// outside the bounds of 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>, + + kind: PointerKind, + }, /// A mouse wheel movement or touchpad scroll occurred. MouseWheel { device_id: Option, delta: MouseScrollDelta, phase: TouchPhase }, /// An mouse button press has been received. - MouseInput { device_id: Option, state: ElementState, button: MouseButton }, + PointerButton { + device_id: Option, + 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. /// @@ -346,18 +382,6 @@ pub enum WindowEvent { /// touchpad is being pressed) and stage (integer representing the click level). TouchpadPressure { device_id: Option, 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: @@ -431,6 +455,129 @@ pub enum WindowEvent { RedrawRequested, } +/// Represents the kind type of a pointer event. +/// +/// ## Platform-specific +/// +/// **Wayland/X11:** [`Unknown`](Self::Unknown) device types are converted to known variants by the +/// system. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum PointerKind { + 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. +/// +/// **Wayland/X11:** [`Unknown`](Self::Unknown) device types are converted to known variants by the +/// system. +#[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, + + /// Describes how hard the screen was pressed. May be [`None`] if the hardware does not + /// support pressure sensitivity. + /// + /// ## Platform-specific + /// + /// - **MacOS / Orbital / Wayland / X11:** Always emits [`None`]. + /// - **Android:** 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).#[derive(Debug, Clone, Copy, PartialEq)] + /// - **Web:** Will never be [`None`]. If the device doesn't support pressure sensitivity, + /// force will be 0.5 when a button is pressed or 0.0 otherwise. + force: Option, + }, + Unknown, +} + +impl From for PointerKind { + 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`]. +/// +/// **Wayland/X11:** [`Unknown`](Self::Unknown) device types are converted to known variants by the +/// system. +#[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 { + /// Convert any [`ButtonSource`] to an equivalent [`MouseButton`]. If a pointer type has no + /// special handling in an application, this method can be used to handle it like any generic + /// mouse input. + 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 @@ -459,7 +606,7 @@ impl FingerId { /// Useful for interactions that diverge significantly from a conventional 2D GUI, such as 3D camera /// or first-person game controls. Many physical actions, such as mouse movement, can produce both /// device and window events. Because window events typically arise from virtual devices -/// (corresponding to GUI cursors and keyboard focus) the device IDs may not match. +/// (corresponding to GUI pointers and keyboard focus) the device IDs may not match. /// /// Note that these events are delivered regardless of input focus. #[derive(Clone, Copy, Debug, PartialEq)] @@ -467,7 +614,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 /// @@ -484,7 +631,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. @@ -813,50 +960,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: Option, - 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))] @@ -877,12 +980,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 @@ -899,13 +996,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, } } @@ -1028,6 +1119,7 @@ mod tests { use crate::event::Event::*; use crate::event::Ime::Enabled; use crate::event::WindowEvent::*; + use crate::event::{PointerKind, PointerSource}; use crate::window::WindowId; // Mainline events. @@ -1050,19 +1142,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: None, position: (0, 0).into() }); + with_window_event(PointerMoved { + device_id: None, + position: (0, 0).into(), + source: PointerSource::Mouse, + }); with_window_event(ModifiersChanged(event::Modifiers::default())); - with_window_event(CursorEntered { device_id: None }); - with_window_event(CursorLeft { device_id: None }); + with_window_event(PointerEntered { + device_id: None, + position: (0, 0).into(), + kind: PointerKind::Mouse, + }); + with_window_event(PointerLeft { + device_id: None, + position: Some((0, 0).into()), + kind: PointerKind::Mouse, + }); with_window_event(MouseWheel { device_id: None, delta: event::MouseScrollDelta::LineDelta(0.0, 0.0), phase: event::TouchPhase::Started, }); - with_window_event(MouseInput { + with_window_event(PointerButton { device_id: None, 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: None, + 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: None, @@ -1081,13 +1195,6 @@ mod tests { phase: event::TouchPhase::Started, }); with_window_event(TouchpadPressure { device_id: None, pressure: 0.0, stage: 0 }); - with_window_event(Touch(event::Touch { - device_id: None, - 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)); } @@ -1099,7 +1206,7 @@ mod tests { let with_device_event = |dev_ev| x(event::Event::DeviceEvent { device_id: None, 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), }); @@ -1122,15 +1229,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); } @@ -1154,16 +1256,6 @@ mod tests { HashSet::new().insert(event::MouseButton::Left.clone()); HashSet::new().insert(event::Ime::Enabled); - let _ = event::Touch { - device_id: None, - 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/event_loop.rs b/src/event_loop.rs index edcac345f8..155a1262de 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -420,7 +420,7 @@ impl rwh_06::HasDisplayHandle for dyn ActiveEventLoop + '_ { /// A proxy for the underlying display handle. /// -/// The purpose of this type is to provide a cheaply clonable handle to the underlying +/// The purpose of this type is to provide a cheaply cloneable handle to the underlying /// display handle. This is often used by graphics APIs to connect to the underlying APIs. /// It is difficult to keep a handle to the [`EventLoop`] type or the [`ActiveEventLoop`] /// type. In contrast, this type involves no lifetimes and can be persisted for as long as diff --git a/src/platform/web.rs b/src/platform/web.rs index b4c93f0c79..a64a890442 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::SurfaceResized`] and [`Window::(set_)surface_size()`] //! - [`WindowEvent::Occluded`] -//! - [`WindowEvent::CursorMoved`], [`WindowEvent::CursorEntered`], [`WindowEvent::CursorLeft`], and -//! [`WindowEvent::Touch`]. +//! - [`WindowEvent::PointerMoved`], [`WindowEvent::PointerEntered`] and +//! [`WindowEvent::PointerLeft`]. //! - [`Window::set_outer_position()`] //! //! [`WindowEvent::SurfaceResized`]: crate::event::WindowEvent::SurfaceResized //! [`Window::(set_)surface_size()`]: crate::window::Window::surface_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 a93dc56dd5..771c9735db 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -317,48 +317,115 @@ impl EventLoop { InputEvent::MotionEvent(motion_event) => { let window_id = window::WindowId(WindowId); let device_id = Some(event::DeviceId(DeviceId(motion_event.device_id()))); - - let phase = match motion_event.action() { - MotionAction::Down | MotionAction::PointerDown => { - Some(event::TouchPhase::Started) - }, - MotionAction::Up | MotionAction::PointerUp => Some(event::TouchPhase::Ended), - MotionAction::Move => Some(event::TouchPhase::Moved), - MotionAction::Cancel => Some(event::TouchPhase::Cancelled), - _ => { - None // TODO mouse events + let action = motion_event.action(); + + let pointers: Option< + Box>>, + > = match action { + MotionAction::Down + | MotionAction::PointerDown + | MotionAction::Up + | MotionAction::PointerUp => Some(Box::new(std::iter::once( + motion_event.pointer_at_index(motion_event.pointer_index()), + ))), + MotionAction::Move | MotionAction::Cancel => { + Some(Box::new(motion_event.pointers())) }, + // TODO mouse events + _ => None, }; - if let Some(phase) = phase { - let pointers: Box>> = - match phase { - event::TouchPhase::Started | event::TouchPhase::Ended => { - Box::new(std::iter::once( - motion_event.pointer_at_index(motion_event.pointer_index()), - )) - }, - event::TouchPhase::Moved | event::TouchPhase::Cancelled => { - Box::new(motion_event.pointers()) - }, - }; + if let Some(pointers) = pointers { for pointer in pointers { - let location = + let tool_type = pointer.tool_type(); + let position = PhysicalPosition { x: pointer.x() as _, y: pointer.y() as _ }; trace!( - "Input event {device_id:?}, {phase:?}, loc={location:?}, \ - pointer={pointer:?}" + "Input event {device_id:?}, {action:?}, loc={position:?}, \ + pointer={pointer:?}, tool_type={tool_type:?}" ); - - 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); + let finger_id = event::FingerId(FingerId(pointer.pointer_id())); + let force = Some(Force::Normalized(pointer.pressure() as f64)); + + match action { + MotionAction::Down | MotionAction::PointerDown => { + let event = event::WindowEvent::PointerEntered { + device_id, + position, + kind: match tool_type { + android_activity::input::ToolType::Finger => { + event::PointerKind::Touch(finger_id) + }, + // TODO mouse events + android_activity::input::ToolType::Mouse => continue, + _ => event::PointerKind::Unknown, + }, + }; + app.window_event(&self.window_target, window_id, event); + let event = event::WindowEvent::PointerButton { + device_id, + state: event::ElementState::Pressed, + position, + button: match tool_type { + android_activity::input::ToolType::Finger => { + event::ButtonSource::Touch { finger_id, force } + }, + // TODO mouse events + android_activity::input::ToolType::Mouse => continue, + _ => event::ButtonSource::Unknown(0), + }, + }; + app.window_event(&self.window_target, window_id, event); + }, + MotionAction::Move => { + let event = event::WindowEvent::PointerMoved { + device_id, + position, + source: match tool_type { + android_activity::input::ToolType::Finger => { + event::PointerSource::Touch { finger_id, force } + }, + // TODO mouse events + android_activity::input::ToolType::Mouse => continue, + _ => event::PointerSource::Unknown, + }, + }; + app.window_event(&self.window_target, window_id, event); + }, + MotionAction::Up | MotionAction::PointerUp | MotionAction::Cancel => { + if let MotionAction::Up | MotionAction::PointerUp = action { + let event = event::WindowEvent::PointerButton { + device_id, + state: event::ElementState::Released, + position, + button: match tool_type { + android_activity::input::ToolType::Finger => { + event::ButtonSource::Touch { finger_id, force } + }, + // TODO mouse events + android_activity::input::ToolType::Mouse => continue, + _ => event::ButtonSource::Unknown(0), + }, + }; + app.window_event(&self.window_target, window_id, event); + } + + let event = event::WindowEvent::PointerLeft { + device_id, + position: Some(position), + kind: match tool_type { + android_activity::input::ToolType::Finger => { + event::PointerKind::Touch(finger_id) + }, + // TODO mouse events + android_activity::input::ToolType::Mouse => continue, + _ => event::PointerKind::Unknown, + }, + }; + app.window_event(&self.window_target, window_id, event); + }, + _ => unreachable!(), + } } } }, diff --git a/src/platform_impl/apple/appkit/app.rs b/src/platform_impl/apple/appkit/app.rs index 5292f92f41..747a17b4c5 100644 --- a/src/platform_impl/apple/appkit/app.rs +++ b/src/platform_impl/apple/appkit/app.rs @@ -60,7 +60,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, None, DeviceEvent::MouseMotion { + app.device_event(event_loop, None, 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 f7c3f9b1d8..b8d878da0e 100644 --- a/src/platform_impl/apple/appkit/view.rs +++ b/src/platform_impl/apple/appkit/view.rs @@ -26,8 +26,8 @@ use super::event::{ use super::window::WinitWindow; use crate::dpi::{LogicalPosition, LogicalSize}; use crate::event::{ - DeviceEvent, ElementState, Ime, Modifiers, MouseButton, MouseScrollDelta, TouchPhase, - WindowEvent, + DeviceEvent, ElementState, Ime, Modifiers, MouseButton, MouseScrollDelta, PointerKind, + PointerSource, TouchPhase, WindowEvent, }; use crate::keyboard::{Key, KeyCode, KeyLocation, ModifiersState, NamedKey}; use crate::platform::macos::OptionAsAlt; @@ -638,19 +638,28 @@ 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 position = self.mouse_view_point(event).to_physical(self.scale_factor()); + + self.queue_event(WindowEvent::PointerEntered { device_id: None, + position, + kind: PointerKind::Mouse, }); } #[method(mouseExited:)] - fn mouse_exited(&self, _event: &NSEvent) { + fn mouse_exited(&self, event: &NSEvent) { trace_scope!("mouseExited:"); - self.queue_event(WindowEvent::CursorLeft { + let position = self.mouse_view_point(event).to_physical(self.scale_factor()); + + self.queue_event(WindowEvent::PointerLeft { device_id: None, + position: Some(position), + kind: PointerKind::Mouse, }); } @@ -1033,16 +1042,21 @@ impl WinitView { } fn mouse_click(&self, event: &NSEvent, button_state: ElementState) { + let position = self.mouse_view_point(event).to_physical(self.scale_factor()); let button = mouse_button(event); self.update_modifiers(event, false); - self.queue_event(WindowEvent::MouseInput { device_id: None, state: button_state, button }); + self.queue_event(WindowEvent::PointerButton { + device_id: None, + state: button_state, + position, + button: button.into(), + }); } fn mouse_motion(&self, event: &NSEvent) { - let window_point = unsafe { event.locationInWindow() }; - let view_point = self.convertPoint_fromView(window_point, None); + let view_point = self.mouse_view_point(event); let frame = self.frame(); if view_point.x.is_sign_negative() @@ -1057,15 +1071,21 @@ impl WinitView { } } - let view_point = LogicalPosition::new(view_point.x, view_point.y); - self.update_modifiers(event, false); - self.queue_event(WindowEvent::CursorMoved { + self.queue_event(WindowEvent::PointerMoved { device_id: None, position: view_point.to_physical(self.scale_factor()), + source: PointerSource::Mouse, }); } + + fn mouse_view_point(&self, event: &NSEvent) -> LogicalPosition { + let window_point = unsafe { event.locationInWindow() }; + let view_point = self.convertPoint_fromView(window_point, None); + + LogicalPosition::new(view_point.x, view_point.y) + } } /// Get the mouse button from the NSEvent. diff --git a/src/platform_impl/apple/uikit/view.rs b/src/platform_impl/apple/uikit/view.rs index a258a8dae0..b11d01354c 100644 --- a/src/platform_impl/apple/uikit/view.rs +++ b/src/platform_impl/apple/uikit/view.rs @@ -17,7 +17,8 @@ use super::window::WinitUIWindow; use super::FingerId; use crate::dpi::PhysicalPosition; use crate::event::{ - ElementState, Event, FingerId as RootFingerId, Force, KeyEvent, Touch, TouchPhase, WindowEvent, + ButtonSource, ElementState, Event, FingerId as RootFingerId, Force, KeyEvent, PointerKind, + PointerSource, TouchPhase, WindowEvent, }; use crate::keyboard::{Key, KeyCode, KeyLocation, NamedKey, NativeKeyCode, PhysicalKey}; use crate::platform_impl::KeyEventExtra; @@ -483,25 +484,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 @@ -511,32 +505,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: None, - 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: None, + position, + kind: if let UITouchType::Pencil = touch_type { + PointerKind::Unknown + } else { + PointerKind::Touch(finger_id) + }, + }, + })); + touch_events.push(EventWrapper::StaticEvent(Event::WindowEvent { + window_id, + event: WindowEvent::PointerButton { + device_id: None, + 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: None, + 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: None, + 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: None, + position: Some(position), + kind: if let UITouchType::Pencil = touch_type { + PointerKind::Unknown + } else { + PointerKind::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 e99988fe28..d080967b5f 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, PointerKind, TouchPhase, WindowEvent}; use crate::platform_impl::wayland::state::WinitState; use crate::platform_impl::wayland::{self, WindowId}; @@ -123,7 +123,11 @@ impl PointerHandler for WinitState { // Regular events on the main surface. PointerEventKind::Enter { .. } => { self.events_sink.push_window_event( - WindowEvent::CursorEntered { device_id: None }, + WindowEvent::PointerEntered { + device_id: None, + position, + kind: PointerKind::Mouse, + }, window_id, ); @@ -131,11 +135,6 @@ impl PointerHandler for WinitState { // 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: None, position }, - window_id, - ); }, PointerEventKind::Leave { .. } => { window.pointer_left(Arc::downgrade(themed_pointer)); @@ -143,12 +142,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: None }, window_id); + self.events_sink.push_window_event( + WindowEvent::PointerLeft { + device_id: None, + position: Some(position), + kind: PointerKind::Mouse, + }, + window_id, + ); }, PointerEventKind::Motion { .. } => { self.events_sink.push_window_event( - WindowEvent::CursorMoved { device_id: None, position }, + WindowEvent::PointerMoved { + device_id: None, + position, + source: PointerSource::Mouse, + }, window_id, ); }, @@ -164,7 +173,12 @@ impl PointerHandler for WinitState { ElementState::Released }; self.events_sink.push_window_event( - WindowEvent::MouseInput { device_id: None, state, button }, + WindowEvent::PointerButton { + device_id: None, + 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 b71fc238d2..4e7c7ec179 100644 --- a/src/platform_impl/linux/wayland/seat/pointer/relative_pointer.rs +++ b/src/platform_impl/linux/wayland/seat/pointer/relative_pointer.rs @@ -68,7 +68,7 @@ impl Dispatch for RelativePointerS }; state .events_sink - .push_device_event(DeviceEvent::MouseMotion { delta: (dx_unaccel, dy_unaccel) }); + .push_device_event(DeviceEvent::PointerMotion { delta: (dx_unaccel, dy_unaccel) }); } } diff --git a/src/platform_impl/linux/wayland/seat/touch/mod.rs b/src/platform_impl/linux/wayland/seat/touch/mod.rs index caaf77224d..cadfbc647f 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, PointerKind, PointerSource, WindowEvent}; use crate::platform_impl::wayland::state::WinitState; use crate::platform_impl::wayland::{self, FingerId}; @@ -42,16 +42,25 @@ impl TouchHandler for WinitState { let location = LogicalPosition::::from(position); seat_state.touch_map.insert(id, TouchPoint { surface, location }); + 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 { + WindowEvent::PointerEntered { device_id: None, - phase: TouchPhase::Started, - location: location.to_physical(scale_factor), - force: None, - finger_id: crate::event::FingerId(crate::platform_impl::FingerId::Wayland( - FingerId(id), - )), - }), + position, + kind: PointerKind::Touch(finger_id), + }, + window_id, + ); + self.events_sink.push_window_event( + WindowEvent::PointerButton { + device_id: None, + state: ElementState::Pressed, + position, + button: ButtonSource::Touch { finger_id, force: None }, + }, window_id, ); } @@ -85,16 +94,25 @@ impl TouchHandler for WinitState { None => return, }; + let position = touch_point.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::PointerButton { + device_id: None, + state: ElementState::Released, + position, + button: ButtonSource::Touch { finger_id, force: None }, + }, + window_id, + ); self.events_sink.push_window_event( - WindowEvent::Touch(Touch { + WindowEvent::PointerLeft { device_id: None, - 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), - )), - }), + position: Some(position), + kind: PointerKind::Touch(finger_id), + }, window_id, ); } @@ -131,15 +149,16 @@ impl TouchHandler for WinitState { touch_point.location = LogicalPosition::::from(position); self.events_sink.push_window_event( - WindowEvent::Touch(Touch { + WindowEvent::PointerMoved { device_id: None, - 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, ); } @@ -160,18 +179,16 @@ 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: None, - phase: TouchPhase::Cancelled, - location, - force: None, - finger_id: crate::event::FingerId(crate::platform_impl::FingerId::Wayland( - FingerId(id), + position: Some(position), + kind: PointerKind::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 c92bbbb77f..353b93f07a 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, MouseButton, MouseScrollDelta, RawKeyEvent, - SurfaceSizeWriter, Touch, TouchPhase, WindowEvent, + ButtonSource, DeviceEvent, ElementState, Event, Ime, MouseButton, MouseScrollDelta, + PointerKind, PointerSource, RawKeyEvent, SurfaceSizeWriter, 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 { @@ -1025,16 +1018,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 @@ -1052,10 +1056,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 }; @@ -1084,7 +1103,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() { @@ -1167,13 +1190,13 @@ impl EventProcessor { let device_id = Some(device_id); 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, + kind: PointerKind::Mouse, + }, }; callback(&self.target, event); } @@ -1193,8 +1216,10 @@ impl EventProcessor { if self.window_exists(window) { let event = Event::WindowEvent { window_id: mkwid(window), - event: WindowEvent::CursorLeft { + event: WindowEvent::PointerLeft { device_id: Some(mkdid(event.deviceid as xinput::DeviceId)), + position: Some(PhysicalPosition::new(event.event_x, event.event_y)), + kind: PointerKind::Mouse, }, }; callback(&self.target, event); @@ -1253,7 +1278,7 @@ 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); } @@ -1309,7 +1334,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), { @@ -1320,29 +1345,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 { device_id: None, position: location.cast() }, + event: WindowEvent::PointerMoved { + device_id: None, + position: position.cast(), + source: PointerSource::Mouse, + }, }; callback(&self.target, event); } - let event = Event::WindowEvent { - window_id, - event: WindowEvent::Touch(Touch { - device_id: Some(mkdid(xev.deviceid as xinput::DeviceId)), - phase, - location, - force: None, // TODO - finger_id: mkfid(id), - }), - }; - callback(&self.target, event) + let device_id = Some(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, + kind: PointerKind::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, + position: Some(position), + kind: PointerKind::Touch(finger_id), + }, + }; + callback(&self.target, event); + }, + _ => unreachable!(), + } } } @@ -1398,7 +1475,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); } @@ -1762,15 +1839,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 19a774c413..f0f397ff68 100644 --- a/src/platform_impl/orbital/event_loop.rs +++ b/src/platform_impl/orbital/event_loop.rs @@ -407,11 +407,15 @@ impl EventLoop { app.window_event( window_target, RootWindowId(window_id), - event::WindowEvent::CursorMoved { device_id: None, position: (x, y).into() }, + event::WindowEvent::PointerMoved { + device_id: None, + position: (x, y).into(), + source: event::PointerSource::Mouse, + }, ); }, EventOption::MouseRelative(MouseRelativeEvent { dx, dy }) => { - app.device_event(window_target, None, event::DeviceEvent::MouseMotion { + app.device_event(window_target, None, event::DeviceEvent::PointerMotion { delta: (dx as f64, dy as f64), }); }, @@ -420,7 +424,12 @@ impl EventLoop { app.window_event( window_target, RootWindowId(window_id), - event::WindowEvent::MouseInput { device_id: None, state, button }, + event::WindowEvent::PointerButton { + device_id: None, + state, + position: dpi::PhysicalPosition::default(), + button: button.into(), + }, ); } }, @@ -469,9 +478,17 @@ impl EventLoop { // TODO: Screen, Clipboard, Drop EventOption::Hover(HoverEvent { entered }) => { let event = if entered { - event::WindowEvent::CursorEntered { device_id: None } + event::WindowEvent::PointerEntered { + device_id: None, + position: dpi::PhysicalPosition::default(), + kind: event::PointerKind::Mouse, + } } else { - event::WindowEvent::CursorLeft { device_id: None } + event::WindowEvent::PointerLeft { + device_id: None, + position: None, + kind: event::PointerKind::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 6912bfc93a..0badcfebb7 100644 --- a/src/platform_impl/web/event.rs +++ b/src/platform_impl/web/event.rs @@ -1,5 +1,7 @@ -#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] -pub struct DeviceId(u32); +use crate::event::FingerId as RootFingerId; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct DeviceId(pub(crate) u32); impl DeviceId { pub fn new(pointer_id: i32) -> Option { @@ -34,3 +36,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 f6fedab0a0..6f33691231 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: DeviceId::new(event.pointer_id()).map(RootDeviceId), 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: DeviceId::new(event.pointer_id()).map(RootDeviceId), 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 dbd3dd7217..77196fef1f 100644 --- a/src/platform_impl/web/event_loop/window_target.rs +++ b/src/platform_impl/web/event_loop/window_target.rs @@ -12,8 +12,7 @@ use super::window::WindowId; use super::{backend, runner, EventLoopProxy}; use crate::error::{NotSupportedError, RequestError}; 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, @@ -200,12 +199,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, kind| { let focus = (has_focus.get() && modifiers.get() != active_modifiers).then(|| { modifiers.set(active_modifiers); Event::WindowEvent { @@ -214,23 +213,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: device_id.map(RootDeviceId) }, - }); - - if focus.is_some() || pointer.is_some() { - runner.send_events(focus.into_iter().chain(pointer)) - } + event: WindowEvent::PointerLeft { + device_id: device_id.map(RootDeviceId), + position: Some(position), + kind, + }, + }))) } }); - 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, kind| { let focus = (has_focus.get() && modifiers.get() != active_modifiers).then(|| { modifiers.set(active_modifiers); Event::WindowEvent { @@ -239,70 +238,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: device_id.map(RootDeviceId) }, - }); - - if focus.is_some() || pointer.is_some() { - runner.send_events(focus.into_iter().chain(pointer)) - } + event: WindowEvent::PointerEntered { + device_id: device_id.map(RootDeviceId), + position, + kind, + }, + }))) } }); - 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 = pointer_id.map(RootDeviceId); - 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: device_id.map(RootDeviceId), - phase: TouchPhase::Moved, - force: Some(force), - location, - }), - }, - ))); + event: WindowEvent::PointerMoved { device_id, position, source }, + })) + })); } }, { @@ -310,11 +280,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); @@ -326,70 +292,48 @@ impl ActiveEventLoop { let device_id = device_id.map(RootDeviceId); - 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 = pointer_id.map(RootDeviceId); + let device_id = pointer_id.map(RootDeviceId); + 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, + }, + }))); + } + }); - // 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(); + 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), @@ -397,89 +341,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: device_id.map(RootDeviceId), - 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 = pointer_id.map(RootDeviceId); + let device_id = pointer_id.map(RootDeviceId); - // 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: device_id.map(RootDeviceId), - 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(); @@ -505,20 +379,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: device_id.map(RootDeviceId), - 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 41d26d9b6f..a627473396 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::RequestError; -use crate::event::{Force, MouseButton, MouseScrollDelta, SurfaceSizeWriter}; +use crate::event::{ + ButtonSource, ElementState, MouseScrollDelta, PointerKind, PointerSource, SurfaceSizeWriter, +}; use crate::keyboard::{Key, KeyLocation, ModifiersState, PhysicalKey}; use crate::platform_impl::Fullscreen; use crate::window::{WindowAttributes, WindowId as RootWindowId}; @@ -328,83 +330,62 @@ 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, Option, PhysicalPosition, PointerKind), { - 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, Option, PhysicalPosition, PointerKind), { - 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, Option, PhysicalPosition, MouseButton), - T: 'static - + FnMut(ModifiersState, Option, FingerId, PhysicalPosition, Force), + C: 'static + FnMut(ModifiersState, Option, 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, Option, PhysicalPosition, MouseButton), - T: 'static - + FnMut(ModifiersState, Option, FingerId, PhysicalPosition, Force), + C: 'static + FnMut(ModifiersState, Option, 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, Option, &mut dyn Iterator>), - T: 'static + C: 'static + FnMut( - ModifiersState, Option, - FingerId, - &mut dyn Iterator, Force)>, + &mut dyn Iterator, PointerSource)>, ), B: 'static + FnMut( ModifiersState, Option, PhysicalPosition, - ButtonsState, - MouseButton, + 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(Option, 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..cd4c8800d8 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, PointerKind}; 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) -> PointerKind { + match event.pointer_type().as_str() { + "mouse" => PointerKind::Mouse, + "touch" => PointerKind::Touch(FingerId::new(pointer_id, event.is_primary()).into()), + _ => PointerKind::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 11a37a3e7a..3ac58cb7c9 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, PointerKind, PointerSource}; use crate::keyboard::ModifiersState; #[allow(dead_code)] @@ -34,88 +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, Option, PhysicalPosition, PointerKind), { + 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 kind = event::pointer_type(&event, pointer_id); + handler(modifiers, device_id, position, kind); })); } - 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, Option, PhysicalPosition, PointerKind), { + 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 kind = event::pointer_type(&event, pointer_id); + handler(modifiers, device_id, position, kind); })); } - pub fn on_mouse_release( - &mut self, - canvas_common: &Common, - mut mouse_handler: M, - mut touch_handler: T, - ) where - M: 'static + FnMut(ModifiersState, Option, PhysicalPosition, MouseButton), - T: 'static - + FnMut(ModifiersState, Option, FingerId, PhysicalPosition, Force), + pub fn on_pointer_release(&mut self, canvas_common: &Common, mut handler: C) + where + C: 'static + FnMut(ModifiersState, Option, 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 kind = 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 kind { + PointerKind::Mouse => ButtonSource::Mouse(button), + PointerKind::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"), - ), - } + PointerKind::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, Option, PhysicalPosition, MouseButton), - T: 'static - + FnMut(ModifiersState, Option, FingerId, PhysicalPosition, Force), + C: 'static + FnMut(ModifiersState, Option, PhysicalPosition, ButtonSource), { let window = canvas_common.window.clone(); let canvas = canvas_common.raw().clone(); @@ -129,75 +118,65 @@ 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 kind = event::pointer_type(&event, pointer_id); + let button = event::mouse_button(&event).expect("no mouse button pressed"); + + let source = match kind { + PointerKind::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); - } + PointerKind::Touch(finger_id) => ButtonSource::Touch { + finger_id, + force: Some(Force::Normalized(event.pressure().into())), }, - } + PointerKind::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, Option, &mut dyn Iterator>), - T: 'static + C: 'static + FnMut( - ModifiersState, Option, - FingerId, - &mut dyn Iterator, Force)>, + &mut dyn Iterator, PointerSource)>, ), B: 'static + FnMut( ModifiersState, Option, PhysicalPosition, - ButtonsState, - MouseButton, + 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 kind = event::pointer_type(&event, pointer_id); // chorded button event if let Some(button) = event::mouse_button(&event) { @@ -208,11 +187,34 @@ impl PointerHandler { let _ = canvas.focus(); } + let state = if event::mouse_buttons(&event).contains(button.into()) { + ElementState::Pressed + } else { + ElementState::Released + }; + + let button = match kind { + PointerKind::Mouse => ButtonSource::Mouse(button), + PointerKind::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())), + } + }, + PointerKind::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, ); @@ -221,44 +223,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(Option, 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 kind { + PointerKind::Mouse => PointerSource::Mouse, + PointerKind::Touch(finger_id) => PointerSource::Touch { + finger_id, + force: Some(Force::Normalized(event.pressure().into())), + }, + PointerKind::Unknown => PointerSource::Unknown, + }, + ) + }), + ); })); } diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 0ed29a3be4..8c6e5391de 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, RequestError}; use crate::event::{ - Event, FingerId as RootFingerId, Force, Ime, RawKeyEvent, SurfaceSizeWriter, Touch, TouchPhase, + Event, FingerId as RootFingerId, Force, Ime, RawKeyEvent, SurfaceSizeWriter, TouchPhase, WindowEvent, }; use crate::event_loop::{ @@ -1520,7 +1520,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::{PointerKind, PointerSource}; let x = super::get_x_lparam(lparam as u32) as i32; let y = super::get_y_lparam(lparam as u32) as i32; @@ -1541,7 +1542,11 @@ unsafe fn public_window_callback_inner( drop(w); userdata.send_event(Event::WindowEvent { window_id: CoreWindowId(WindowId(window)), - event: CursorEntered { device_id: None }, + event: PointerEntered { + device_id: None, + position, + kind: PointerKind::Mouse, + }, }); // Calling TrackMouseEvent in order to receive mouse leave events. @@ -1562,7 +1567,11 @@ unsafe fn public_window_callback_inner( drop(w); userdata.send_event(Event::WindowEvent { window_id: CoreWindowId(WindowId(window)), - event: CursorLeft { device_id: None }, + event: PointerLeft { + device_id: None, + position: Some(position), + kind: PointerKind::Mouse, + }, }); }, PointerMoveKind::None => drop(w), @@ -1581,7 +1590,7 @@ unsafe fn public_window_callback_inner( userdata.send_event(Event::WindowEvent { window_id: CoreWindowId(WindowId(window)), - event: CursorMoved { device_id: None, position }, + event: PointerMoved { device_id: None, position, source: PointerSource::Mouse }, }); } @@ -1589,7 +1598,9 @@ unsafe fn public_window_callback_inner( }, WM_MOUSELEAVE => { - use crate::event::WindowEvent::CursorLeft; + use crate::event::PointerKind::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(); @@ -1597,7 +1608,7 @@ unsafe fn public_window_callback_inner( userdata.send_event(Event::WindowEvent { window_id: CoreWindowId(WindowId(window)), - event: CursorLeft { device_id: None }, + event: PointerLeft { device_id: None, position: None, kind: Mouse }, }); result = ProcResult::Value(0); @@ -1660,15 +1671,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: CoreWindowId(WindowId(window)), - event: MouseInput { device_id: None, state: Pressed, button: Left }, + event: PointerButton { + device_id: None, + state: Pressed, + position, + button: Left.into(), + }, }); result = ProcResult::Value(0); }, @@ -1676,15 +1696,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: CoreWindowId(WindowId(window)), - event: MouseInput { device_id: None, state: Released, button: Left }, + event: PointerButton { + device_id: None, + state: Released, + position, + button: Left.into(), + }, }); result = ProcResult::Value(0); }, @@ -1692,15 +1721,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: CoreWindowId(WindowId(window)), - event: MouseInput { device_id: None, state: Pressed, button: Right }, + event: PointerButton { + device_id: None, + state: Pressed, + position, + button: Right.into(), + }, }); result = ProcResult::Value(0); }, @@ -1708,15 +1746,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: CoreWindowId(WindowId(window)), - event: MouseInput { device_id: None, state: Released, button: Right }, + event: PointerButton { + device_id: None, + state: Released, + position, + button: Right.into(), + }, }); result = ProcResult::Value(0); }, @@ -1724,15 +1771,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: CoreWindowId(WindowId(window)), - event: MouseInput { device_id: None, state: Pressed, button: Middle }, + event: PointerButton { + device_id: None, + state: Pressed, + position, + button: Middle.into(), + }, }); result = ProcResult::Value(0); }, @@ -1740,15 +1796,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: CoreWindowId(WindowId(window)), - event: MouseInput { device_id: None, state: Released, button: Middle }, + event: PointerButton { + device_id: None, + state: Released, + position, + button: Middle.into(), + }, }); result = ProcResult::Value(0); }, @@ -1756,23 +1821,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: CoreWindowId(WindowId(window)), - event: MouseInput { + event: PointerButton { device_id: None, state: Pressed, + position, button: match xbutton { 1 => Back, 2 => Forward, _ => Other(xbutton), - }, + } + .into(), }, }); result = ProcResult::Value(0); @@ -1781,23 +1852,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: CoreWindowId(WindowId(window)), - event: MouseInput { + event: PointerButton { device_id: None, state: Released, + position, button: match xbutton { 1 => Back, 2 => Forward, _ => Other(xbutton), - }, + } + .into(), }, }); result = ProcResult::Value(0); @@ -1815,6 +1892,10 @@ unsafe fn public_window_callback_inner( }, WM_TOUCH => { + use crate::event::ButtonSource::Touch; + use crate::event::ElementState::{Pressed, Released}; + use crate::event::{PointerKind, PointerSource}; + let pcount = super::loword(wparam as u32) as usize; let mut inputs = Vec::with_capacity(pcount); let htouch = lparam; @@ -1828,36 +1909,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: CoreWindowId(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: None, - }), + 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 = CoreWindowId(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: None, + position, + kind: PointerKind::Touch(finger_id), + }, + }); + userdata.send_event(Event::WindowEvent { + window_id, + event: WindowEvent::PointerButton { + device_id: None, + 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: None, + state: Released, + position, + button: Touch { finger_id, force: None }, + }, + }); + userdata.send_event(Event::WindowEvent { + window_id, + event: WindowEvent::PointerLeft { + device_id: None, + position: Some(position), + kind: PointerKind::Touch(finger_id), + }, + }); + } else if util::has_flag(input.dwFlags, TOUCHEVENTF_MOVE) { + userdata.send_event(Event::WindowEvent { + window_id, + event: WindowEvent::PointerMoved { + device_id: None, + position, + source: PointerSource::Touch { finger_id, force: None }, + }, + }); + } else { + continue; + } } } unsafe { CloseTouchInputHandle(htouch) }; @@ -1865,6 +1980,9 @@ unsafe fn public_window_callback_inner( }, WM_POINTERDOWN | WM_POINTERUPDATE | WM_POINTERUP => { + use crate::event::ElementState::{Pressed, Released}; + use crate::event::{ButtonSource, PointerKind, PointerSource}; + if let ( Some(GetPointerFrameInfoHistory), Some(SkipPointerFrameMessages), @@ -1949,67 +2067,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: CoreWindowId(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: None, - }), + let position = PhysicalPosition::new(x, y); + + let window_id = CoreWindowId(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: None, + position, + kind: if let PT_TOUCH = pointer_info.pointerType { + PointerKind::Touch(finger_id) + } else { + PointerKind::Unknown + }, + }, + }); + userdata.send_event(Event::WindowEvent { + window_id, + event: WindowEvent::PointerButton { + device_id: None, + 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: None, + 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: None, + position: Some(position), + kind: if let PT_TOUCH = pointer_info.pointerType { + PointerKind::Touch(finger_id) + } else { + PointerKind::Unknown + }, + }, + }); + } else if util::has_flag(pointer_info.pointerFlags, POINTER_FLAG_UPDATE) { + userdata.send_event(Event::WindowEvent { + window_id, + event: WindowEvent::PointerMoved { + device_id: None, + position, + source: if let PT_TOUCH = pointer_info.pointerType { + PointerSource::Touch { finger_id, force } + } else { + PointerSource::Unknown + }, + }, + }); + } else { + continue; + } } unsafe { SkipPointerFrameMessages(pointer_id) }; @@ -2431,7 +2582,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; @@ -2447,7 +2598,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));