From c8c1eca3c7f12d5200fb8066a0a027b18e0cc74c Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Fri, 11 Oct 2024 20:08:51 +0300 Subject: [PATCH] api: move primary from FingerId to Pointer events Whether the pointer event is primary or not generally matters for the context where all input is done by the same event, so users can _ignore_ non-primary events since they are likely from users clicking something else with their other fingers. Having it only on a FingerId made it useless, since it's usually used to avoid multi-touch, but if you start mapping on touch event you already can track things like that yourself. Fixes #3943. Co-authored-by: daxpedda --- src/changelog/unreleased.md | 8 +- src/event.rs | 29 +++ src/platform/web.rs | 14 -- src/platform/windows.rs | 16 +- src/platform_impl/android/mod.rs | 170 ++++++++++-------- src/platform_impl/apple/appkit/view.rs | 4 + src/platform_impl/apple/uikit/view.rs | 57 +++++- src/platform_impl/linux/wayland/seat/mod.rs | 3 + .../linux/wayland/seat/pointer/mod.rs | 4 + .../linux/wayland/seat/touch/mod.rs | 18 ++ .../linux/x11/event_processor.rs | 26 ++- src/platform_impl/orbital/event_loop.rs | 4 + src/platform_impl/web/event.rs | 11 +- .../web/event_loop/window_target.rs | 69 ++++--- src/platform_impl/web/web_sys/canvas.rs | 17 +- src/platform_impl/web/web_sys/event.rs | 2 +- src/platform_impl/web/web_sys/pointer.rs | 26 ++- src/platform_impl/windows/event_loop.rs | 41 +++-- src/platform_impl/windows/mod.rs | 9 +- 19 files changed, 349 insertions(+), 179 deletions(-) diff --git a/src/changelog/unreleased.md b/src/changelog/unreleased.md index 6216b71b4d..d70a7ab7d9 100644 --- a/src/changelog/unreleased.md +++ b/src/changelog/unreleased.md @@ -67,8 +67,8 @@ changelog entry. - On macOS, add `WindowExtMacOS::set_unified_titlebar` and `WindowAttributesExtMacOS::with_unified_titlebar` to use a larger style of titlebar. - 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. +- Add `PointerKind`, `PointerSource`, `ButtonSource`, `FingerId`, `primary` and `position` to all + pointer events as part of the pointer event overhaul. - Add `DeviceId::into_raw()` and `from_raw()`. ### Changed @@ -138,6 +138,8 @@ changelog entry. - Rename `CursorEntered` to `PointerEntered`. - Rename `CursorLeft` to `PointerLeft`. - Rename `MouseInput` to `PointerButton`. + - Add `primary` to every `PointerEvent` as a way to identify discard non-primary pointers in a + multi-touch interaction. - Add `position` to every `PointerEvent`. - `PointerMoved` is **not sent** after `PointerEntered` anymore. - Remove `Touch`, which is folded into the `Pointer*` events. @@ -150,8 +152,6 @@ changelog entry. 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`. diff --git a/src/event.rs b/src/event.rs index edb3ea7161..2420f6f85c 100644 --- a/src/event.rs +++ b/src/event.rs @@ -245,6 +245,12 @@ pub enum WindowEvent { /// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform position: PhysicalPosition, + /// Indicates whether the event is created by a primary pointer. + /// + /// A pointer is considered primary when it's a mouse, the first finger in a multi-touch + /// interaction, or an unknown pointer source. + primary: bool, + source: PointerSource, }, @@ -264,6 +270,12 @@ pub enum WindowEvent { /// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform position: PhysicalPosition, + /// Indicates whether the event is created by a primary pointer. + /// + /// A pointer is considered primary when it's a mouse, the first finger in a multi-touch + /// interaction, or an unknown pointer source. + primary: bool, + kind: PointerKind, }, @@ -284,6 +296,12 @@ pub enum WindowEvent { /// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform position: Option>, + /// Indicates whether the event is created by a primary pointer. + /// + /// A pointer is considered primary when it's a mouse, the first finger in a multi-touch + /// interaction, or an unknown pointer source. + primary: bool, + kind: PointerKind, }, @@ -307,6 +325,12 @@ pub enum WindowEvent { /// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform position: PhysicalPosition, + /// Indicates whether the event is created by a primary pointer. + /// + /// A pointer is considered primary when it's a mouse, the first finger in a multi-touch + /// interaction, or an unknown pointer source. + primary: bool, + button: ButtonSource, }, @@ -1162,16 +1186,19 @@ mod tests { with_window_event(Ime(Enabled)); with_window_event(PointerMoved { device_id: None, + primary: true, position: (0, 0).into(), source: PointerSource::Mouse, }); with_window_event(ModifiersChanged(event::Modifiers::default())); with_window_event(PointerEntered { device_id: None, + primary: true, position: (0, 0).into(), kind: PointerKind::Mouse, }); with_window_event(PointerLeft { + primary: true, device_id: None, position: Some((0, 0).into()), kind: PointerKind::Mouse, @@ -1183,12 +1210,14 @@ mod tests { }); with_window_event(PointerButton { device_id: None, + primary: true, state: event::ElementState::Pressed, position: (0, 0).into(), button: event::MouseButton::Other(0).into(), }); with_window_event(PointerButton { device_id: None, + primary: true, state: event::ElementState::Released, position: (0, 0).into(), button: event::ButtonSource::Touch { diff --git a/src/platform/web.rs b/src/platform/web.rs index a64a890442..28227662d8 100644 --- a/src/platform/web.rs +++ b/src/platform/web.rs @@ -57,7 +57,6 @@ 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; @@ -780,16 +779,3 @@ 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() - } -} diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 74982f9765..fcd0289bc5 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -13,7 +13,7 @@ use serde::{Deserialize, Serialize}; use windows_sys::Win32::Foundation::HANDLE; use crate::dpi::PhysicalSize; -use crate::event::{DeviceId, FingerId}; +use crate::event::DeviceId; use crate::event_loop::EventLoopBuilder; use crate::monitor::MonitorHandle; use crate::window::{BadIcon, Icon, Window, WindowAttributes}; @@ -670,20 +670,6 @@ 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. diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index 912e61e54a..c784e7d839 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -107,6 +107,7 @@ pub struct EventLoop { running: bool, pending_redraw: bool, cause: StartCause, + primary_pointer: FingerId, ignore_volume_keys: bool, combining_accent: Option, } @@ -140,6 +141,7 @@ impl EventLoop { Ok(Self { android_app: android_app.clone(), + primary_pointer: FingerId::dummy(), window_target: ActiveEventLoop { app: android_app.clone(), control_flow: Cell::new(ControlFlow::default()), @@ -333,36 +335,83 @@ impl EventLoop { _ => None, }; - if let Some(pointers) = pointers { - for pointer in pointers { - let tool_type = pointer.tool_type(); - let position = - PhysicalPosition { x: pointer.x() as _, y: pointer.y() as _ }; - trace!( - "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)); - - match action { - MotionAction::Down | MotionAction::PointerDown => { - let event = event::WindowEvent::PointerEntered { - device_id, - position, - kind: match tool_type { - android_activity::input::ToolType::Finger => { - event::PointerKind::Touch(finger_id) - }, - // TODO mouse events - android_activity::input::ToolType::Mouse => continue, - _ => event::PointerKind::Unknown, + for pointer in pointers.into_iter().flatten() { + let tool_type = pointer.tool_type(); + let position = PhysicalPosition { x: pointer.x() as _, y: pointer.y() as _ }; + trace!( + "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)); + + match action { + MotionAction::Down | MotionAction::PointerDown => { + let primary = action == MotionAction::Down; + if primary { + self.primary_pointer = finger_id.0; + } + let event = event::WindowEvent::PointerEntered { + device_id, + primary, + position, + kind: match tool_type { + android_activity::input::ToolType::Finger => { + event::PointerKind::Touch(finger_id) }, - }; - app.window_event(&self.window_target, GLOBAL_WINDOW, event); + // TODO mouse events + android_activity::input::ToolType::Mouse => continue, + _ => event::PointerKind::Unknown, + }, + }; + app.window_event(&self.window_target, GLOBAL_WINDOW, event); + let event = event::WindowEvent::PointerButton { + device_id, + primary, + 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, GLOBAL_WINDOW, event); + }, + MotionAction::Move => { + let primary = self.primary_pointer == finger_id.0; + let event = event::WindowEvent::PointerMoved { + device_id, + primary, + 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, GLOBAL_WINDOW, event); + }, + MotionAction::Up | MotionAction::PointerUp | MotionAction::Cancel => { + let primary = action == MotionAction::Up + || (action == MotionAction::Cancel + && self.primary_pointer == finger_id.0); + + if primary { + self.primary_pointer = FingerId::dummy(); + } + + if let MotionAction::Up | MotionAction::PointerUp = action { let event = event::WindowEvent::PointerButton { device_id, - state: event::ElementState::Pressed, + primary, + state: event::ElementState::Released, position, button: match tool_type { android_activity::input::ToolType::Finger => { @@ -374,56 +423,24 @@ impl EventLoop { }, }; app.window_event(&self.window_target, GLOBAL_WINDOW, 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, GLOBAL_WINDOW, 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, GLOBAL_WINDOW, 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, + } + + let event = event::WindowEvent::PointerLeft { + device_id, + primary, + position: Some(position), + kind: match tool_type { + android_activity::input::ToolType::Finger => { + event::PointerKind::Touch(finger_id) }, - }; - app.window_event(&self.window_target, GLOBAL_WINDOW, event); - }, - _ => unreachable!(), - } + // TODO mouse events + android_activity::input::ToolType::Mouse => continue, + _ => event::PointerKind::Unknown, + }, + }; + app.window_event(&self.window_target, GLOBAL_WINDOW, event); + }, + _ => unreachable!(), } } }, @@ -732,7 +749,6 @@ impl OwnedDisplayHandle { pub struct FingerId(i32); impl FingerId { - #[cfg(test)] pub const fn dummy() -> Self { FingerId(0) } diff --git a/src/platform_impl/apple/appkit/view.rs b/src/platform_impl/apple/appkit/view.rs index e466856cd5..4e97d9867e 100644 --- a/src/platform_impl/apple/appkit/view.rs +++ b/src/platform_impl/apple/appkit/view.rs @@ -657,6 +657,7 @@ declare_class!( self.queue_event(WindowEvent::PointerEntered { device_id: None, + primary: true, position, kind: PointerKind::Mouse, }); @@ -670,6 +671,7 @@ declare_class!( self.queue_event(WindowEvent::PointerLeft { device_id: None, + primary: true, position: Some(position), kind: PointerKind::Mouse, }); @@ -1061,6 +1063,7 @@ impl WinitView { self.queue_event(WindowEvent::PointerButton { device_id: None, + primary: true, state: button_state, position, button: button.into(), @@ -1087,6 +1090,7 @@ impl WinitView { self.queue_event(WindowEvent::PointerMoved { device_id: None, + primary: true, position: view_point.to_physical(self.scale_factor()), source: PointerSource::Mouse, }); diff --git a/src/platform_impl/apple/uikit/view.rs b/src/platform_impl/apple/uikit/view.rs index e4c1844006..e6a297a2ad 100644 --- a/src/platform_impl/apple/uikit/view.rs +++ b/src/platform_impl/apple/uikit/view.rs @@ -34,6 +34,9 @@ pub struct WinitViewState { rotation_last_delta: Cell, pinch_last_delta: Cell, pan_last_delta: Cell, + + primary_finger: Cell>, + fingers: Cell, } declare_class!( @@ -371,6 +374,9 @@ impl WinitView { rotation_last_delta: Cell::new(0.0), pinch_last_delta: Cell::new(0.0), pan_last_delta: Cell::new(CGPoint { x: 0.0, y: 0.0 }), + + primary_finger: Cell::new(None), + fingers: Cell::new(0), }); let this: Retained = unsafe { msg_send_id![super(this), initWithFrame: frame] }; @@ -515,12 +521,33 @@ impl WinitView { let window_id = window.id(); let finger_id = RootFingerId(FingerId(touch_id)); + let ivars = self.ivars(); + match phase { UITouchPhase::Began => { + let primary = if let UITouchType::Pencil = touch_type { + true + } else { + ivars.fingers.set(ivars.fingers.get() + 1); + match ivars.primary_finger.get() { + Some(primary_id) => primary_id == touch_id, + None => { + debug_assert_eq!( + ivars.fingers.get(), + 1, + "number of fingers were not counted correctly" + ); + ivars.primary_finger.set(Some(touch_id)); + true + }, + } + }; + touch_events.push(EventWrapper::StaticEvent(Event::WindowEvent { window_id, event: WindowEvent::PointerEntered { device_id: None, + primary, position, kind: if let UITouchType::Pencil = touch_type { PointerKind::Unknown @@ -533,6 +560,7 @@ impl WinitView { window_id, event: WindowEvent::PointerButton { device_id: None, + primary, state: ElementState::Pressed, position, button: if let UITouchType::Pencil = touch_type { @@ -544,26 +572,44 @@ impl WinitView { })); }, UITouchPhase::Moved => { + let (primary, source) = if let UITouchType::Pencil = touch_type { + (true, PointerSource::Unknown) + } else { + (ivars.primary_finger.get().unwrap() == touch_id, PointerSource::Touch { + finger_id, + force, + }) + }; + touch_events.push(EventWrapper::StaticEvent(Event::WindowEvent { window_id, event: WindowEvent::PointerMoved { device_id: None, + primary, position, - source: if let UITouchType::Pencil = touch_type { - PointerSource::Unknown - } else { - PointerSource::Touch { finger_id, force } - }, + source, }, })); }, // 2 is UITouchPhase::Stationary and is not expected here UITouchPhase::Ended | UITouchPhase::Cancelled => { + let primary = if let UITouchType::Pencil = touch_type { + true + } else { + ivars.fingers.set(ivars.fingers.get() - 1); + let primary = ivars.primary_finger.get().unwrap() == touch_id; + if ivars.fingers.get() == 0 { + ivars.primary_finger.set(None); + } + primary + }; + if let UITouchPhase::Ended = phase { touch_events.push(EventWrapper::StaticEvent(Event::WindowEvent { window_id, event: WindowEvent::PointerButton { device_id: None, + primary, state: ElementState::Released, position, button: if let UITouchType::Pencil = touch_type { @@ -579,6 +625,7 @@ impl WinitView { window_id, event: WindowEvent::PointerLeft { device_id: None, + primary, position: Some(position), kind: if let UITouchType::Pencil = touch_type { PointerKind::Unknown diff --git a/src/platform_impl/linux/wayland/seat/mod.rs b/src/platform_impl/linux/wayland/seat/mod.rs index 36af28a535..1306699029 100644 --- a/src/platform_impl/linux/wayland/seat/mod.rs +++ b/src/platform_impl/linux/wayland/seat/mod.rs @@ -40,6 +40,9 @@ pub struct WinitSeatState { /// The mapping from touched points to the surfaces they're present. touch_map: AHashMap, + /// Id of the first touch event. + first_touch_id: Option, + /// The text input bound on the seat. text_input: Option>, diff --git a/src/platform_impl/linux/wayland/seat/pointer/mod.rs b/src/platform_impl/linux/wayland/seat/pointer/mod.rs index d080967b5f..944918d3a3 100644 --- a/src/platform_impl/linux/wayland/seat/pointer/mod.rs +++ b/src/platform_impl/linux/wayland/seat/pointer/mod.rs @@ -124,6 +124,7 @@ impl PointerHandler for WinitState { PointerEventKind::Enter { .. } => { self.events_sink.push_window_event( WindowEvent::PointerEntered { + primary: true, device_id: None, position, kind: PointerKind::Mouse, @@ -144,6 +145,7 @@ impl PointerHandler for WinitState { self.events_sink.push_window_event( WindowEvent::PointerLeft { + primary: true, device_id: None, position: Some(position), kind: PointerKind::Mouse, @@ -154,6 +156,7 @@ impl PointerHandler for WinitState { PointerEventKind::Motion { .. } => { self.events_sink.push_window_event( WindowEvent::PointerMoved { + primary: true, device_id: None, position, source: PointerSource::Mouse, @@ -174,6 +177,7 @@ impl PointerHandler for WinitState { }; self.events_sink.push_window_event( WindowEvent::PointerButton { + primary: true, device_id: None, state, position, diff --git a/src/platform_impl/linux/wayland/seat/touch/mod.rs b/src/platform_impl/linux/wayland/seat/touch/mod.rs index cadfbc647f..ca9d0b7554 100644 --- a/src/platform_impl/linux/wayland/seat/touch/mod.rs +++ b/src/platform_impl/linux/wayland/seat/touch/mod.rs @@ -41,6 +41,7 @@ impl TouchHandler for WinitState { // Update the state of the point. let location = LogicalPosition::::from(position); seat_state.touch_map.insert(id, TouchPoint { surface, location }); + let primary = seat_state.first_touch_id.get_or_insert(id) == &id; let position = location.to_physical(scale_factor); let finger_id = @@ -49,6 +50,7 @@ impl TouchHandler for WinitState { self.events_sink.push_window_event( WindowEvent::PointerEntered { device_id: None, + primary, position, kind: PointerKind::Touch(finger_id), }, @@ -57,6 +59,7 @@ impl TouchHandler for WinitState { self.events_sink.push_window_event( WindowEvent::PointerButton { device_id: None, + primary, state: ElementState::Pressed, position, button: ButtonSource::Touch { finger_id, force: None }, @@ -88,6 +91,12 @@ impl TouchHandler for WinitState { None => return, }; + // Update the primary touch point. + let primary = seat_state.first_touch_id == Some(id); + if primary { + seat_state.first_touch_id = None; + } + let window_id = wayland::make_wid(&touch_point.surface); let scale_factor = match self.windows.get_mut().get(&window_id) { Some(window) => window.lock().unwrap().scale_factor(), @@ -101,6 +110,7 @@ impl TouchHandler for WinitState { self.events_sink.push_window_event( WindowEvent::PointerButton { device_id: None, + primary, state: ElementState::Released, position, button: ButtonSource::Touch { finger_id, force: None }, @@ -110,6 +120,7 @@ impl TouchHandler for WinitState { self.events_sink.push_window_event( WindowEvent::PointerLeft { device_id: None, + primary, position: Some(position), kind: PointerKind::Touch(finger_id), }, @@ -140,6 +151,8 @@ impl TouchHandler for WinitState { None => return, }; + let primary = seat_state.first_touch_id == Some(id); + let window_id = wayland::make_wid(&touch_point.surface); let scale_factor = match self.windows.get_mut().get(&window_id) { Some(window) => window.lock().unwrap().scale_factor(), @@ -151,6 +164,7 @@ impl TouchHandler for WinitState { self.events_sink.push_window_event( WindowEvent::PointerMoved { device_id: None, + primary, position: touch_point.location.to_physical(scale_factor), source: PointerSource::Touch { finger_id: crate::event::FingerId(crate::platform_impl::FingerId::Wayland( @@ -179,11 +193,13 @@ impl TouchHandler for WinitState { None => return, }; + let primary = seat_state.first_touch_id == Some(id); let position = touch_point.location.to_physical(scale_factor); self.events_sink.push_window_event( WindowEvent::PointerLeft { device_id: None, + primary, position: Some(position), kind: PointerKind::Touch(crate::event::FingerId( crate::platform_impl::FingerId::Wayland(FingerId(id)), @@ -192,6 +208,8 @@ impl TouchHandler for WinitState { window_id, ); } + + seat_state.first_touch_id = None; } fn shape( diff --git a/src/platform_impl/linux/x11/event_processor.rs b/src/platform_impl/linux/x11/event_processor.rs index 1be903fa32..54848119d8 100644 --- a/src/platform_impl/linux/x11/event_processor.rs +++ b/src/platform_impl/linux/x11/event_processor.rs @@ -1034,12 +1034,14 @@ impl EventProcessor { let event = match event.detail as u32 { xlib::Button1 => WindowEvent::PointerButton { device_id, + primary: true, state, position, button: MouseButton::Left.into(), }, xlib::Button2 => WindowEvent::PointerButton { device_id, + primary: true, state, position, button: MouseButton::Middle.into(), @@ -1047,6 +1049,7 @@ impl EventProcessor { xlib::Button3 => WindowEvent::PointerButton { device_id, + primary: true, state, position, button: MouseButton::Right.into(), @@ -1069,6 +1072,7 @@ impl EventProcessor { }, 8 => WindowEvent::PointerButton { device_id, + primary: true, state, position, button: MouseButton::Back.into(), @@ -1076,12 +1080,14 @@ impl EventProcessor { 9 => WindowEvent::PointerButton { device_id, + primary: true, state, position, button: MouseButton::Forward.into(), }, x => WindowEvent::PointerButton { device_id, + primary: true, state, position, button: MouseButton::Other(x as u16).into(), @@ -1116,6 +1122,7 @@ impl EventProcessor { window_id, event: WindowEvent::PointerMoved { device_id, + primary: true, position, source: PointerSource::Mouse, }, @@ -1205,6 +1212,7 @@ impl EventProcessor { window_id, event: WindowEvent::PointerEntered { device_id, + primary: true, position, kind: PointerKind::Mouse, }, @@ -1229,6 +1237,7 @@ impl EventProcessor { window_id: mkwid(window), event: WindowEvent::PointerLeft { device_id: Some(mkdid(event.deviceid as xinput::DeviceId)), + primary: true, position: Some(PhysicalPosition::new(event.event_x, event.event_y)), kind: PointerKind::Mouse, }, @@ -1289,7 +1298,12 @@ impl EventProcessor { let event = Event::WindowEvent { window_id, - event: WindowEvent::PointerMoved { device_id, position, source: PointerSource::Mouse }, + event: WindowEvent::PointerMoved { + device_id, + primary: true, + position, + source: PointerSource::Mouse, + }, }; callback(&self.target, event); } @@ -1360,11 +1374,14 @@ impl EventProcessor { // 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 is_first_touch = + is_first_touch(&mut self.first_touch, &mut self.num_touch, id, phase); + if is_first_touch { let event = Event::WindowEvent { window_id, event: WindowEvent::PointerMoved { device_id: None, + primary: true, position: position.cast(), source: PointerSource::Mouse, }, @@ -1381,6 +1398,7 @@ impl EventProcessor { window_id, event: WindowEvent::PointerEntered { device_id, + primary: is_first_touch, position, kind: PointerKind::Touch(finger_id), }, @@ -1390,6 +1408,7 @@ impl EventProcessor { window_id, event: WindowEvent::PointerButton { device_id, + primary: is_first_touch, state: ElementState::Pressed, position, button: ButtonSource::Touch { finger_id, force: None }, @@ -1402,6 +1421,7 @@ impl EventProcessor { window_id, event: WindowEvent::PointerMoved { device_id, + primary: is_first_touch, position, source: PointerSource::Touch { finger_id, force: None }, }, @@ -1413,6 +1433,7 @@ impl EventProcessor { window_id, event: WindowEvent::PointerButton { device_id, + primary: is_first_touch, state: ElementState::Released, position, button: ButtonSource::Touch { finger_id, force: None }, @@ -1423,6 +1444,7 @@ impl EventProcessor { window_id, event: WindowEvent::PointerLeft { device_id, + primary: is_first_touch, position: Some(position), kind: PointerKind::Touch(finger_id), }, diff --git a/src/platform_impl/orbital/event_loop.rs b/src/platform_impl/orbital/event_loop.rs index 55b52aef50..af079ed177 100644 --- a/src/platform_impl/orbital/event_loop.rs +++ b/src/platform_impl/orbital/event_loop.rs @@ -404,6 +404,7 @@ impl EventLoop { EventOption::Mouse(MouseEvent { x, y }) => { app.window_event(window_target, window_id, event::WindowEvent::PointerMoved { device_id: None, + primary: true, position: (x, y).into(), source: event::PointerSource::Mouse, }); @@ -417,6 +418,7 @@ impl EventLoop { while let Some((button, state)) = event_state.mouse(left, middle, right) { app.window_event(window_target, window_id, event::WindowEvent::PointerButton { device_id: None, + primary: true, state, position: dpi::PhysicalPosition::default(), button: button.into(), @@ -458,12 +460,14 @@ impl EventLoop { let event = if entered { event::WindowEvent::PointerEntered { device_id: None, + primary: true, position: dpi::PhysicalPosition::default(), kind: event::PointerKind::Mouse, } } else { event::WindowEvent::PointerLeft { device_id: None, + primary: true, position: None, kind: event::PointerKind::Mouse, } diff --git a/src/platform_impl/web/event.rs b/src/platform_impl/web/event.rs index fcd634010d..5d016aab82 100644 --- a/src/platform_impl/web/event.rs +++ b/src/platform_impl/web/event.rs @@ -14,21 +14,16 @@ pub(crate) fn mkdid(pointer_id: i32) -> Option { #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct FingerId { pointer_id: i32, - primary: bool, } impl FingerId { - pub fn new(pointer_id: i32, primary: bool) -> Self { - Self { pointer_id, primary } + pub fn new(pointer_id: i32) -> Self { + Self { pointer_id } } #[cfg(test)] pub const fn dummy() -> Self { - Self { pointer_id: -1, primary: false } - } - - pub fn is_primary(self) -> bool { - self.primary + Self { pointer_id: -1 } } } diff --git a/src/platform_impl/web/event_loop/window_target.rs b/src/platform_impl/web/event_loop/window_target.rs index 9c6d680feb..4e75f7fbbb 100644 --- a/src/platform_impl/web/event_loop/window_target.rs +++ b/src/platform_impl/web/event_loop/window_target.rs @@ -197,7 +197,7 @@ impl ActiveEventLoop { let has_focus = has_focus.clone(); let modifiers = self.modifiers.clone(); - move |active_modifiers, device_id, position, kind| { + move |active_modifiers, device_id, primary, position, kind| { let focus = (has_focus.get() && modifiers.get() != active_modifiers).then(|| { modifiers.set(active_modifiers); Event::WindowEvent { @@ -208,7 +208,12 @@ impl ActiveEventLoop { runner.send_events(focus.into_iter().chain(iter::once(Event::WindowEvent { window_id, - event: WindowEvent::PointerLeft { device_id, position: Some(position), kind }, + event: WindowEvent::PointerLeft { + device_id, + primary, + position: Some(position), + kind, + }, }))) } }); @@ -218,7 +223,7 @@ impl ActiveEventLoop { let has_focus = has_focus.clone(); let modifiers = self.modifiers.clone(); - move |active_modifiers, device_id, position, kind| { + move |active_modifiers, device_id, primary, position, kind| { let focus = (has_focus.get() && modifiers.get() != active_modifiers).then(|| { modifiers.set(active_modifiers); Event::WindowEvent { @@ -229,7 +234,7 @@ impl ActiveEventLoop { runner.send_events(focus.into_iter().chain(iter::once(Event::WindowEvent { window_id, - event: WindowEvent::PointerEntered { device_id, position, kind }, + event: WindowEvent::PointerEntered { device_id, primary, position, kind }, }))) } }); @@ -241,21 +246,31 @@ impl ActiveEventLoop { let modifiers = self.modifiers.clone(); move |device_id, events| { - runner.send_events(events.flat_map(|(active_modifiers, position, source)| { - let modifiers = (has_focus.get() && modifiers.get() != active_modifiers) - .then(|| { - modifiers.set(active_modifiers); - Event::WindowEvent { - window_id, - event: WindowEvent::ModifiersChanged(active_modifiers.into()), - } - }); - - modifiers.into_iter().chain(iter::once(Event::WindowEvent { - window_id, - event: WindowEvent::PointerMoved { device_id, position, source }, - })) - })); + runner.send_events(events.flat_map( + |(active_modifiers, primary, position, source)| { + let modifiers = (has_focus.get() + && modifiers.get() != active_modifiers) + .then(|| { + modifiers.set(active_modifiers); + Event::WindowEvent { + window_id, + event: WindowEvent::ModifiersChanged( + active_modifiers.into(), + ), + } + }); + + modifiers.into_iter().chain(iter::once(Event::WindowEvent { + window_id, + event: WindowEvent::PointerMoved { + device_id, + primary, + position, + source, + }, + })) + }, + )); } }, { @@ -263,7 +278,7 @@ impl ActiveEventLoop { let has_focus = has_focus.clone(); let modifiers = self.modifiers.clone(); - move |active_modifiers, device_id, position, state, button| { + move |active_modifiers, device_id, primary, position, state, button| { let modifiers = (has_focus.get() && modifiers.get() != active_modifiers).then(|| { modifiers.set(active_modifiers); @@ -275,7 +290,13 @@ impl ActiveEventLoop { runner.send_events(modifiers.into_iter().chain([Event::WindowEvent { window_id, - event: WindowEvent::PointerButton { device_id, state, position, button }, + event: WindowEvent::PointerButton { + device_id, + primary, + state, + position, + button, + }, }])); } }, @@ -285,7 +306,7 @@ impl ActiveEventLoop { let runner = self.runner.clone(); let modifiers = self.modifiers.clone(); - move |active_modifiers, device_id, position, button| { + move |active_modifiers, device_id, primary, position, button| { let modifiers = (modifiers.get() != active_modifiers).then(|| { modifiers.set(active_modifiers); Event::WindowEvent { @@ -298,6 +319,7 @@ impl ActiveEventLoop { window_id, event: WindowEvent::PointerButton { device_id, + primary, state: ElementState::Pressed, position, button, @@ -311,7 +333,7 @@ impl ActiveEventLoop { let has_focus = has_focus.clone(); let modifiers = self.modifiers.clone(); - move |active_modifiers, device_id, position, button| { + move |active_modifiers, device_id, primary, position, button| { let modifiers = (has_focus.get() && modifiers.get() != active_modifiers).then(|| { modifiers.set(active_modifiers); @@ -325,6 +347,7 @@ impl ActiveEventLoop { window_id, event: WindowEvent::PointerButton { device_id, + primary, state: ElementState::Released, position, button, diff --git a/src/platform_impl/web/web_sys/canvas.rs b/src/platform_impl/web/web_sys/canvas.rs index 08b1a3dd23..8ab4f7e846 100644 --- a/src/platform_impl/web/web_sys/canvas.rs +++ b/src/platform_impl/web/web_sys/canvas.rs @@ -331,28 +331,32 @@ impl Canvas { pub fn on_pointer_leave(&self, handler: F) where - F: 'static + FnMut(ModifiersState, Option, PhysicalPosition, PointerKind), + F: 'static + + FnMut(ModifiersState, Option, bool, PhysicalPosition, PointerKind), { self.handlers.borrow_mut().pointer_handler.on_pointer_leave(&self.common, handler) } pub fn on_pointer_enter(&self, handler: F) where - F: 'static + FnMut(ModifiersState, Option, PhysicalPosition, PointerKind), + F: 'static + + FnMut(ModifiersState, Option, bool, PhysicalPosition, PointerKind), { self.handlers.borrow_mut().pointer_handler.on_pointer_enter(&self.common, handler) } pub fn on_pointer_release(&self, handler: C) where - C: 'static + FnMut(ModifiersState, Option, PhysicalPosition, ButtonSource), + C: 'static + + FnMut(ModifiersState, Option, bool, PhysicalPosition, ButtonSource), { self.handlers.borrow_mut().pointer_handler.on_pointer_release(&self.common, handler) } pub fn on_pointer_press(&self, handler: C) where - C: 'static + FnMut(ModifiersState, Option, PhysicalPosition, ButtonSource), + C: 'static + + FnMut(ModifiersState, Option, bool, PhysicalPosition, ButtonSource), { self.handlers.borrow_mut().pointer_handler.on_pointer_press( &self.common, @@ -366,12 +370,15 @@ impl Canvas { C: 'static + FnMut( Option, - &mut dyn Iterator, PointerSource)>, + &mut dyn Iterator< + Item = (ModifiersState, bool, PhysicalPosition, PointerSource), + >, ), B: 'static + FnMut( ModifiersState, Option, + bool, PhysicalPosition, ElementState, ButtonSource, diff --git a/src/platform_impl/web/web_sys/event.rs b/src/platform_impl/web/web_sys/event.rs index cd4c8800d8..8d56459c3f 100644 --- a/src/platform_impl/web/web_sys/event.rs +++ b/src/platform_impl/web/web_sys/event.rs @@ -164,7 +164,7 @@ 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()), + "touch" => PointerKind::Touch(FingerId::new(pointer_id).into()), _ => PointerKind::Unknown, } } diff --git a/src/platform_impl/web/web_sys/pointer.rs b/src/platform_impl/web/web_sys/pointer.rs index 53a42f5b41..7acfc1679e 100644 --- a/src/platform_impl/web/web_sys/pointer.rs +++ b/src/platform_impl/web/web_sys/pointer.rs @@ -35,7 +35,8 @@ impl PointerHandler { pub fn on_pointer_leave(&mut self, canvas_common: &Common, mut handler: F) where - F: 'static + FnMut(ModifiersState, Option, PhysicalPosition, PointerKind), + F: 'static + + FnMut(ModifiersState, Option, bool, PhysicalPosition, PointerKind), { let window = canvas_common.window.clone(); self.on_cursor_leave = @@ -46,13 +47,14 @@ impl PointerHandler { 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); + handler(modifiers, device_id, event.is_primary(), position, kind); })); } pub fn on_pointer_enter(&mut self, canvas_common: &Common, mut handler: F) where - F: 'static + FnMut(ModifiersState, Option, PhysicalPosition, PointerKind), + F: 'static + + FnMut(ModifiersState, Option, bool, PhysicalPosition, PointerKind), { let window = canvas_common.window.clone(); self.on_cursor_enter = @@ -63,13 +65,14 @@ impl PointerHandler { 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); + handler(modifiers, device_id, event.is_primary(), position, kind); })); } pub fn on_pointer_release(&mut self, canvas_common: &Common, mut handler: C) where - C: 'static + FnMut(ModifiersState, Option, PhysicalPosition, ButtonSource), + C: 'static + + FnMut(ModifiersState, Option, bool, PhysicalPosition, ButtonSource), { let window = canvas_common.window.clone(); self.on_pointer_release = @@ -92,6 +95,7 @@ impl PointerHandler { handler( modifiers, mkdid(pointer_id), + event.is_primary(), event::mouse_position(&event).to_physical(super::scale_factor(&window)), source, ) @@ -104,7 +108,8 @@ impl PointerHandler { mut handler: C, prevent_default: Rc>, ) where - C: 'static + FnMut(ModifiersState, Option, PhysicalPosition, ButtonSource), + C: 'static + + FnMut(ModifiersState, Option, bool, PhysicalPosition, ButtonSource), { let window = canvas_common.window.clone(); let canvas = canvas_common.raw().clone(); @@ -143,6 +148,7 @@ impl PointerHandler { handler( modifiers, mkdid(pointer_id), + event.is_primary(), event::mouse_position(&event).to_physical(super::scale_factor(&window)), source, ) @@ -159,12 +165,15 @@ impl PointerHandler { C: 'static + FnMut( Option, - &mut dyn Iterator, PointerSource)>, + &mut dyn Iterator< + Item = (ModifiersState, bool, PhysicalPosition, PointerSource), + >, ), B: 'static + FnMut( ModifiersState, Option, + bool, PhysicalPosition, ElementState, ButtonSource, @@ -177,6 +186,7 @@ impl PointerHandler { let pointer_id = event.pointer_id(); let device_id = mkdid(pointer_id); let kind = event::pointer_type(&event, pointer_id); + let primary = event.is_primary(); // chorded button event if let Some(button) = event::mouse_button(&event) { @@ -213,6 +223,7 @@ impl PointerHandler { button_handler( event::mouse_modifiers(&event), device_id, + primary, event::mouse_position(&event).to_physical(super::scale_factor(&window)), state, button, @@ -229,6 +240,7 @@ impl PointerHandler { &mut event::pointer_move_event(event).map(|event| { ( event::mouse_modifiers(&event), + event.is_primary(), event::mouse_position(&event).to_physical(scale), match kind { PointerKind::Mouse => PointerSource::Mouse, diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index c0c5b9414a..317fa483fb 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -1621,6 +1621,7 @@ unsafe fn public_window_callback_inner( window_id: WindowId::from_raw(window as usize), event: PointerEntered { device_id: None, + primary: true, position, kind: PointerKind::Mouse, }, @@ -1646,6 +1647,7 @@ unsafe fn public_window_callback_inner( window_id: WindowId::from_raw(window as usize), event: PointerLeft { device_id: None, + primary: true, position: Some(position), kind: PointerKind::Mouse, }, @@ -1667,7 +1669,12 @@ unsafe fn public_window_callback_inner( userdata.send_event(Event::WindowEvent { window_id: WindowId::from_raw(window as usize), - event: PointerMoved { device_id: None, position, source: PointerSource::Mouse }, + event: PointerMoved { + device_id: None, + primary: true, + position, + source: PointerSource::Mouse, + }, }); } @@ -1685,7 +1692,7 @@ unsafe fn public_window_callback_inner( userdata.send_event(Event::WindowEvent { window_id: WindowId::from_raw(window as usize), - event: PointerLeft { device_id: None, position: None, kind: Mouse }, + event: PointerLeft { device_id: None, primary: true, position: None, kind: Mouse }, }); result = ProcResult::Value(0); @@ -1762,6 +1769,7 @@ unsafe fn public_window_callback_inner( window_id: WindowId::from_raw(window as usize), event: PointerButton { device_id: None, + primary: true, state: Pressed, position, button: Left.into(), @@ -1787,6 +1795,7 @@ unsafe fn public_window_callback_inner( window_id: WindowId::from_raw(window as usize), event: PointerButton { device_id: None, + primary: true, state: Released, position, button: Left.into(), @@ -1812,6 +1821,7 @@ unsafe fn public_window_callback_inner( window_id: WindowId::from_raw(window as usize), event: PointerButton { device_id: None, + primary: true, state: Pressed, position, button: Right.into(), @@ -1837,6 +1847,7 @@ unsafe fn public_window_callback_inner( window_id: WindowId::from_raw(window as usize), event: PointerButton { device_id: None, + primary: true, state: Released, position, button: Right.into(), @@ -1862,6 +1873,7 @@ unsafe fn public_window_callback_inner( window_id: WindowId::from_raw(window as usize), event: PointerButton { device_id: None, + primary: true, state: Pressed, position, button: Middle.into(), @@ -1887,6 +1899,7 @@ unsafe fn public_window_callback_inner( window_id: WindowId::from_raw(window as usize), event: PointerButton { device_id: None, + primary: true, state: Released, position, button: Middle.into(), @@ -1913,6 +1926,7 @@ unsafe fn public_window_callback_inner( window_id: WindowId::from_raw(window as usize), event: PointerButton { device_id: None, + primary: true, state: Pressed, position, button: match xbutton { @@ -1944,6 +1958,7 @@ unsafe fn public_window_callback_inner( window_id: WindowId::from_raw(window as usize), event: PointerButton { device_id: None, + primary: true, state: Released, position, button: match xbutton { @@ -1997,16 +2012,15 @@ unsafe fn public_window_callback_inner( let position = PhysicalPosition::new(x, y); let window_id = WindowId::from_raw(window as usize); - let finger_id = RootFingerId(FingerId { - id: input.dwID, - primary: util::has_flag(input.dwFlags, TOUCHEVENTF_PRIMARY), - }); + let finger_id = RootFingerId(FingerId { id: input.dwID }); + let primary = util::has_flag(input.dwFlags, TOUCHEVENTF_PRIMARY); if util::has_flag(input.dwFlags, TOUCHEVENTF_DOWN) { userdata.send_event(Event::WindowEvent { window_id, event: WindowEvent::PointerEntered { device_id: None, + primary, position, kind: PointerKind::Touch(finger_id), }, @@ -2015,6 +2029,7 @@ unsafe fn public_window_callback_inner( window_id, event: WindowEvent::PointerButton { device_id: None, + primary, state: Pressed, position, button: Touch { finger_id, force: None }, @@ -2025,6 +2040,7 @@ unsafe fn public_window_callback_inner( window_id, event: WindowEvent::PointerButton { device_id: None, + primary, state: Released, position, button: Touch { finger_id, force: None }, @@ -2034,6 +2050,7 @@ unsafe fn public_window_callback_inner( window_id, event: WindowEvent::PointerLeft { device_id: None, + primary, position: Some(position), kind: PointerKind::Touch(finger_id), }, @@ -2043,6 +2060,7 @@ unsafe fn public_window_callback_inner( window_id, event: WindowEvent::PointerMoved { device_id: None, + primary, position, source: PointerSource::Touch { finger_id, force: None }, }, @@ -2165,16 +2183,15 @@ unsafe fn public_window_callback_inner( let position = PhysicalPosition::new(x, y); let window_id = WindowId::from_raw(window as usize); - let finger_id = RootFingerId(FingerId { - id: pointer_info.pointerId, - primary: util::has_flag(pointer_info.pointerFlags, POINTER_FLAG_PRIMARY), - }); + let finger_id = RootFingerId(FingerId { id: pointer_info.pointerId }); + let primary = util::has_flag(pointer_info.pointerFlags, POINTER_FLAG_PRIMARY); if util::has_flag(pointer_info.pointerFlags, POINTER_FLAG_DOWN) { userdata.send_event(Event::WindowEvent { window_id, event: WindowEvent::PointerEntered { device_id: None, + primary, position, kind: if let PT_TOUCH = pointer_info.pointerType { PointerKind::Touch(finger_id) @@ -2187,6 +2204,7 @@ unsafe fn public_window_callback_inner( window_id, event: WindowEvent::PointerButton { device_id: None, + primary, state: Pressed, position, button: if let PT_TOUCH = pointer_info.pointerType { @@ -2201,6 +2219,7 @@ unsafe fn public_window_callback_inner( window_id, event: WindowEvent::PointerButton { device_id: None, + primary, state: Released, position, button: if let PT_TOUCH = pointer_info.pointerType { @@ -2214,6 +2233,7 @@ unsafe fn public_window_callback_inner( window_id, event: WindowEvent::PointerLeft { device_id: None, + primary, position: Some(position), kind: if let PT_TOUCH = pointer_info.pointerType { PointerKind::Touch(finger_id) @@ -2227,6 +2247,7 @@ unsafe fn public_window_callback_inner( window_id, event: WindowEvent::PointerMoved { device_id: None, + primary, position, source: if let PT_TOUCH = pointer_info.pointerType { PointerSource::Touch { finger_id, force } diff --git a/src/platform_impl/windows/mod.rs b/src/platform_impl/windows/mod.rs index 48fe4bfeaa..6164c635fd 100644 --- a/src/platform_impl/windows/mod.rs +++ b/src/platform_impl/windows/mod.rs @@ -62,19 +62,12 @@ unsafe impl Sync for PlatformSpecificWindowAttributes {} #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct FingerId { id: u32, - primary: bool, } impl FingerId { #[cfg(test)] pub const fn dummy() -> Self { - FingerId { id: 0, primary: false } - } -} - -impl FingerId { - pub fn is_primary(self) -> bool { - self.primary + FingerId { id: 0 } } }