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

@ -37,9 +37,9 @@ use windows_sys::Win32::UI::WindowsAndMessaging::{
GetMenu, GetMessageW, KillTimer, LoadCursorW, PeekMessageW, PostMessageW, RegisterClassExW,
RegisterWindowMessageA, SetCursor, SetTimer, SetWindowPos, TranslateMessage, CREATESTRUCTW,
GWL_STYLE, GWL_USERDATA, HTCAPTION, HTCLIENT, MINMAXINFO, MNC_CLOSE, MSG, NCCALCSIZE_PARAMS,
PM_REMOVE, PT_PEN, PT_TOUCH, RI_MOUSE_HWHEEL, RI_MOUSE_WHEEL, SC_MINIMIZE, SC_RESTORE,
SIZE_MAXIMIZED, SWP_NOACTIVATE, SWP_NOMOVE, SWP_NOSIZE, SWP_NOZORDER, WHEEL_DELTA, WINDOWPOS,
WMSZ_BOTTOM, WMSZ_BOTTOMLEFT, WMSZ_BOTTOMRIGHT, WMSZ_LEFT, WMSZ_RIGHT, WMSZ_TOP, WMSZ_TOPLEFT,
PM_REMOVE, PT_TOUCH, RI_MOUSE_HWHEEL, RI_MOUSE_WHEEL, SC_MINIMIZE, SC_RESTORE, SIZE_MAXIMIZED,
SWP_NOACTIVATE, SWP_NOMOVE, SWP_NOSIZE, SWP_NOZORDER, WHEEL_DELTA, WINDOWPOS, WMSZ_BOTTOM,
WMSZ_BOTTOMLEFT, WMSZ_BOTTOMRIGHT, WMSZ_LEFT, WMSZ_RIGHT, WMSZ_TOP, WMSZ_TOPLEFT,
WMSZ_TOPRIGHT, WM_CAPTURECHANGED, WM_CLOSE, WM_CREATE, WM_DESTROY, WM_DPICHANGED,
WM_ENTERSIZEMOVE, WM_EXITSIZEMOVE, WM_GETMINMAXINFO, WM_IME_COMPOSITION, WM_IME_ENDCOMPOSITION,
WM_IME_SETCONTEXT, WM_IME_STARTCOMPOSITION, WM_INPUT, WM_KEYDOWN, WM_KEYUP, WM_KILLFOCUS,
@ -58,7 +58,7 @@ use crate::application::ApplicationHandler;
use crate::dpi::{PhysicalPosition, PhysicalSize};
use crate::error::{EventLoopError, RequestError};
use crate::event::{
Event, FingerId as RootFingerId, Force, Ime, RawKeyEvent, SurfaceSizeWriter, Touch, TouchPhase,
Event, FingerId as RootFingerId, Force, Ime, RawKeyEvent, SurfaceSizeWriter, TouchPhase,
WindowEvent,
};
use crate::event_loop::{
@ -1520,7 +1520,8 @@ unsafe fn public_window_callback_inner(
},
WM_MOUSEMOVE => {
use crate::event::WindowEvent::{CursorEntered, CursorLeft, CursorMoved};
use crate::event::WindowEvent::{PointerEntered, PointerLeft, PointerMoved};
use crate::event::{PointerKind, PointerSource};
let x = super::get_x_lparam(lparam as u32) as i32;
let y = super::get_y_lparam(lparam as u32) as i32;
@ -1541,7 +1542,11 @@ unsafe fn public_window_callback_inner(
drop(w);
userdata.send_event(Event::WindowEvent {
window_id: CoreWindowId(WindowId(window)),
event: CursorEntered { device_id: None },
event: PointerEntered {
device_id: None,
position,
kind: PointerKind::Mouse,
},
});
// Calling TrackMouseEvent in order to receive mouse leave events.
@ -1562,7 +1567,11 @@ unsafe fn public_window_callback_inner(
drop(w);
userdata.send_event(Event::WindowEvent {
window_id: CoreWindowId(WindowId(window)),
event: CursorLeft { device_id: None },
event: PointerLeft {
device_id: None,
position: Some(position),
kind: PointerKind::Mouse,
},
});
},
PointerMoveKind::None => drop(w),
@ -1581,7 +1590,7 @@ unsafe fn public_window_callback_inner(
userdata.send_event(Event::WindowEvent {
window_id: CoreWindowId(WindowId(window)),
event: CursorMoved { device_id: None, position },
event: PointerMoved { device_id: None, position, source: PointerSource::Mouse },
});
}
@ -1589,7 +1598,9 @@ unsafe fn public_window_callback_inner(
},
WM_MOUSELEAVE => {
use crate::event::WindowEvent::CursorLeft;
use crate::event::PointerKind::Mouse;
use crate::event::WindowEvent::PointerLeft;
{
let mut w = userdata.window_state_lock();
w.mouse.set_cursor_flags(window, |f| f.set(CursorFlags::IN_WINDOW, false)).ok();
@ -1597,7 +1608,7 @@ unsafe fn public_window_callback_inner(
userdata.send_event(Event::WindowEvent {
window_id: CoreWindowId(WindowId(window)),
event: CursorLeft { device_id: None },
event: PointerLeft { device_id: None, position: None, kind: Mouse },
});
result = ProcResult::Value(0);
@ -1660,15 +1671,24 @@ unsafe fn public_window_callback_inner(
WM_LBUTTONDOWN => {
use crate::event::ElementState::Pressed;
use crate::event::MouseButton::Left;
use crate::event::WindowEvent::MouseInput;
use crate::event::WindowEvent::PointerButton;
unsafe { capture_mouse(window, &mut userdata.window_state_lock()) };
update_modifiers(window, userdata);
let x = super::get_x_lparam(lparam as u32) as i32;
let y = super::get_y_lparam(lparam as u32) as i32;
let position = PhysicalPosition::new(x as f64, y as f64);
userdata.send_event(Event::WindowEvent {
window_id: CoreWindowId(WindowId(window)),
event: MouseInput { device_id: None, state: Pressed, button: Left },
event: PointerButton {
device_id: None,
state: Pressed,
position,
button: Left.into(),
},
});
result = ProcResult::Value(0);
},
@ -1676,15 +1696,24 @@ unsafe fn public_window_callback_inner(
WM_LBUTTONUP => {
use crate::event::ElementState::Released;
use crate::event::MouseButton::Left;
use crate::event::WindowEvent::MouseInput;
use crate::event::WindowEvent::PointerButton;
unsafe { release_mouse(userdata.window_state_lock()) };
update_modifiers(window, userdata);
let x = super::get_x_lparam(lparam as u32) as i32;
let y = super::get_y_lparam(lparam as u32) as i32;
let position = PhysicalPosition::new(x as f64, y as f64);
userdata.send_event(Event::WindowEvent {
window_id: CoreWindowId(WindowId(window)),
event: MouseInput { device_id: None, state: Released, button: Left },
event: PointerButton {
device_id: None,
state: Released,
position,
button: Left.into(),
},
});
result = ProcResult::Value(0);
},
@ -1692,15 +1721,24 @@ unsafe fn public_window_callback_inner(
WM_RBUTTONDOWN => {
use crate::event::ElementState::Pressed;
use crate::event::MouseButton::Right;
use crate::event::WindowEvent::MouseInput;
use crate::event::WindowEvent::PointerButton;
unsafe { capture_mouse(window, &mut userdata.window_state_lock()) };
update_modifiers(window, userdata);
let x = super::get_x_lparam(lparam as u32) as i32;
let y = super::get_y_lparam(lparam as u32) as i32;
let position = PhysicalPosition::new(x as f64, y as f64);
userdata.send_event(Event::WindowEvent {
window_id: CoreWindowId(WindowId(window)),
event: MouseInput { device_id: None, state: Pressed, button: Right },
event: PointerButton {
device_id: None,
state: Pressed,
position,
button: Right.into(),
},
});
result = ProcResult::Value(0);
},
@ -1708,15 +1746,24 @@ unsafe fn public_window_callback_inner(
WM_RBUTTONUP => {
use crate::event::ElementState::Released;
use crate::event::MouseButton::Right;
use crate::event::WindowEvent::MouseInput;
use crate::event::WindowEvent::PointerButton;
unsafe { release_mouse(userdata.window_state_lock()) };
update_modifiers(window, userdata);
let x = super::get_x_lparam(lparam as u32) as i32;
let y = super::get_y_lparam(lparam as u32) as i32;
let position = PhysicalPosition::new(x as f64, y as f64);
userdata.send_event(Event::WindowEvent {
window_id: CoreWindowId(WindowId(window)),
event: MouseInput { device_id: None, state: Released, button: Right },
event: PointerButton {
device_id: None,
state: Released,
position,
button: Right.into(),
},
});
result = ProcResult::Value(0);
},
@ -1724,15 +1771,24 @@ unsafe fn public_window_callback_inner(
WM_MBUTTONDOWN => {
use crate::event::ElementState::Pressed;
use crate::event::MouseButton::Middle;
use crate::event::WindowEvent::MouseInput;
use crate::event::WindowEvent::PointerButton;
unsafe { capture_mouse(window, &mut userdata.window_state_lock()) };
update_modifiers(window, userdata);
let x = super::get_x_lparam(lparam as u32) as i32;
let y = super::get_y_lparam(lparam as u32) as i32;
let position = PhysicalPosition::new(x as f64, y as f64);
userdata.send_event(Event::WindowEvent {
window_id: CoreWindowId(WindowId(window)),
event: MouseInput { device_id: None, state: Pressed, button: Middle },
event: PointerButton {
device_id: None,
state: Pressed,
position,
button: Middle.into(),
},
});
result = ProcResult::Value(0);
},
@ -1740,15 +1796,24 @@ unsafe fn public_window_callback_inner(
WM_MBUTTONUP => {
use crate::event::ElementState::Released;
use crate::event::MouseButton::Middle;
use crate::event::WindowEvent::MouseInput;
use crate::event::WindowEvent::PointerButton;
unsafe { release_mouse(userdata.window_state_lock()) };
update_modifiers(window, userdata);
let x = super::get_x_lparam(lparam as u32) as i32;
let y = super::get_y_lparam(lparam as u32) as i32;
let position = PhysicalPosition::new(x as f64, y as f64);
userdata.send_event(Event::WindowEvent {
window_id: CoreWindowId(WindowId(window)),
event: MouseInput { device_id: None, state: Released, button: Middle },
event: PointerButton {
device_id: None,
state: Released,
position,
button: Middle.into(),
},
});
result = ProcResult::Value(0);
},
@ -1756,23 +1821,29 @@ unsafe fn public_window_callback_inner(
WM_XBUTTONDOWN => {
use crate::event::ElementState::Pressed;
use crate::event::MouseButton::{Back, Forward, Other};
use crate::event::WindowEvent::MouseInput;
use crate::event::WindowEvent::PointerButton;
let xbutton = super::get_xbutton_wparam(wparam as u32);
unsafe { capture_mouse(window, &mut userdata.window_state_lock()) };
update_modifiers(window, userdata);
let x = super::get_x_lparam(lparam as u32) as i32;
let y = super::get_y_lparam(lparam as u32) as i32;
let position = PhysicalPosition::new(x as f64, y as f64);
userdata.send_event(Event::WindowEvent {
window_id: CoreWindowId(WindowId(window)),
event: MouseInput {
event: PointerButton {
device_id: None,
state: Pressed,
position,
button: match xbutton {
1 => Back,
2 => Forward,
_ => Other(xbutton),
},
}
.into(),
},
});
result = ProcResult::Value(0);
@ -1781,23 +1852,29 @@ unsafe fn public_window_callback_inner(
WM_XBUTTONUP => {
use crate::event::ElementState::Released;
use crate::event::MouseButton::{Back, Forward, Other};
use crate::event::WindowEvent::MouseInput;
use crate::event::WindowEvent::PointerButton;
let xbutton = super::get_xbutton_wparam(wparam as u32);
unsafe { release_mouse(userdata.window_state_lock()) };
update_modifiers(window, userdata);
let x = super::get_x_lparam(lparam as u32) as i32;
let y = super::get_y_lparam(lparam as u32) as i32;
let position = PhysicalPosition::new(x as f64, y as f64);
userdata.send_event(Event::WindowEvent {
window_id: CoreWindowId(WindowId(window)),
event: MouseInput {
event: PointerButton {
device_id: None,
state: Released,
position,
button: match xbutton {
1 => Back,
2 => Forward,
_ => Other(xbutton),
},
}
.into(),
},
});
result = ProcResult::Value(0);
@ -1815,6 +1892,10 @@ unsafe fn public_window_callback_inner(
},
WM_TOUCH => {
use crate::event::ButtonSource::Touch;
use crate::event::ElementState::{Pressed, Released};
use crate::event::{PointerKind, PointerSource};
let pcount = super::loword(wparam as u32) as usize;
let mut inputs = Vec::with_capacity(pcount);
let htouch = lparam;
@ -1828,36 +1909,70 @@ unsafe fn public_window_callback_inner(
} {
unsafe { inputs.set_len(pcount) };
for input in &inputs {
let mut location = POINT { x: input.x / 100, y: input.y / 100 };
let mut position = POINT { x: input.x / 100, y: input.y / 100 };
if unsafe { ScreenToClient(window, &mut location) } == false.into() {
if unsafe { ScreenToClient(window, &mut position) } == false.into() {
continue;
}
let x = location.x as f64 + (input.x % 100) as f64 / 100f64;
let y = location.y as f64 + (input.y % 100) as f64 / 100f64;
let location = PhysicalPosition::new(x, y);
userdata.send_event(Event::WindowEvent {
window_id: CoreWindowId(WindowId(window)),
event: WindowEvent::Touch(Touch {
phase: if util::has_flag(input.dwFlags, TOUCHEVENTF_DOWN) {
TouchPhase::Started
} else if util::has_flag(input.dwFlags, TOUCHEVENTF_UP) {
TouchPhase::Ended
} else if util::has_flag(input.dwFlags, TOUCHEVENTF_MOVE) {
TouchPhase::Moved
} else {
continue;
},
location,
force: None, // WM_TOUCH doesn't support pressure information
finger_id: RootFingerId(FingerId {
id: input.dwID,
primary: util::has_flag(input.dwFlags, TOUCHEVENTF_PRIMARY),
}),
device_id: None,
}),
let x = position.x as f64 + (input.x % 100) as f64 / 100f64;
let y = position.y as f64 + (input.y % 100) as f64 / 100f64;
let position = PhysicalPosition::new(x, y);
let window_id = CoreWindowId(WindowId(window));
let finger_id = RootFingerId(FingerId {
id: input.dwID,
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,
position,
kind: PointerKind::Touch(finger_id),
},
});
userdata.send_event(Event::WindowEvent {
window_id,
event: WindowEvent::PointerButton {
device_id: None,
state: Pressed,
position,
button: Touch { finger_id, force: None },
},
});
} else if util::has_flag(input.dwFlags, TOUCHEVENTF_UP) {
userdata.send_event(Event::WindowEvent {
window_id,
event: WindowEvent::PointerButton {
device_id: None,
state: Released,
position,
button: Touch { finger_id, force: None },
},
});
userdata.send_event(Event::WindowEvent {
window_id,
event: WindowEvent::PointerLeft {
device_id: None,
position: Some(position),
kind: PointerKind::Touch(finger_id),
},
});
} else if util::has_flag(input.dwFlags, TOUCHEVENTF_MOVE) {
userdata.send_event(Event::WindowEvent {
window_id,
event: WindowEvent::PointerMoved {
device_id: None,
position,
source: PointerSource::Touch { finger_id, force: None },
},
});
} else {
continue;
}
}
}
unsafe { CloseTouchInputHandle(htouch) };
@ -1865,6 +1980,9 @@ unsafe fn public_window_callback_inner(
},
WM_POINTERDOWN | WM_POINTERUPDATE | WM_POINTERUP => {
use crate::event::ElementState::{Pressed, Released};
use crate::event::{ButtonSource, PointerKind, PointerSource};
if let (
Some(GetPointerFrameInfoHistory),
Some(SkipPointerFrameMessages),
@ -1949,67 +2067,100 @@ unsafe fn public_window_callback_inner(
continue;
}
let force = match pointer_info.pointerType {
PT_TOUCH => {
let mut touch_info = mem::MaybeUninit::uninit();
util::GET_POINTER_TOUCH_INFO.and_then(|GetPointerTouchInfo| {
match unsafe {
GetPointerTouchInfo(
pointer_info.pointerId,
touch_info.as_mut_ptr(),
)
} {
0 => None,
_ => normalize_pointer_pressure(unsafe {
touch_info.assume_init().pressure
}),
}
})
},
PT_PEN => {
let mut pen_info = mem::MaybeUninit::uninit();
util::GET_POINTER_PEN_INFO.and_then(|GetPointerPenInfo| {
match unsafe {
GetPointerPenInfo(pointer_info.pointerId, pen_info.as_mut_ptr())
} {
0 => None,
_ => normalize_pointer_pressure(unsafe {
pen_info.assume_init().pressure
}),
}
})
},
_ => None,
let force = if let PT_TOUCH = pointer_info.pointerType {
let mut touch_info = mem::MaybeUninit::uninit();
util::GET_POINTER_TOUCH_INFO.and_then(|GetPointerTouchInfo| {
match unsafe {
GetPointerTouchInfo(pointer_info.pointerId, touch_info.as_mut_ptr())
} {
0 => None,
_ => normalize_pointer_pressure(unsafe {
touch_info.assume_init().pressure
}),
}
})
} else {
None
};
let x = location.x as f64 + x.fract();
let y = location.y as f64 + y.fract();
let location = PhysicalPosition::new(x, y);
userdata.send_event(Event::WindowEvent {
window_id: CoreWindowId(WindowId(window)),
event: WindowEvent::Touch(Touch {
phase: if util::has_flag(pointer_info.pointerFlags, POINTER_FLAG_DOWN) {
TouchPhase::Started
} else if util::has_flag(pointer_info.pointerFlags, POINTER_FLAG_UP) {
TouchPhase::Ended
} else if util::has_flag(pointer_info.pointerFlags, POINTER_FLAG_UPDATE)
{
TouchPhase::Moved
} else {
continue;
},
location,
force,
finger_id: RootFingerId(FingerId {
id: pointer_info.pointerId,
primary: util::has_flag(
pointer_info.pointerFlags,
POINTER_FLAG_PRIMARY,
),
}),
device_id: None,
}),
let position = PhysicalPosition::new(x, y);
let window_id = CoreWindowId(WindowId(window));
let finger_id = RootFingerId(FingerId {
id: pointer_info.pointerId,
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,
position,
kind: if let PT_TOUCH = pointer_info.pointerType {
PointerKind::Touch(finger_id)
} else {
PointerKind::Unknown
},
},
});
userdata.send_event(Event::WindowEvent {
window_id,
event: WindowEvent::PointerButton {
device_id: None,
state: Pressed,
position,
button: if let PT_TOUCH = pointer_info.pointerType {
ButtonSource::Touch { finger_id, force }
} else {
ButtonSource::Unknown(0)
},
},
});
} else if util::has_flag(pointer_info.pointerFlags, POINTER_FLAG_UP) {
userdata.send_event(Event::WindowEvent {
window_id,
event: WindowEvent::PointerButton {
device_id: None,
state: Released,
position,
button: if let PT_TOUCH = pointer_info.pointerType {
ButtonSource::Touch { finger_id, force }
} else {
ButtonSource::Unknown(0)
},
},
});
userdata.send_event(Event::WindowEvent {
window_id,
event: WindowEvent::PointerLeft {
device_id: None,
position: Some(position),
kind: if let PT_TOUCH = pointer_info.pointerType {
PointerKind::Touch(finger_id)
} else {
PointerKind::Unknown
},
},
});
} else if util::has_flag(pointer_info.pointerFlags, POINTER_FLAG_UPDATE) {
userdata.send_event(Event::WindowEvent {
window_id,
event: WindowEvent::PointerMoved {
device_id: None,
position,
source: if let PT_TOUCH = pointer_info.pointerType {
PointerSource::Touch { finger_id, force }
} else {
PointerSource::Unknown
},
},
});
} else {
continue;
}
}
unsafe { SkipPointerFrameMessages(pointer_id) };
@ -2431,7 +2582,7 @@ unsafe extern "system" fn thread_event_target_callback(
}
unsafe fn handle_raw_input(userdata: &ThreadMsgTargetData, data: RAWINPUT) {
use crate::event::DeviceEvent::{Button, Key, MouseMotion, MouseWheel};
use crate::event::DeviceEvent::{Button, Key, MouseWheel, PointerMotion};
use crate::event::ElementState::{Pressed, Released};
use crate::event::MouseScrollDelta::LineDelta;
@ -2447,7 +2598,7 @@ unsafe fn handle_raw_input(userdata: &ThreadMsgTargetData, data: RAWINPUT) {
if x != 0.0 || y != 0.0 {
userdata.send_event(Event::DeviceEvent {
device_id,
event: MouseMotion { delta: (x, y) },
event: PointerMotion { delta: (x, y) },
});
}
}