Use himetric values in WM_POINTER events (#1053)

* Use himetric location for WM_POINTER events

* Ran rustfmt
This commit is contained in:
dam4rus 2019-07-26 09:12:06 +02:00 committed by Hal Gentz
parent a28b60578d
commit 454d4190b7

View file

@ -39,7 +39,7 @@ use winapi::{
}, },
um::{ um::{
commctrl, libloaderapi, ole2, processthreadsapi, winbase, commctrl, libloaderapi, ole2, processthreadsapi, winbase,
winnt::{LONG, LPCSTR, SHORT}, winnt::{HANDLE, LONG, LPCSTR, SHORT},
winuser, winuser,
}, },
}; };
@ -71,12 +71,19 @@ type GetPointerFrameInfoHistory = unsafe extern "system" fn(
) -> BOOL; ) -> BOOL;
type SkipPointerFrameMessages = unsafe extern "system" fn(pointerId: UINT) -> BOOL; type SkipPointerFrameMessages = unsafe extern "system" fn(pointerId: UINT) -> BOOL;
type GetPointerDeviceRects = unsafe extern "system" fn(
device: HANDLE,
pointerDeviceRect: *mut RECT,
displayRect: *mut RECT,
) -> BOOL;
lazy_static! { lazy_static! {
static ref GET_POINTER_FRAME_INFO_HISTORY: Option<GetPointerFrameInfoHistory> = static ref GET_POINTER_FRAME_INFO_HISTORY: Option<GetPointerFrameInfoHistory> =
get_function!("user32.dll", GetPointerFrameInfoHistory); get_function!("user32.dll", GetPointerFrameInfoHistory);
static ref SKIP_POINTER_FRAME_MESSAGES: Option<SkipPointerFrameMessages> = static ref SKIP_POINTER_FRAME_MESSAGES: Option<SkipPointerFrameMessages> =
get_function!("user32.dll", SkipPointerFrameMessages); get_function!("user32.dll", SkipPointerFrameMessages);
static ref GET_POINTER_DEVICE_RECTS: Option<GetPointerDeviceRects> =
get_function!("user32.dll", GetPointerDeviceRects);
} }
pub(crate) struct SubclassInput<T> { pub(crate) struct SubclassInput<T> {
@ -1484,9 +1491,14 @@ unsafe extern "system" fn public_window_callback<T>(
} }
winuser::WM_POINTERDOWN | winuser::WM_POINTERUPDATE | winuser::WM_POINTERUP => { winuser::WM_POINTERDOWN | winuser::WM_POINTERUPDATE | winuser::WM_POINTERUP => {
if let (Some(GetPointerFrameInfoHistory), Some(SkipPointerFrameMessages)) = ( if let (
Some(GetPointerFrameInfoHistory),
Some(SkipPointerFrameMessages),
Some(GetPointerDeviceRects),
) = (
*GET_POINTER_FRAME_INFO_HISTORY, *GET_POINTER_FRAME_INFO_HISTORY,
*SKIP_POINTER_FRAME_MESSAGES, *SKIP_POINTER_FRAME_MESSAGES,
*GET_POINTER_DEVICE_RECTS,
) { ) {
let pointer_id = LOWORD(wparam as DWORD) as UINT; let pointer_id = LOWORD(wparam as DWORD) as UINT;
let mut entries_count = 0 as UINT; let mut entries_count = 0 as UINT;
@ -1519,17 +1531,44 @@ unsafe extern "system" fn public_window_callback<T>(
// The information retrieved appears in reverse chronological order, with the most recent entry in the first // The information retrieved appears in reverse chronological order, with the most recent entry in the first
// row of the returned array // row of the returned array
for pointer_info in pointer_infos.iter().rev() { for pointer_info in pointer_infos.iter().rev() {
let mut device_rect: RECT = mem::uninitialized();
let mut display_rect: RECT = mem::uninitialized();
if (GetPointerDeviceRects(
pointer_info.sourceDevice,
&mut device_rect as *mut _,
&mut display_rect as *mut _,
)) == 0
{
continue;
}
// For the most precise himetric to pixel conversion we calculate the ratio between the resolution
// of the display device (pixel) and the touch device (himetric).
let himetric_to_pixel_ratio_x = (display_rect.right - display_rect.left) as f64
/ (device_rect.right - device_rect.left) as f64;
let himetric_to_pixel_ratio_y = (display_rect.bottom - display_rect.top) as f64
/ (device_rect.bottom - device_rect.top) as f64;
// ptHimetricLocation's origin is 0,0 even on multi-monitor setups.
// On multi-monitor setups we need to translate the himetric location to the rect of the
// display device it's attached to.
let x = display_rect.left as f64
+ pointer_info.ptHimetricLocation.x as f64 * himetric_to_pixel_ratio_x;
let y = display_rect.top as f64
+ pointer_info.ptHimetricLocation.y as f64 * himetric_to_pixel_ratio_y;
let mut location = POINT { let mut location = POINT {
x: pointer_info.ptPixelLocation.x, x: x.floor() as i32,
y: pointer_info.ptPixelLocation.y, y: y.floor() as i32,
}; };
if winuser::ScreenToClient(window, &mut location as *mut _) == 0 { if winuser::ScreenToClient(window, &mut location as *mut _) == 0 {
continue; continue;
} }
let x = location.x as f64; let x = location.x as f64 + x.fract();
let y = location.y as f64; let y = location.y as f64 + y.fract();
let location = LogicalPosition::from_physical((x, y), dpi_factor); let location = LogicalPosition::from_physical((x, y), dpi_factor);
subclass_input.send_event(Event::WindowEvent { subclass_input.send_event(Event::WindowEvent {
window_id: RootWindowId(WindowId(window)), window_id: RootWindowId(WindowId(window)),