Add touch pressure information for touch events on Windows (#1134)

* Add touch pressure information for touch events on Windows

* Modified CHANGELOG.md and FEATURES.md to reflect changes

* Updated documentation of struct Touch to reflect changes

* Replaced mem::uninitalized() with mem::MaybeUninit
Fixed warnings in platform_impl/windows/dpi.rs
This commit is contained in:
dam4rus 2019-09-09 20:15:49 +02:00 committed by Osspial
parent 3273c14dea
commit 068d114740
5 changed files with 63 additions and 10 deletions

View file

@ -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)

View file

@ -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**|❓ |

View file

@ -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<Force>,
/// Unique identifier of a finger.
pub id: u64,

View file

@ -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::{

View file

@ -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<GetPointerFrameInfoHistory> =
get_function!("user32.dll", GetPointerFrameInfoHistory);
@ -84,6 +90,10 @@ lazy_static! {
get_function!("user32.dll", SkipPointerFrameMessages);
static ref GET_POINTER_DEVICE_RECTS: Option<GetPointerDeviceRects> =
get_function!("user32.dll", GetPointerDeviceRects);
static ref GET_POINTER_TOUCH_INFO: Option<GetPointerTouchInfo> =
get_function!("user32.dll", GetPointerTouchInfo);
static ref GET_POINTER_PEN_INFO: Option<GetPointerPenInfo> =
get_function!("user32.dll", GetPointerPenInfo);
}
pub(crate) struct SubclassInput<T> {
@ -852,6 +862,13 @@ pub(crate) fn subclass_window<T>(window: HWND, subclass_input: SubclassInput<T>)
assert_eq!(subclass_result, 1);
}
fn normalize_pointer_pressure(pressure: u32) -> Option<Force> {
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<T>(
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<T>(
// 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<T>(
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<T>(
continue;
},
location,
force: None, // TODO
force,
id: pointer_info.pointerId as u64,
device_id: DEVICE_ID,
}),