diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dbb42c9..055446a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - On X11, performance is improved when rapidly calling `Window::set_cursor_icon`. - On iOS, fix improper `msg_send` usage that was UB and/or would break if `!` is stabilized. - On Windows, unset `maximized` when manually changing the window's position or size. +- On Windows, add touch pressure information for touch events. # 0.20.0 Alpha 3 (2019-08-14) diff --git a/FEATURES.md b/FEATURES.md index e8927957..cd3712b9 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -194,7 +194,7 @@ Legend: |Cursor grab |✔️ |▢[#165] |▢[#242] |❌[#306] |**N/A**|**N/A**|✔️ | |Cursor icon |✔️ |✔️ |✔️ |❌[#306] |**N/A**|**N/A**|❌ | |Touch events |✔️ |❌ |✔️ |✔️ |✔️ |✔️ |✔️ | -|Touch pressure |❌ |❌ |❌ |❌ |❌ |✔️ |❌ | +|Touch pressure |✔️ |❌ |❌ |❌ |❌ |✔️ |❌ | |Multitouch |✔️ |❌ |✔️ |✔️ |❓ |✔️ |❌ | |Keyboard events |✔️ |✔️ |✔️ |✔️ |❓ |❌ |✔️ | |Drag & Drop |▢[#720] |▢[#720] |▢[#720] |❌[#306] |**N/A**|**N/A**|❓ | diff --git a/src/event.rs b/src/event.rs index 5b515086..fc894d97 100644 --- a/src/event.rs +++ b/src/event.rs @@ -333,7 +333,7 @@ pub struct Touch { /// /// ## Platform-specific /// - /// - Only available on **iOS** 9.0+. + /// - Only available on **iOS** 9.0+ and **Windows** 8+. pub force: Option, /// Unique identifier of a finger. pub id: u64, diff --git a/src/platform_impl/windows/dpi.rs b/src/platform_impl/windows/dpi.rs index 548c2608..1a5fa13c 100644 --- a/src/platform_impl/windows/dpi.rs +++ b/src/platform_impl/windows/dpi.rs @@ -1,6 +1,6 @@ #![allow(non_snake_case, unused_unsafe)] -use std::{mem, os::raw::c_void, sync::Once}; +use std::sync::Once; use winapi::{ shared::{ diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 749c0d5d..57e51b21 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -46,7 +46,7 @@ use winapi::{ use crate::{ dpi::{LogicalPosition, LogicalSize, PhysicalSize}, - event::{DeviceEvent, Event, KeyboardInput, StartCause, Touch, TouchPhase, WindowEvent}, + event::{DeviceEvent, Event, Force, KeyboardInput, StartCause, Touch, TouchPhase, WindowEvent}, event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW}, platform_impl::platform::{ dpi::{ @@ -77,6 +77,12 @@ type GetPointerDeviceRects = unsafe extern "system" fn( displayRect: *mut RECT, ) -> BOOL; +type GetPointerTouchInfo = + unsafe extern "system" fn(pointerId: UINT, touchInfo: *mut winuser::POINTER_TOUCH_INFO) -> BOOL; + +type GetPointerPenInfo = + unsafe extern "system" fn(pointId: UINT, penInfo: *mut winuser::POINTER_PEN_INFO) -> BOOL; + lazy_static! { static ref GET_POINTER_FRAME_INFO_HISTORY: Option = get_function!("user32.dll", GetPointerFrameInfoHistory); @@ -84,6 +90,10 @@ lazy_static! { get_function!("user32.dll", SkipPointerFrameMessages); static ref GET_POINTER_DEVICE_RECTS: Option = get_function!("user32.dll", GetPointerDeviceRects); + static ref GET_POINTER_TOUCH_INFO: Option = + get_function!("user32.dll", GetPointerTouchInfo); + static ref GET_POINTER_PEN_INFO: Option = + get_function!("user32.dll", GetPointerPenInfo); } pub(crate) struct SubclassInput { @@ -852,6 +862,13 @@ pub(crate) fn subclass_window(window: HWND, subclass_input: SubclassInput) assert_eq!(subclass_result, 1); } +fn normalize_pointer_pressure(pressure: u32) -> Option { + match pressure { + 1..=1024 => Some(Force::Normalized(pressure as f64 / 1024.0)), + _ => None, + } +} + /// Any window whose callback is configured to this function will have its events propagated /// through the events loop of the thread the window was created in. // @@ -1499,7 +1516,7 @@ unsafe extern "system" fn public_window_callback( continue; }, location, - force: None, // TODO + force: None, // WM_TOUCH doesn't support pressure information id: input.dwID as u64, device_id: DEVICE_ID, }), @@ -1551,18 +1568,21 @@ unsafe extern "system" fn public_window_callback( // 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 mut device_rect: RECT = mem::uninitialized(); - let mut display_rect: RECT = mem::uninitialized(); + let mut device_rect = mem::MaybeUninit::uninit(); + let mut display_rect = mem::MaybeUninit::uninit(); if (GetPointerDeviceRects( pointer_info.sourceDevice, - &mut device_rect as *mut _, - &mut display_rect as *mut _, + device_rect.as_mut_ptr(), + display_rect.as_mut_ptr(), )) == 0 { continue; } + let device_rect = device_rect.assume_init(); + let display_rect = display_rect.assume_init(); + // 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 @@ -1587,6 +1607,38 @@ unsafe extern "system" fn public_window_callback( continue; } + let force = match pointer_info.pointerType { + winuser::PT_TOUCH => { + let mut touch_info = mem::MaybeUninit::uninit(); + GET_POINTER_TOUCH_INFO.and_then(|GetPointerTouchInfo| { + match GetPointerTouchInfo( + pointer_info.pointerId, + touch_info.as_mut_ptr(), + ) { + 0 => None, + _ => normalize_pointer_pressure( + touch_info.assume_init().pressure, + ), + } + }) + } + winuser::PT_PEN => { + let mut pen_info = mem::MaybeUninit::uninit(); + GET_POINTER_PEN_INFO.and_then(|GetPointerPenInfo| { + match GetPointerPenInfo( + pointer_info.pointerId, + pen_info.as_mut_ptr(), + ) { + 0 => None, + _ => { + normalize_pointer_pressure(pen_info.assume_init().pressure) + } + } + }) + } + _ => None, + }; + let x = location.x as f64 + x.fract(); let y = location.y as f64 + y.fract(); let location = LogicalPosition::from_physical((x, y), dpi_factor); @@ -1604,7 +1656,7 @@ unsafe extern "system" fn public_window_callback( continue; }, location, - force: None, // TODO + force, id: pointer_info.pointerId as u64, device_id: DEVICE_ID, }),