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 <daxpedda@gmail.com>
This commit is contained in:
Kirill Chibisov 2024-10-11 20:08:51 +03:00
parent d3207a8d76
commit c8c1eca3c7
19 changed files with 346 additions and 176 deletions

View file

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

View file

@ -245,6 +245,12 @@ pub enum WindowEvent {
/// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform
position: PhysicalPosition<f64>,
/// 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<f64>,
/// 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<PhysicalPosition<f64>>,
/// 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<f64>,
/// 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 {

View file

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

View file

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

View file

@ -107,6 +107,7 @@ pub struct EventLoop {
running: bool,
pending_redraw: bool,
cause: StartCause,
primary_pointer: FingerId,
ignore_volume_keys: bool,
combining_accent: Option<char>,
}
@ -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));
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 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,
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)
}

View file

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

View file

@ -34,6 +34,9 @@ pub struct WinitViewState {
rotation_last_delta: Cell<CGFloat>,
pinch_last_delta: Cell<CGFloat>,
pan_last_delta: Cell<CGPoint>,
primary_finger: Cell<Option<usize>>,
fingers: Cell<u8>,
}
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<Self> = 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

View file

@ -40,6 +40,9 @@ pub struct WinitSeatState {
/// The mapping from touched points to the surfaces they're present.
touch_map: AHashMap<i32, TouchPoint>,
/// Id of the first touch event.
first_touch_id: Option<i32>,
/// The text input bound on the seat.
text_input: Option<Arc<ZwpTextInputV3>>,

View file

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

View file

@ -41,6 +41,7 @@ impl TouchHandler for WinitState {
// Update the state of the point.
let location = LogicalPosition::<f64>::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(

View file

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

View file

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

View file

@ -14,21 +14,16 @@ pub(crate) fn mkdid(pointer_id: i32) -> Option<DeviceId> {
#[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 }
}
}

View file

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

View file

@ -331,28 +331,32 @@ impl Canvas {
pub fn on_pointer_leave<F>(&self, handler: F)
where
F: 'static + FnMut(ModifiersState, Option<DeviceId>, PhysicalPosition<f64>, PointerKind),
F: 'static
+ FnMut(ModifiersState, Option<DeviceId>, bool, PhysicalPosition<f64>, PointerKind),
{
self.handlers.borrow_mut().pointer_handler.on_pointer_leave(&self.common, handler)
}
pub fn on_pointer_enter<F>(&self, handler: F)
where
F: 'static + FnMut(ModifiersState, Option<DeviceId>, PhysicalPosition<f64>, PointerKind),
F: 'static
+ FnMut(ModifiersState, Option<DeviceId>, bool, PhysicalPosition<f64>, PointerKind),
{
self.handlers.borrow_mut().pointer_handler.on_pointer_enter(&self.common, handler)
}
pub fn on_pointer_release<C>(&self, handler: C)
where
C: 'static + FnMut(ModifiersState, Option<DeviceId>, PhysicalPosition<f64>, ButtonSource),
C: 'static
+ FnMut(ModifiersState, Option<DeviceId>, bool, PhysicalPosition<f64>, ButtonSource),
{
self.handlers.borrow_mut().pointer_handler.on_pointer_release(&self.common, handler)
}
pub fn on_pointer_press<C>(&self, handler: C)
where
C: 'static + FnMut(ModifiersState, Option<DeviceId>, PhysicalPosition<f64>, ButtonSource),
C: 'static
+ FnMut(ModifiersState, Option<DeviceId>, bool, PhysicalPosition<f64>, ButtonSource),
{
self.handlers.borrow_mut().pointer_handler.on_pointer_press(
&self.common,
@ -366,12 +370,15 @@ impl Canvas {
C: 'static
+ FnMut(
Option<DeviceId>,
&mut dyn Iterator<Item = (ModifiersState, PhysicalPosition<f64>, PointerSource)>,
&mut dyn Iterator<
Item = (ModifiersState, bool, PhysicalPosition<f64>, PointerSource),
>,
),
B: 'static
+ FnMut(
ModifiersState,
Option<DeviceId>,
bool,
PhysicalPosition<f64>,
ElementState,
ButtonSource,

View file

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

View file

@ -35,7 +35,8 @@ impl PointerHandler {
pub fn on_pointer_leave<F>(&mut self, canvas_common: &Common, mut handler: F)
where
F: 'static + FnMut(ModifiersState, Option<DeviceId>, PhysicalPosition<f64>, PointerKind),
F: 'static
+ FnMut(ModifiersState, Option<DeviceId>, bool, PhysicalPosition<f64>, 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<F>(&mut self, canvas_common: &Common, mut handler: F)
where
F: 'static + FnMut(ModifiersState, Option<DeviceId>, PhysicalPosition<f64>, PointerKind),
F: 'static
+ FnMut(ModifiersState, Option<DeviceId>, bool, PhysicalPosition<f64>, 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<C>(&mut self, canvas_common: &Common, mut handler: C)
where
C: 'static + FnMut(ModifiersState, Option<DeviceId>, PhysicalPosition<f64>, ButtonSource),
C: 'static
+ FnMut(ModifiersState, Option<DeviceId>, bool, PhysicalPosition<f64>, 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<Cell<bool>>,
) where
C: 'static + FnMut(ModifiersState, Option<DeviceId>, PhysicalPosition<f64>, ButtonSource),
C: 'static
+ FnMut(ModifiersState, Option<DeviceId>, bool, PhysicalPosition<f64>, 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<DeviceId>,
&mut dyn Iterator<Item = (ModifiersState, PhysicalPosition<f64>, PointerSource)>,
&mut dyn Iterator<
Item = (ModifiersState, bool, PhysicalPosition<f64>, PointerSource),
>,
),
B: 'static
+ FnMut(
ModifiersState,
Option<DeviceId>,
bool,
PhysicalPosition<f64>,
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,

View file

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

View file

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