api: overhaul pointer API

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

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

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

View file

@ -638,7 +638,7 @@ pub fn keysym_to_key(keysym: u32) -> Key {
// keysyms::ISO_Release_Margin_Left => NamedKey::IsoReleaseMarginLeft,
// keysyms::ISO_Release_Margin_Right => NamedKey::IsoReleaseMarginRight,
// keysyms::ISO_Release_Both_Margins => NamedKey::IsoReleaseBothMargins,
// keysyms::ISO_Fast_Cursor_Left => NamedKey::IsoFastCursorLeft,
// keysyms::ISO_Fast_Cursor_Left => NamedKey::IsoFastPointerLeft,
// keysyms::ISO_Fast_Cursor_Right => NamedKey::IsoFastCursorRight,
// keysyms::ISO_Fast_Cursor_Up => NamedKey::IsoFastCursorUp,
// keysyms::ISO_Fast_Cursor_Down => NamedKey::IsoFastCursorDown,

View file

@ -27,7 +27,7 @@ use sctk::seat::pointer::{
use sctk::seat::SeatState;
use crate::dpi::{LogicalPosition, PhysicalPosition};
use crate::event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase, WindowEvent};
use crate::event::{ElementState, MouseButton, MouseScrollDelta, PointerSource, PointerKind, TouchPhase, WindowEvent};
use crate::platform_impl::wayland::state::WinitState;
use crate::platform_impl::wayland::{self, WindowId};
@ -123,7 +123,11 @@ impl PointerHandler for WinitState {
// Regular events on the main surface.
PointerEventKind::Enter { .. } => {
self.events_sink.push_window_event(
WindowEvent::CursorEntered { device_id: None },
WindowEvent::PointerEntered {
device_id: None,
position,
kind: PointerKind::Mouse,
},
window_id,
);
@ -131,11 +135,6 @@ impl PointerHandler for WinitState {
// Set the currently focused surface.
pointer.winit_data().inner.lock().unwrap().surface = Some(window_id);
self.events_sink.push_window_event(
WindowEvent::CursorMoved { device_id: None, position },
window_id,
);
},
PointerEventKind::Leave { .. } => {
window.pointer_left(Arc::downgrade(themed_pointer));
@ -143,12 +142,22 @@ impl PointerHandler for WinitState {
// Remove the active surface.
pointer.winit_data().inner.lock().unwrap().surface = None;
self.events_sink
.push_window_event(WindowEvent::CursorLeft { device_id: None }, window_id);
self.events_sink.push_window_event(
WindowEvent::PointerLeft {
device_id: None,
position: Some(position),
kind: PointerKind::Mouse,
},
window_id,
);
},
PointerEventKind::Motion { .. } => {
self.events_sink.push_window_event(
WindowEvent::CursorMoved { device_id: None, position },
WindowEvent::PointerMoved {
device_id: None,
position,
source: PointerSource::Mouse,
},
window_id,
);
},
@ -164,7 +173,12 @@ impl PointerHandler for WinitState {
ElementState::Released
};
self.events_sink.push_window_event(
WindowEvent::MouseInput { device_id: None, state, button },
WindowEvent::PointerButton {
device_id: None,
state,
position,
button: button.into(),
},
window_id,
);
},

View file

@ -68,7 +68,7 @@ impl Dispatch<ZwpRelativePointerV1, GlobalData, WinitState> for RelativePointerS
};
state
.events_sink
.push_device_event(DeviceEvent::MouseMotion { delta: (dx_unaccel, dy_unaccel) });
.push_device_event(DeviceEvent::PointerMotion { delta: (dx_unaccel, dy_unaccel) });
}
}

View file

