Skip to content

Commit

Permalink
Introduce FingerId (#3783)
Browse files Browse the repository at this point in the history
  • Loading branch information
daxpedda authored Aug 7, 2024
1 parent f07153b commit 9dff801
Show file tree
Hide file tree
Showing 24 changed files with 329 additions and 113 deletions.
4 changes: 4 additions & 0 deletions src/changelog/unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ changelog entry.
well.
- On Android, add `{Active,}EventLoopExtAndroid::android_app()` to access the app used to create the loop.
- Add `ActiveEventLoop::system_theme()`, returning the current system theme.
- 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.

### Changed

Expand Down Expand Up @@ -110,6 +113,7 @@ 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`.

### Fixed

Expand Down
28 changes: 25 additions & 3 deletions src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,26 @@ impl DeviceId {
}
}

/// Identifier of a finger in a touch event.
///
/// Whenever a touch event is received it contains a `FingerId` which uniquely identifies the finger
/// used for the current interaction.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FingerId(pub(crate) platform_impl::FingerId);

impl FingerId {
/// Returns a dummy id, useful for unit testing.
///
/// # Notes
///
/// The only guarantee made about the return value of this function is that
/// it will always be equal to itself and to future values returned by this function.
/// No other guarantees are made. This may be equal to a real `FingerId`.
pub const fn dummy() -> Self {
FingerId(platform_impl::FingerId::dummy())
}
}

/// Represents raw hardware events that are not associated with any particular window.
///
/// Useful for interactions that diverge significantly from a conventional 2D GUI, such as 3D camera
Expand Down Expand Up @@ -846,7 +866,7 @@ pub struct Touch {
/// [android documentation](https://developer.android.com/reference/android/view/MotionEvent#AXIS_PRESSURE).
pub force: Option<Force>,
/// Unique identifier of a finger.
pub id: u64,
pub finger_id: FingerId,
}

/// Describes the force of a touch event
Expand Down Expand Up @@ -1012,6 +1032,7 @@ mod tests {
#[allow(unused_mut)]
let mut x = $closure;
let did = event::DeviceId::dummy();
let fid = event::FingerId::dummy();

#[allow(deprecated)]
{
Expand Down Expand Up @@ -1075,7 +1096,7 @@ mod tests {
device_id: did,
phase: event::TouchPhase::Started,
location: (0.0, 0.0).into(),
id: 0,
finger_id: fid,
force: Some(event::Force::Normalized(0.0)),
}));
with_window_event(ThemeChanged(crate::window::Theme::Light));
Expand Down Expand Up @@ -1133,6 +1154,7 @@ mod tests {
let _ = event::StartCause::Init.clone();

let did = crate::event::DeviceId::dummy().clone();
let fid = crate::event::FingerId::dummy().clone();
HashSet::new().insert(did);
let mut set = [did, did, did];
set.sort_unstable();
Expand All @@ -1148,7 +1170,7 @@ mod tests {
device_id: did,
phase: event::TouchPhase::Started,
location: (0.0, 0.0).into(),
id: 0,
finger_id: fid,
force: Some(event::Force::Normalized(0.0)),
}
.clone();
Expand Down
14 changes: 14 additions & 0 deletions src/platform/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ use web_sys::HtmlCanvasElement;
use crate::application::ApplicationHandler;
use crate::cursor::CustomCursorSource;
use crate::error::NotSupportedError;
use crate::event::FingerId;
use crate::event_loop::{ActiveEventLoop, EventLoop};
use crate::monitor::MonitorHandle;
use crate::platform_impl::PlatformCustomCursorSource;
Expand Down Expand Up @@ -763,3 +764,16 @@ impl Display for OrientationLockError {
}

impl Error for OrientationLockError {}

/// Additional methods on [`FingerId`] that are specific to Web.
pub trait FingerIdExtWeb {
/// Indicates if the finger represents the first contact in a multi-touch interaction.
#[allow(clippy::wrong_self_convention)]
fn is_primary(self) -> bool;
}

impl FingerIdExtWeb for FingerId {
fn is_primary(self) -> bool {
self.0.is_primary()
}
}
16 changes: 15 additions & 1 deletion src/platform/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::ffi::c_void;
use std::path::Path;

use crate::dpi::PhysicalSize;
use crate::event::DeviceId;
use crate::event::{DeviceId, FingerId};
use crate::event_loop::EventLoopBuilder;
use crate::monitor::MonitorHandle;
use crate::window::{BadIcon, Icon, Window, WindowAttributes};
Expand Down Expand Up @@ -668,6 +668,20 @@ impl DeviceIdExtWindows for DeviceId {
}
}

/// Additional methods on `FingerId` that are specific to Windows.
pub trait FingerIdExtWindows {
/// Indicates if the finger represents the first contact in a multi-touch interaction.
#[allow(clippy::wrong_self_convention)]
fn is_primary(self) -> bool;
}

impl FingerIdExtWindows for FingerId {
#[inline]
fn is_primary(self) -> bool {
self.0.is_primary()
}
}

/// Additional methods on `Icon` that are specific to Windows.
pub trait IconExtWindows: Sized {
/// Create an icon from a file path.
Expand Down
11 changes: 10 additions & 1 deletion src/platform_impl/android/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ impl EventLoop {
device_id,
phase,
location,
id: pointer.pointer_id() as u64,
finger_id: event::FingerId(FingerId(pointer.pointer_id())),
force: Some(Force::Normalized(pointer.pressure() as f64)),
});

Expand Down Expand Up @@ -705,6 +705,15 @@ impl DeviceId {
}
}

#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct FingerId(i32);

impl FingerId {
pub const fn dummy() -> Self {
FingerId(0)
}
}

#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct PlatformSpecificWindowAttributes;

Expand Down
9 changes: 9 additions & 0 deletions src/platform_impl/apple/appkit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ impl DeviceId {
// Constant device ID; to be removed when if backend is updated to report real device IDs.
pub(crate) const DEVICE_ID: RootDeviceId = RootDeviceId(DeviceId);

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FingerId;

impl FingerId {
pub const fn dummy() -> Self {
FingerId
}
}

#[derive(Debug)]
pub enum OsError {
CGError(core_graphics::base::CGError),
Expand Down
9 changes: 9 additions & 0 deletions src/platform_impl/apple/uikit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ impl DeviceId {

pub(crate) const DEVICE_ID: RootDeviceId = RootDeviceId(DeviceId);

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FingerId(usize);

impl FingerId {
pub const fn dummy() -> Self {
FingerId(0)
}
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct KeyEventExtra {}

Expand Down
8 changes: 4 additions & 4 deletions src/platform_impl/apple/uikit/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ use objc2_ui_kit::{

use super::app_state::{self, EventWrapper};
use super::window::WinitUIWindow;
use super::DEVICE_ID;
use super::{FingerId, DEVICE_ID};
use crate::dpi::PhysicalPosition;
use crate::event::{Event, Force, Touch, TouchPhase, WindowEvent};
use crate::event::{Event, FingerId as RootFingerId, Force, Touch, TouchPhase, WindowEvent};
use crate::window::{WindowAttributes, WindowId as RootWindowId};

pub struct WinitViewState {
Expand Down Expand Up @@ -480,7 +480,7 @@ impl WinitView {
} else {
None
};
let touch_id = touch as *const UITouch as u64;
let touch_id = touch as *const UITouch as usize;
let phase = touch.phase();
let phase = match phase {
UITouchPhase::Began => TouchPhase::Started,
Expand All @@ -502,7 +502,7 @@ impl WinitView {
window_id: RootWindowId(window.id()),
event: WindowEvent::Touch(Touch {
device_id: DEVICE_ID,
id: touch_id,
finger_id: RootFingerId(FingerId(touch_id)),
location: physical_location,
force,
phase,
Expand Down
17 changes: 17 additions & 0 deletions src/platform_impl/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,23 @@ impl DeviceId {
}
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum FingerId {
#[cfg(x11_platform)]
X(x11::FingerId),
#[cfg(wayland_platform)]
Wayland(wayland::FingerId),
}

impl FingerId {
pub const fn dummy() -> Self {
#[cfg(wayland_platform)]
return FingerId::Wayland(wayland::FingerId::dummy());
#[cfg(all(not(wayland_platform), x11_platform))]
return FingerId::X(x11::FingerId::dummy());
}
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum MonitorHandle {
#[cfg(x11_platform)]
Expand Down
9 changes: 9 additions & 0 deletions src/platform_impl/linux/wayland/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,15 @@ impl DeviceId {
}
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FingerId(i32);

impl FingerId {
pub const fn dummy() -> Self {
FingerId(0)
}
}

/// Get the WindowId out of the surface.
#[inline]
fn make_wid(surface: &WlSurface) -> WindowId {
Expand Down
18 changes: 13 additions & 5 deletions src/platform_impl/linux/wayland/seat/touch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use tracing::warn;
use crate::dpi::LogicalPosition;
use crate::event::{Touch, TouchPhase, WindowEvent};
use crate::platform_impl::wayland::state::WinitState;
use crate::platform_impl::wayland::{self, DeviceId};
use crate::platform_impl::wayland::{self, DeviceId, FingerId};

impl TouchHandler for WinitState {
fn down(
Expand Down Expand Up @@ -50,7 +50,9 @@ impl TouchHandler for WinitState {
phase: TouchPhase::Started,
location: location.to_physical(scale_factor),
force: None,
id: id as u64,
finger_id: crate::event::FingerId(crate::platform_impl::FingerId::Wayland(
FingerId(id),
)),
}),
window_id,
);
Expand Down Expand Up @@ -93,7 +95,9 @@ impl TouchHandler for WinitState {
phase: TouchPhase::Ended,
location: touch_point.location.to_physical(scale_factor),
force: None,
id: id as u64,
finger_id: crate::event::FingerId(crate::platform_impl::FingerId::Wayland(
FingerId(id),
)),
}),
window_id,
);
Expand Down Expand Up @@ -138,7 +142,9 @@ impl TouchHandler for WinitState {
phase: TouchPhase::Moved,
location: touch_point.location.to_physical(scale_factor),
force: None,
id: id as u64,
finger_id: crate::event::FingerId(crate::platform_impl::FingerId::Wayland(
FingerId(id),
)),
}),
window_id,
);
Expand Down Expand Up @@ -170,7 +176,9 @@ impl TouchHandler for WinitState {
phase: TouchPhase::Cancelled,
location,
force: None,
id: id as u64,
finger_id: crate::event::FingerId(crate::platform_impl::FingerId::Wayland(
FingerId(id),
)),
}),
window_id,
);
Expand Down
12 changes: 6 additions & 6 deletions src/platform_impl/linux/x11/event_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ use crate::platform_impl::platform::x11::ActiveEventLoop;
use crate::platform_impl::x11::atoms::*;
use crate::platform_impl::x11::util::cookie::GenericEventCookie;
use crate::platform_impl::x11::{
mkdid, mkwid, util, CookieResultExt, Device, DeviceId, DeviceInfo, Dnd, DndState, ImeReceiver,
ScrollOrientation, UnownedWindow, WindowId,
mkdid, mkfid, mkwid, util, CookieResultExt, Device, DeviceId, DeviceInfo, Dnd, DndState,
ImeReceiver, ScrollOrientation, UnownedWindow, WindowId,
};

/// The maximum amount of X modifiers to replay.
Expand All @@ -60,7 +60,7 @@ pub struct EventProcessor {
//
// Used to detect key repeats.
pub held_key_press: Option<u32>,
pub first_touch: Option<u64>,
pub first_touch: Option<u32>,
// Currently focused window belonging to this process
pub active_window: Option<xproto::Window>,
/// Latest modifiers we've sent for the user to trigger change in event.
Expand Down Expand Up @@ -1313,7 +1313,7 @@ impl EventProcessor {
let window = xev.event as xproto::Window;
if self.window_exists(window) {
let window_id = mkwid(window);
let id = xev.detail as u64;
let id = xev.detail as u32;
let location = PhysicalPosition::new(xev.event_x, xev.event_y);

// Mouse cursor position changes when touch events are received.
Expand All @@ -1336,7 +1336,7 @@ impl EventProcessor {
phase,
location,
force: None, // TODO
id,
finger_id: mkfid(id),
}),
};
callback(&self.target, event)
Expand Down Expand Up @@ -1761,7 +1761,7 @@ impl EventProcessor {
}
}

fn is_first_touch(first: &mut Option<u64>, num: &mut u32, id: u64, phase: TouchPhase) -> bool {
fn is_first_touch(first: &mut Option<u32>, num: &mut u32, id: u32, phase: TouchPhase) -> bool {
match phase {
TouchPhase::Started => {
if *num == 0 {
Expand Down
14 changes: 14 additions & 0 deletions src/platform_impl/linux/x11/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,16 @@ impl DeviceId {
}
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FingerId(u32);

impl FingerId {
#[allow(unused)]
pub const fn dummy() -> Self {
FingerId(0)
}
}

pub(crate) struct Window(Arc<UnownedWindow>);

impl Deref for Window {
Expand Down Expand Up @@ -1027,6 +1037,10 @@ fn mkdid(w: xinput::DeviceId) -> crate::event::DeviceId {
crate::event::DeviceId(crate::platform_impl::DeviceId::X(DeviceId(w)))
}

fn mkfid(w: u32) -> crate::event::FingerId {
crate::event::FingerId(crate::platform_impl::FingerId::X(FingerId(w)))
}

#[derive(Debug)]
pub struct Device {
_name: String,
Expand Down
Loading

0 comments on commit 9dff801

Please sign in to comment.