Handle WM_POINTER* events in favor of WM_TOUCH

Fixes #975
This commit is contained in:
Kalmár Róbert 2019-07-05 18:37:25 +02:00
parent 93c36ccf78
commit 026b331ba5
4 changed files with 114 additions and 82 deletions

View file

@ -1,3 +1,4 @@
#![allow(non_snake_case)]
//! An events loop on Win32 is a background thread.
//!
//! Creating an events loop spawns a thread and blocks it in a permanent Win32 events loop.
@ -62,6 +63,22 @@ use crate::{
window::WindowId as RootWindowId,
};
type GetPointerFrameInfoHistory = unsafe extern "system" fn(
pointerId: UINT,
entriesCount: *mut UINT,
pointerCount: *mut UINT,
pointerInfo: *mut winuser::POINTER_INFO,
) -> BOOL;
type SkipPointerFrameMessages = unsafe extern "system" fn(pointerId: UINT) -> BOOL;
lazy_static! {
static ref GET_POINTER_FRAME_INFO_HISTORY: Option<GetPointerFrameInfoHistory> =
get_function!("user32.dll", GetPointerFrameInfoHistory);
static ref SKIP_POINTER_FRAME_MESSAGES: Option<SkipPointerFrameMessages> =
get_function!("user32.dll", SkipPointerFrameMessages);
}
pub(crate) struct SubclassInput<T> {
pub window_state: Arc<Mutex<WindowState>>,
pub event_loop_runner: EventLoopRunnerShared<T>,
@ -1458,60 +1475,66 @@ unsafe extern "system" fn public_window_callback<T>(
}
winuser::WM_POINTERDOWN | winuser::WM_POINTERUPDATE | winuser::WM_POINTERUP => {
let pointer_id = LOWORD(wparam as DWORD) as UINT;
let mut entries_count = 0 as UINT;
let mut pointers_count = 0 as UINT;
if winuser::GetPointerFrameInfoHistory(
pointer_id,
&mut entries_count as *mut _,
&mut pointers_count as *mut _,
std::ptr::null_mut(),
) == 0
{
return 0;
}
if let (Some(GetPointerFrameInfoHistory), Some(SkipPointerFrameMessages)) = (
*GET_POINTER_FRAME_INFO_HISTORY,
*SKIP_POINTER_FRAME_MESSAGES,
) {
let pointer_id = LOWORD(wparam as DWORD) as UINT;
let mut entries_count = 0 as UINT;
let mut pointers_count = 0 as UINT;
if GetPointerFrameInfoHistory(
pointer_id,
&mut entries_count as *mut _,
&mut pointers_count as *mut _,
std::ptr::null_mut(),
) == 0
{
return 0;
}
let pointer_info_count = (entries_count * pointers_count) as usize;
let mut pointer_infos = Vec::with_capacity(pointer_info_count);
pointer_infos.set_len(pointer_info_count);
if winuser::GetPointerFrameInfoHistory(
pointer_id,
&mut entries_count as *mut _,
&mut pointers_count as *mut _,
pointer_infos.as_mut_ptr(),
) == 0
{
return 0;
}
let pointer_info_count = (entries_count * pointers_count) as usize;
let mut pointer_infos = Vec::with_capacity(pointer_info_count);
pointer_infos.set_len(pointer_info_count);
if GetPointerFrameInfoHistory(
pointer_id,
&mut entries_count as *mut _,
&mut pointers_count as *mut _,
pointer_infos.as_mut_ptr(),
) == 0
{
return 0;
}
let dpi_factor = hwnd_scale_factor(window);
// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getpointerframeinfohistory
// The information retrieved appears in reverse chronological order, with the most recent entry in the first
// row of the returned array
for pointer_info in pointer_infos.iter().rev() {
let x = pointer_info.ptPixelLocation.x as f64;
let y = pointer_info.ptPixelLocation.y as f64;
let location = LogicalPosition::from_physical((x, y), dpi_factor);
subclass_input.send_event(Event::WindowEvent {
window_id: RootWindowId(WindowId(window)),
event: WindowEvent::Touch(Touch {
phase: if pointer_info.pointerFlags & winuser::POINTER_FLAG_DOWN != 0 {
TouchPhase::Started
} else if pointer_info.pointerFlags & winuser::POINTER_FLAG_UP != 0 {
TouchPhase::Ended
} else if pointer_info.pointerFlags & winuser::POINTER_FLAG_UPDATE != 0 {
TouchPhase::Moved
} else {
continue;
},
location,
id: pointer_info.pointerId as u64,
device_id: DEVICE_ID,
}),
});
}
let dpi_factor = hwnd_scale_factor(window);
// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getpointerframeinfohistory
// The information retrieved appears in reverse chronological order, with the most recent entry in the first
// row of the returned array
for pointer_info in pointer_infos.iter().rev() {
let x = pointer_info.ptPixelLocation.x as f64;
let y = pointer_info.ptPixelLocation.y as f64;
let location = LogicalPosition::from_physical((x, y), dpi_factor);
subclass_input.send_event(Event::WindowEvent {
window_id: RootWindowId(WindowId(window)),
event: WindowEvent::Touch(Touch {
phase: if pointer_info.pointerFlags & winuser::POINTER_FLAG_DOWN != 0 {
TouchPhase::Started
} else if pointer_info.pointerFlags & winuser::POINTER_FLAG_UP != 0 {
TouchPhase::Ended
} else if pointer_info.pointerFlags & winuser::POINTER_FLAG_UPDATE != 0
{
TouchPhase::Moved
} else {
continue;
},
location,
id: pointer_info.pointerId as u64,
device_id: DEVICE_ID,
}),
});
}
winuser::SkipPointerFrameMessages(pointer_id);
SkipPointerFrameMessages(pointer_id);
}
0
}