@ -8,7 +8,7 @@ use sctk::seat::touch::{TouchData, TouchHandler};
use tracing::warn;
use crate::dpi::LogicalPosition;
use crate::event::{Touch, TouchPhase, WindowEvent};
use crate::event::{ButtonSource, ElementState, PointerKind, PointerSource, WindowEvent};
use crate::platform_impl::wayland::state::WinitState;
use crate::platform_impl::wayland::{self, FingerId};
@ -42,16 +42,25 @@ impl TouchHandler for WinitState {
let location = LogicalPosition::<f64>::from(position);
seat_state.touch_map.insert(id, TouchPoint { surface, location });
let position = location.to_physical(scale_factor);
let finger_id =
crate::event::FingerId(crate::platform_impl::FingerId::Wayland(FingerId(id)));
self.events_sink.push_window_event(
WindowEvent::Touch(Touch {
WindowEvent::PointerEntered {
device_id: None,
phase: TouchPhase::Started,
location: location.to_physical(scale_factor),
force: None,
finger_id: crate::event::FingerId(crate::platform_impl::FingerId::Wayland(
FingerId(id),
)),
}),
position,
kind: PointerKind::Touch(finger_id),
},
window_id,
);
self.events_sink.push_window_event(
WindowEvent::PointerButton {
device_id: None,
state: ElementState::Pressed,
position,
button: ButtonSource::Touch { finger_id, force: None },
},
window_id,
);
}
@ -85,16 +94,25 @@ impl TouchHandler for WinitState {
None => return,
};
let position = touch_point.location.to_physical(scale_factor);
let finger_id =
crate::event::FingerId(crate::platform_impl::FingerId::Wayland(FingerId(id)));
self.events_sink.push_window_event(
WindowEvent::Touch(Touch {
WindowEvent::PointerButton {
device_id: None,
phase: TouchPhase::Ended,
location: touch_point.location.to_physical(scale_factor),
force: None,
finger_id: crate::event::FingerId(crate::platform_impl::FingerId::Wayland(
FingerId(id),
)),
}),
state: ElementState::Released,
position,
button: ButtonSource::Touch { finger_id, force: None },
},
window_id,
);
self.events_sink.push_window_event(
WindowEvent::PointerLeft {
device_id: None,
position: Some(position),
kind: PointerKind::Touch(finger_id),
},
window_id,
);
}
@ -131,15 +149,16 @@ impl TouchHandler for WinitState {
touch_point.location = LogicalPosition::<f64>::from(position);
self.events_sink.push_window_event(
WindowEvent::Touch(Touch {
WindowEvent::PointerMoved {
device_id: None,
phase: TouchPhase::Moved,
location: touch_point.location.to_physical(scale_factor),
force: None,
finger_id: crate::event::FingerId(crate::platform_impl::FingerId::Wayland(
FingerId(id),
)),
}),
position: touch_point.location.to_physical(scale_factor),
source: PointerSource::Touch {
finger_id: crate::event::FingerId(crate::platform_impl::FingerId::Wayland(
FingerId(id),
)),
force: None,
},
},
window_id,
);
}
@ -160,18 +179,16 @@ impl TouchHandler for WinitState {
None => return,
};
let location = touch_point.location.to_physical(scale_factor);
let position = touch_point.location.to_physical(scale_factor);
self.events_sink.push_window_event(
WindowEvent::Touch(Touch {
WindowEvent::PointerLeft {
device_id: None,
phase: TouchPhase::Cancelled,
location,
force: None,
finger_id: crate::event::FingerId(crate::platform_impl::FingerId::Wayland(
FingerId(id),
position: Some(position),
kind: PointerKind::Touch(crate::event::FingerId(
crate::platform_impl::FingerId::Wayland(FingerId(id)),
)),
}),
},
window_id,
);
}

View file

@ -22,8 +22,8 @@ use xkbcommon_dl::xkb_mod_mask_t;
use crate::dpi::{PhysicalPosition, PhysicalSize};
use crate::event::{
DeviceEvent, ElementState, Event, Ime, MouseButton, MouseScrollDelta, RawKeyEvent,
SurfaceSizeWriter, Touch, TouchPhase, WindowEvent,
ButtonSource, DeviceEvent, ElementState, Event, Ime, MouseButton, MouseScrollDelta,
PointerKind, PointerSource, RawKeyEvent, SurfaceSizeWriter, TouchPhase, WindowEvent,
};
use crate::keyboard::ModifiersState;
use crate::platform_impl::common::xkb::{self, XkbState};
@ -238,15 +238,8 @@ impl EventProcessor {
self.xinput2_unfocused(xev, &mut callback);
},
xinput2::XI_TouchBegin | xinput2::XI_TouchUpdate | xinput2::XI_TouchEnd => {
let phase = match evtype {
xinput2::XI_TouchBegin => TouchPhase::Started,
xinput2::XI_TouchUpdate => TouchPhase::Moved,
xinput2::XI_TouchEnd => TouchPhase::Ended,
_ => unreachable!(),
};
let xev: &XIDeviceEvent = unsafe { xev.as_event() };
self.xinput2_touch(xev, phase, &mut callback);
self.xinput2_touch(xev, evtype, &mut callback);
},
xinput2::XI_RawButtonPress | xinput2::XI_RawButtonRelease => {
let state = match evtype {
@ -1025,16 +1018,27 @@ impl EventProcessor {
return;
}
let position = PhysicalPosition::new(event.event_x, event.event_y);
let event = match event.detail as u32 {
xlib::Button1 => {
WindowEvent::MouseInput { device_id, state, button: MouseButton::Left }
xlib::Button1 => WindowEvent::PointerButton {
device_id,
state,
position,
button: MouseButton::Left.into(),
},
xlib::Button2 => {
WindowEvent::MouseInput { device_id, state, button: MouseButton::Middle }
xlib::Button2 => WindowEvent::PointerButton {
device_id,
state,
position,
button: MouseButton::Middle.into(),
},
xlib::Button3 => {
WindowEvent::MouseInput { device_id, state, button: MouseButton::Right }
xlib::Button3 => WindowEvent::PointerButton {
device_id,
state,
position,
button: MouseButton::Right.into(),
},
// Suppress emulated scroll wheel clicks, since we handle the real motion events for
@ -1052,10 +1056,25 @@ impl EventProcessor {
},
phase: TouchPhase::Moved,
},
8 => WindowEvent::MouseInput { device_id, state, button: MouseButton::Back },
8 => WindowEvent::PointerButton {
device_id,
state,
position,
button: MouseButton::Back.into(),
},
9 => WindowEvent::MouseInput { device_id, state, button: MouseButton::Forward },
x => WindowEvent::MouseInput { device_id, state, button: MouseButton::Other(x as u16) },
9 => WindowEvent::PointerButton {
device_id,
state,
position,
button: MouseButton::Forward.into(),
},
x => WindowEvent::PointerButton {
device_id,
state,
position,
button: MouseButton::Other(x as u16).into(),
},
};
let event = Event::WindowEvent { window_id, event };
@ -1084,7 +1103,11 @@ impl EventProcessor {
let event = Event::WindowEvent {
window_id,
event: WindowEvent::CursorMoved { device_id, position },
event: WindowEvent::PointerMoved {
device_id,
position,
source: PointerSource::Mouse,
},
};
callback(&self.target, event);
} else if cursor_moved.is_none() {
@ -1167,13 +1190,13 @@ impl EventProcessor {
let device_id = Some(device_id);
let position = PhysicalPosition::new(event.event_x, event.event_y);
let event =
Event::WindowEvent { window_id, event: WindowEvent::CursorEntered { device_id } };
callback(&self.target, event);
let event = Event::WindowEvent {
window_id,
event: WindowEvent::CursorMoved { device_id, position },
event: WindowEvent::PointerEntered {
device_id,
position,
kind: PointerKind::Mouse,
},
};
callback(&self.target, event);
}
@ -1193,8 +1216,10 @@ impl EventProcessor {
if self.window_exists(window) {
let event = Event::WindowEvent {
window_id: mkwid(window),
event: WindowEvent::CursorLeft {
event: WindowEvent::PointerLeft {
device_id: Some(mkdid(event.deviceid as xinput::DeviceId)),
position: Some(PhysicalPosition::new(event.event_x, event.event_y)),
kind: PointerKind::Mouse,
},
};
callback(&self.target, event);
@ -1253,7 +1278,7 @@ impl EventProcessor {
let event = Event::WindowEvent {
window_id,
event: WindowEvent::CursorMoved { device_id, position },
event: WindowEvent::PointerMoved { device_id, position, source: PointerSource::Mouse },
};
callback(&self.target, event);
}
@ -1309,7 +1334,7 @@ impl EventProcessor {
}
}
fn xinput2_touch<F>(&mut self, xev: &XIDeviceEvent, phase: TouchPhase, mut callback: F)
fn xinput2_touch<F>(&mut self, xev: &XIDeviceEvent, phase: i32, mut callback: F)
where
F: FnMut(&ActiveEventLoop, Event),
{
@ -1320,29 +1345,81 @@ impl EventProcessor {
if self.window_exists(window) {
let window_id = mkwid(window);
let id = xev.detail as u32;
let location = PhysicalPosition::new(xev.event_x, xev.event_y);
let position = PhysicalPosition::new(xev.event_x, xev.event_y);
// Mouse cursor position changes when touch events are received.
// Only the first concurrently active touch ID moves the mouse cursor.
if is_first_touch(&mut self.first_touch, &mut self.num_touch, id, phase) {
let event = Event::WindowEvent {
window_id,
event: WindowEvent::CursorMoved { device_id: None, position: location.cast() },
event: WindowEvent::PointerMoved {
device_id: None,
position: position.cast(),
source: PointerSource::Mouse,
},
};
callback(&self.target, event);
}
let event = Event::WindowEvent {
window_id,
event: WindowEvent::Touch(Touch {
device_id: Some(mkdid(xev.deviceid as xinput::DeviceId)),
phase,
location,
force: None, // TODO
finger_id: mkfid(id),
}),
};
callback(&self.target, event)
let device_id = Some(mkdid(xev.deviceid as xinput::DeviceId));
let finger_id = mkfid(id);
match phase {
xinput2::XI_TouchBegin => {
let event = Event::WindowEvent {
window_id,
event: WindowEvent::PointerEntered {
device_id,
position,
kind: PointerKind::Touch(finger_id),
},
};
callback(&self.target, event);
let event = Event::WindowEvent {
window_id,
event: WindowEvent::PointerButton {
device_id,
state: ElementState::Pressed,
position,
button: ButtonSource::Touch { finger_id, force: None },
},
};
callback(&self.target, event);
},
xinput2::XI_TouchUpdate => {
let event = Event::WindowEvent {
window_id,
event: WindowEvent::PointerMoved {
device_id,
position,
source: PointerSource::Touch { finger_id, force: None },
},
};
callback(&self.target, event);
},
xinput2::XI_TouchEnd => {
let event = Event::WindowEvent {
window_id,
event: WindowEvent::PointerButton {
device_id,
state: ElementState::Released,
position,
button: ButtonSource::Touch { finger_id, force: None },
},
};
callback(&self.target, event);
let event = Event::WindowEvent {
window_id,
event: WindowEvent::PointerLeft {
device_id,
position: Some(position),
kind: PointerKind::Touch(finger_id),
},
};
callback(&self.target, event);
},
_ => unreachable!(),
}
}
}
@ -1398,7 +1475,7 @@ impl EventProcessor {
if let Some(mouse_delta) = mouse_delta.consume() {
let event = Event::DeviceEvent {
device_id: did,
event: DeviceEvent::MouseMotion { delta: mouse_delta },
event: DeviceEvent::PointerMotion { delta: mouse_delta },
};
callback(&self.target, event);
}
@ -1762,15 +1839,15 @@ impl EventProcessor {
}
}
fn is_first_touch(first: &mut Option<u32>, num: &mut u32, id: u32, phase: TouchPhase) -> bool {
fn is_first_touch(first: &mut Option<u32>, num: &mut u32, id: u32, phase: i32) -> bool {
match phase {
TouchPhase::Started => {
xinput2::XI_TouchBegin => {
if *num == 0 {
*first = Some(id);
}
*num += 1;
},
TouchPhase::Cancelled | TouchPhase::Ended => {
xinput2::XI_TouchEnd => {
if *first == Some(id) {
*first = None;
}