api: overhaul pointer API

- Rename `CursorMoved` to `PointerMoved`.
- Rename `CursorEntered` to `PointerEntered`.
- Rename `CursorLeft` to `PointerLeft`.
- Rename `MouseInput` to `PointerButton`.
- Add `position` to every `PointerEvent`.
- Remove `Touch`, which is folded into the `Pointer*` events.
- New `PointerType` added to `PointerEntered` and `PointerLeft`,
  signifying which pointer type is the source of this event.
- New `PointerSource` added to `PointerMoved`, similar to `PointerType`
  but holding additional data.
- New `ButtonSource` added to `PointerButton`, similar to `PointerType`
  but holding pointer type specific buttons. Use
  `ButtonSource::mouse_button()` to easily normalize any pointer button
  type to a generic mouse button.
- In the same spirit rename `DeviceEvent::MouseMotion` to `PointerMotion`.
- Remove `Force::Calibrated::altitude_angle`.

Fixes #3833.
Fixes #883.
Fixes #336.

Co-authored-by: Kirill Chibisov <contact@kchibisov.com>
This commit is contained in:
daxpedda 2024-10-08 14:19:00 +02:00 committed by GitHub
parent 32cd1ad9a7
commit eccd9e415d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 1236 additions and 869 deletions

View file

@ -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

View file

@ -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(_) => (),
}
}

View file

