本文记录在 WPF 开启 Pointer 消息的坑
屏幕键盘
启用了Pointer之后,调用Textbox.Focus(),起不来屏幕键盘,必须点在它之上才行,触摸在它之上才行
使用屏幕绝对坐标而不是窗口坐标
默认 Pointer 消息是使用屏幕绝对坐标而不是窗口坐标
可能存在获取 Stylus 事件时触摸点不准,此时可以通过获取 Touch 代替,详细请看 WPF will have a touch offset after trun on the WM_Pointer message · Issue #3360 · dotnet/wpf 此问题应该在 Fix raw stylus data to support per-monitor DPI by rladuca · Pull Request #2891 · dotnet/wpf 修复
开启 Pointer 消息之后无法隐藏触摸反馈点
开启 Pointer 消息之后,调用 Stylus.IsPressAndHoldEnabled="False"
无效
在没有开启 Pointer 消息,将会在 System.Windows.Interop.HwndSource 的 Initialize 方法通过判断是否开启 Pointer 消息执行 HwndStylusInputProvider 逻辑
if (StylusLogic.IsStylusAndTouchSupportEnabled)
{
// Choose between Wisp and Pointer stacks
if (StylusLogic.IsPointerStackEnabled)
{
// 开启 Pointer 的逻辑
_stylus = new SecurityCriticalDataClass<IStylusInputProvider>(new HwndPointerInputProvider(this));
}
else
{
_stylus = new SecurityCriticalDataClass<IStylusInputProvider>(new HwndStylusInputProvider(this));
}
}
在 HwndStylusInputProvider 将会读取 IsPressAndHoldEnabledProperty 属性,然后使用 WM_TABLET_QUERYSYSTEMGESTURESTATUS 返回 1 的方式告诉系统不显示触摸反馈点。也就是 WPF 隐藏触摸反馈点是通过 How do I disable the press-and-hold gesture for my window 的方法
如果不设置 Stylus.IsPressAndHoldEnabled="False"
也可以自己手动监听消息,在消息 WM_TABLET_QUERYSYSTEMGESTURESTATUS 里面返回 1 就可以告诉系统不显示触摸反馈点
private IntPtr Hook(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
{
const int WM_TABLET_DEFBASE =0x02C0;
const int WM_TABLET_QUERYSYSTEMGESTURESTATUS = WM_TABLET_DEFBASE + 12;
const int WM_TABLET_FLICK = WM_TABLET_DEFBASE + 11;
if (msg == WM_TABLET_QUERYSYSTEMGESTURESTATUS)
{
uint flags = 0;
flags |= TABLET_PRESSANDHOLD_DISABLED;
flags |= TABLET_TAPFEEDBACK_DISABLED;
flags |= TABLET_TOUCHUI_FORCEON;
flags |= TABLET_TOUCHUI_FORCEOFF;
flags |= TABLET_FLICKS_DISABLED;
handled = true;
return new IntPtr(flags);
}
else if (msg == WM_TABLET_FLICK)
{
handled = true;
return new IntPtr(1);
}
return IntPtr.Zero;
}
private const uint TABLET_PRESSANDHOLD_DISABLED = 0x00000001;
private const uint TABLET_TAPFEEDBACK_DISABLED = 0x00000008;
private const uint TABLET_TOUCHUI_FORCEON = 0x00000100;
private const uint TABLET_TOUCHUI_FORCEOFF = 0x00000200;
private const uint TABLET_FLICKS_DISABLED = 0x00010000;
但如果开启了 Pointer 消息,那么这个机制将会无效,即使依然是手动监听消息,如 https://github.com/lindexi/lindexi_gd/tree/81b2a63a/KemjawyecawDurbahelal 的代码,也是无效的
问题报告给了 WPF 官方,请看 WPF can not work well with set IsPressAndHoldEnabled to false when enable pointer message · Issue #3379 · dotnet/wpf 但预计不会在 WPF 中修复,原因是这是 Windows 的 WM_Pointer 机制的坑,和 WPF 其实没有关系
另一个解决方法是在关闭系统全局触摸反馈点,关闭方法请看 3 Ways to Enable or Disable Touch Feedback in Windows 10
更多请看
How do I disable the press-and-hold gesture for my window
WM_TABLET_QUERYSYSTEMGESTURESTATUS message (Tpcshrd.h)
WM_TABLET_FLICK message (Tpcshrd.h)
c# - Calling SetGestureConfig method affects onmousemove override of control - Stack Overflow
SetGestureConfig 函数-中文整理_Augusdi的专栏-CSDN博客
更多阅读
本文会经常更新,请阅读原文: https://dotnet-campus.github.io//post/WPF-%E5%BC%80%E5%90%AFPointer%E6%B6%88%E6%81%AF%E5%AD%98%E5%9C%A8%E7%9A%84%E5%9D%91.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 lindexi (包含链接: https://dotnet-campus.github.io/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 。