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