@ -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<DeviceId>` 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<u64> for WindowId` and `impl From<WindowId> 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

View file

@ -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<DeviceId>,
/// (x,y) coords in pixels relative to the top-left corner of the window. Because the range
/// of this data is limited by the display area and it may have been transformed by
/// the OS to implement effects such as cursor acceleration, it should not be used
/// to implement non-cursor-like interactions such as 3D camera control. 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<f64>,
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<DeviceId> },
/// The pointer has entered the window.
PointerEntered {
device_id: Option<DeviceId>,
/// The cursor has left the window.
/// 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
CursorLeft { device_id: Option<DeviceId> },
position: PhysicalPosition<f64>,
kind: PointerKind,
},
/// The pointer has left the window.
PointerLeft {
device_id: Option<DeviceId>,
/// 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<PhysicalPosition<f64>>,
kind: PointerKind,
},
/// A mouse wheel movement or touchpad scroll occurred.
MouseWheel { device_id: Option<DeviceId>, delta: MouseScrollDelta, phase: TouchPhase },
/// An mouse button press has been received.
MouseInput { device_id: Option<DeviceId>, state: ElementState, button: MouseButton },
PointerButton {
device_id: Option<DeviceId>,
state: ElementState,
/// The position of the pointer when the button was pressed.
///
/// ## Platform-specific
///
/// - **Orbital: Always emits `(0., 0.)`.
/// - **Web:** Doesn't take into account CSS [`border`], [`padding`], or [`transform`].
///
/// [`border`]: https://developer.mozilla.org/en-US/docs/Web/CSS/border
/// [`padding`]: https://developer.mozilla.org/en-US/docs/Web/CSS/padding
/// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform
position: PhysicalPosition<f64>,
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<DeviceId>, pressure: f32, stage: i64 },
/// Touch event has been received
///
/// ## Platform-specific
///
/// - **Web:** Doesn't take into account CSS [`border`], [`padding`], or [`transform`].
/// - **macOS:** Unsupported.
///
/// [`border`]: https://developer.mozilla.org/en-US/docs/Web/CSS/border
/// [`padding`]: https://developer.mozilla.org/en-US/docs/Web/CSS/padding
/// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform
Touch(Touch),
/// The window's scale factor has changed.
///
/// The following user actions can cause DPI changes:
@ -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<Force>,
},
Unknown,
}
impl From<PointerSource> 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<Force>,
},
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<MouseButton> 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<DeviceId>,
pub phase: TouchPhase,
pub location: PhysicalPosition<f64>,
/// 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<Force>,
/// 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<f64>,
},
/// 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();
}
}

View file

@ -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

View file

@ -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;

View file

@ -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 action = motion_event.action();
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
},
};
if let Some(phase) = phase {
let pointers: Box<dyn Iterator<Item = android_activity::input::Pointer<'_>>> =
match phase {
event::TouchPhase::Started | event::TouchPhase::Ended => {
Box::new(std::iter::once(
let pointers: Option<
Box<dyn Iterator<Item = android_activity::input::Pointer<'_>>>,
> = 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()),
))
},
event::TouchPhase::Moved | event::TouchPhase::Cancelled => {
Box::new(motion_event.pointers())
))),
MotionAction::Move | MotionAction::Cancel => {
Some(Box::new(motion_event.pointers()))
},
// TODO mouse events
_ => None,
};
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 finger_id = event::FingerId(FingerId(pointer.pointer_id()));
let force = Some(Force::Normalized(pointer.pressure() as f64));
let event = event::WindowEvent::Touch(event::Touch {
match action {
MotionAction::Down | MotionAction::PointerDown => {
let event = event::WindowEvent::PointerEntered {
device_id,
phase,
location,
finger_id: event::FingerId(FingerId(pointer.pointer_id())),
force: Some(Force::Normalized(pointer.pressure() as f64)),
});
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!(),
}
}
}
},

View file

@ -60,7 +60,7 @@ fn maybe_dispatch_device_event(app_state: &Rc<AppState>, 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),
});
});

View file

@ -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<f64> {
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.

View file

@ -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<f64> = 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,
)
};
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: RootWindowId(window.id()),
event: WindowEvent::Touch(Touch {
window_id,
event: WindowEvent::PointerEntered {
device_id: None,
finger_id: RootFingerId(FingerId(touch_id)),
location: physical_location,
force,
phase,
}),
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);

View file

@ -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,

View file

@ -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,
);
},

View file

@ -68,7 +68,7 @@ impl Dispatch<ZwpRelativePointerV1, GlobalData, WinitState> 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) });
}
}

View file

@ -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::<f64>::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::Touch(Touch {
WindowEvent::PointerButton {
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),
)),
}),
state: ElementState::Released,
position,
button: ButtonSource::Touch { finger_id, force: None },
},
window_id,
);
self.events_sink.push_window_event(
WindowEvent::PointerLeft {
device_id: None,
position: Some(position),
kind: PointerKind::Touch(finger_id),
},
window_id,
);
}
@ -131,15 +149,16 @@ impl TouchHandler for WinitState {
touch_point.location = LogicalPosition::<f64>::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,
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,
);
}

View file

@ -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<F>(&mut self, xev: &XIDeviceEvent, phase: TouchPhase, mut callback: F)
fn xinput2_touch<F>(&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 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::Touch(Touch {
device_id: Some(mkdid(xev.deviceid as xinput::DeviceId)),
phase,
location,
force: None, // TODO
finger_id: mkfid(id),
}),
event: WindowEvent::PointerEntered {
device_id,
position,
kind: PointerKind::Touch(finger_id),
},
};
callback(&self.target, event)
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<u32>, num: &mut u32, id: u32, phase: TouchPhase) -> bool {
fn is_first_touch(first: &mut Option<u32>, 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;
}

View file

@ -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);

View file

@ -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<Self> {
@ -34,3 +36,9 @@ impl FingerId {
self.primary
}
}
impl From<FingerId> for RootFingerId {
fn from(id: FingerId) -> Self {
Self(id)
}
}

View file

@ -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,
},
});

View file

@ -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,51 +238,29 @@ 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(|| {
let modifiers = (has_focus.get() && modifiers.get() != active_modifiers)
.then(|| {
modifiers.set(active_modifiers);
Event::WindowEvent {
window_id: RootWindowId(id),
@ -291,18 +268,11 @@ impl ActiveEventLoop {
}
});
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<f64>,
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,31 +292,15 @@ 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 {
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 },
},
]));
event: WindowEvent::PointerButton { device_id, state, position, button },
}]));
}
},
);
canvas.on_mouse_press(
{
canvas.on_pointer_press({
let runner = self.runner.clone();
let modifiers = self.modifiers.clone();
@ -364,57 +314,19 @@ impl ActiveEventLoop {
});
let device_id = pointer_id.map(RootDeviceId);
// 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 {
runner.send_events(modifiers.into_iter().chain(iter::once(Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::CursorMoved { device_id, position },
},
Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::MouseInput {
event: WindowEvent::PointerButton {
device_id,
state: ElementState::Pressed,
position,
button,
},
},
]));
}
},
{
let runner = self.runner.clone();
let modifiers = self.modifiers.clone();
move |active_modifiers, device_id, finger_id, location, force| {
let modifiers = (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(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(
{
canvas.on_pointer_release({
let runner = self.runner.clone();
let has_focus = has_focus.clone();
let modifiers = self.modifiers.clone();
@ -431,56 +343,18 @@ impl ActiveEventLoop {
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 {
runner.send_events(modifiers.into_iter().chain(iter::once(Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::CursorMoved { device_id, position },
},
Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::MouseInput {
event: WindowEvent::PointerButton {
device_id,
state: ElementState::Released,
position,
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,
}),
},
)));
}
},
);
let runner = self.runner.clone();
let modifiers = self.modifiers.clone();
canvas.on_mouse_wheel(move |delta, active_modifiers| {
@ -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 };

View file

@ -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<F>(&self, handler: F)
pub fn on_pointer_leave<F>(&self, handler: F)
where
F: 'static + FnMut(ModifiersState, Option<Option<DeviceId>>),
F: 'static + FnMut(ModifiersState, Option<DeviceId>, PhysicalPosition<f64>, 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<F>(&self, handler: F)
pub fn on_pointer_enter<F>(&self, handler: F)
where
F: 'static + FnMut(ModifiersState, Option<Option<DeviceId>>),
F: 'static + FnMut(ModifiersState, Option<DeviceId>, PhysicalPosition<f64>, 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<M, T>(&self, mouse_handler: M, touch_handler: T)
pub fn on_pointer_release<C>(&self, handler: C)
where
M: 'static + FnMut(ModifiersState, Option<DeviceId>, PhysicalPosition<f64>, MouseButton),
T: 'static
+ FnMut(ModifiersState, Option<DeviceId>, FingerId, PhysicalPosition<f64>, Force),
C: 'static + FnMut(ModifiersState, Option<DeviceId>, PhysicalPosition<f64>, ButtonSource),
{
self.handlers.borrow_mut().pointer_handler.on_mouse_release(
self.handlers.borrow_mut().pointer_handler.on_pointer_release(&self.common, handler)
}
pub fn on_pointer_press<C>(&self, handler: C)
where
C: 'static + FnMut(ModifiersState, Option<DeviceId>, PhysicalPosition<f64>, ButtonSource),
{
self.handlers.borrow_mut().pointer_handler.on_pointer_press(
&self.common,
mouse_handler,
touch_handler,
)
}
pub fn on_mouse_press<M, T>(&self, mouse_handler: M, touch_handler: T)
where
M: 'static + FnMut(ModifiersState, Option<DeviceId>, PhysicalPosition<f64>, MouseButton),
T: 'static
+ FnMut(ModifiersState, Option<DeviceId>, FingerId, PhysicalPosition<f64>, Force),
{
self.handlers.borrow_mut().pointer_handler.on_mouse_press(
&self.common,
mouse_handler,
touch_handler,
handler,
Rc::clone(&self.prevent_default),
)
}
pub fn on_cursor_move<M, T, B>(&self, mouse_handler: M, touch_handler: T, button_handler: B)
pub fn on_pointer_move<C, B>(&self, cursor_handler: C, button_handler: B)
where
M: 'static
+ FnMut(ModifiersState, Option<DeviceId>, &mut dyn Iterator<Item = PhysicalPosition<f64>>),
T: 'static
C: 'static
+ FnMut(
ModifiersState,
Option<DeviceId>,
FingerId,
&mut dyn Iterator<Item = (PhysicalPosition<f64>, Force)>,
&mut dyn Iterator<Item = (ModifiersState, PhysicalPosition<f64>, PointerSource)>,
),
B: 'static
+ FnMut(
ModifiersState,
Option<DeviceId>,
PhysicalPosition<f64>,
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<F>(&self, handler: F)
where
F: 'static + FnMut(Option<DeviceId>, FingerId, PhysicalPosition<f64>, Force),
{
self.handlers.borrow_mut().pointer_handler.on_touch_cancel(&self.common, handler)
}
pub fn on_mouse_wheel<F>(&self, mut handler: F)
where
F: 'static + FnMut(MouseScrollDelta, ModifiersState),

View file

@ -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<MouseButton> {
}
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)

View file

@ -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;

View file

@ -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<F>(&mut self, canvas_common: &Common, mut handler: F)
pub fn on_pointer_leave<F>(&mut self, canvas_common: &Common, mut handler: F)
where
F: 'static + FnMut(ModifiersState, Option<Option<DeviceId>>),
F: 'static + FnMut(ModifiersState, Option<DeviceId>, PhysicalPosition<f64>, 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<F>(&mut self, canvas_common: &Common, mut handler: F)
pub fn on_pointer_enter<F>(&mut self, canvas_common: &Common, mut handler: F)
where
F: 'static + FnMut(ModifiersState, Option<Option<DeviceId>>),
F: 'static + FnMut(ModifiersState, Option<DeviceId>, PhysicalPosition<f64>, 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<M, T>(
&mut self,
canvas_common: &Common,
mut mouse_handler: M,
mut touch_handler: T,
) where
M: 'static + FnMut(ModifiersState, Option<DeviceId>, PhysicalPosition<f64>, MouseButton),
T: 'static
+ FnMut(ModifiersState, Option<DeviceId>, FingerId, PhysicalPosition<f64>, Force),
pub fn on_pointer_release<C>(&mut self, canvas_common: &Common, mut handler: C)
where
C: 'static + FnMut(ModifiersState, Option<DeviceId>, PhysicalPosition<f64>, 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);
match event.pointer_type().as_str() {
"touch" => {
let pointer_id = event.pointer_id();
touch_handler(
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 => ButtonSource::Mouse(button),
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),
FingerId::new(pointer_id, event.is_primary()),
event::mouse_position(&event).to_physical(super::scale_factor(&window)),
Force::Normalized(event.pressure() as f64),
source,
)
},
_ => 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"),
),
}
}));
}
pub fn on_mouse_press<M, T>(
pub fn on_pointer_press<C>(
&mut self,
canvas_common: &Common,
mut mouse_handler: M,
mut touch_handler: T,
mut handler: C,
prevent_default: Rc<Cell<bool>>,
) where
M: 'static + FnMut(ModifiersState, Option<DeviceId>, PhysicalPosition<f64>, MouseButton),
T: 'static
+ FnMut(ModifiersState, Option<DeviceId>, FingerId, PhysicalPosition<f64>, Force),
C: 'static + FnMut(ModifiersState, Option<DeviceId>, PhysicalPosition<f64>, 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");
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" {
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)
},
}
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<M, T, B>(
pub fn on_pointer_move<C, B>(
&mut self,
canvas_common: &Common,
mut mouse_handler: M,
mut touch_handler: T,
mut cursor_handler: C,
mut button_handler: B,
prevent_default: Rc<Cell<bool>>,
) where
M: 'static
+ FnMut(ModifiersState, Option<DeviceId>, &mut dyn Iterator<Item = PhysicalPosition<f64>>),
T: 'static
C: 'static
+ FnMut(
ModifiersState,
Option<DeviceId>,
FingerId,
&mut dyn Iterator<Item = (PhysicalPosition<f64>, Force)>,
&mut dyn Iterator<Item = (ModifiersState, PhysicalPosition<f64>, PointerSource)>,
),
B: 'static
+ FnMut(
ModifiersState,
Option<DeviceId>,
PhysicalPosition<f64>,
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,
cursor_handler(
device_id,
FingerId::new(pointer_id, event.is_primary()),
&mut event::pointer_move_event(event).map(|event| {
(
event::mouse_modifiers(&event),
event::mouse_position(&event).to_physical(scale),
Force::Normalized(event.pressure() as f64),
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,
},
)
}),
),
_ => 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<F>(&mut self, canvas_common: &Common, mut handler: F)
where
F: 'static + FnMut(Option<DeviceId>, FingerId, PhysicalPosition<f64>, 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),
);
}
}));
}

View file

@ -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 {
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),
}),
device_id: None,
}),
});
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,15 +2067,11 @@ unsafe fn public_window_callback_inner(
continue;
}
let force = match pointer_info.pointerType {
PT_TOUCH => {
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(),
)
GetPointerTouchInfo(pointer_info.pointerId, touch_info.as_mut_ptr())
} {
0 => None,
_ => normalize_pointer_pressure(unsafe {
@ -1965,51 +2079,88 @@ unsafe fn public_window_callback_inner(
}),
}
})
},
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,
} else {
None
};
let x = location.x as f64 + x.fract();
let y = location.y as f64 + y.fract();
let location = PhysicalPosition::new(x, y);
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: CoreWindowId(WindowId(window)),
event: WindowEvent::Touch(Touch {
phase: if util::has_flag(pointer_info.pointerFlags, POINTER_FLAG_DOWN) {
TouchPhase::Started
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) {
TouchPhase::Ended
} else if util::has_flag(pointer_info.pointerFlags, POINTER_FLAG_UPDATE)
{
TouchPhase::Moved
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;
},
location,
force,
finger_id: RootFingerId(FingerId {
id: pointer_info.pointerId,
primary: util::has_flag(
pointer_info.pointerFlags,
POINTER_FLAG_PRIMARY,
),
}),
device_id: None,
}),
});
}
}
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) },
});
}
}

View file

@ -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<Option<GetDpiForWindow>> =
Lazy::new(|| get_function!("user32.dll", GetDpiForWindow));
pub(crate) static ADJUST_WINDOW_RECT_EX_FOR_DPI: Lazy<Option<AdjustWindowRectExForDpi>> =
@ -269,5 +266,3 @@ pub(crate) static GET_POINTER_DEVICE_RECTS: Lazy<Option<GetPointerDeviceRects>>
Lazy::new(|| get_function!("user32.dll", GetPointerDeviceRects));
pub(crate) static GET_POINTER_TOUCH_INFO: Lazy<Option<GetPointerTouchInfo>> =
Lazy::new(|| get_function!("user32.dll", GetPointerTouchInfo));
pub(crate) static GET_POINTER_PEN_INFO: Lazy<Option<GetPointerPenInfo>> =
Lazy::new(|| get_function!("user32.dll", GetPointerPenInfo));