WPF 编写一个测试 WM_TOUCH 触摸消息延迟的应用
我听说在 Win10 到 Win11 的系统版本左右,微软加上了一大波触摸性能优化,准确来说是 HID 性能优化。我想测试一下在这些系统下,采用从 Windows 消息接收到 WM_TOUCH 触摸消息的延迟将会是多少。本文将告诉大家我编写的测试应用
为了能够让 WPF 窗口能接收到 WM_TOUCH 触摸消息,首先需要将 WPF 默认走的实时触摸机制禁用,否则两个触摸接收方法将会打架,在 Windows 层将不会调度 WM_TOUCH 触摸消息给到 WPF 窗口。根据 WPF 禁用实时触摸 提供的方法禁用实时触摸,如果没有禁用 WPF 的 RealTimeStylus 实时触摸,就无法拿到 WM_TOUCH 消息,这是因为两套触摸机制将会打架。在 Windows 系统层发现开启了实时触摸之后,将不会调度 WM_TOUCH 消息给到应用窗口
在 App 构造函数加上以下代码用来禁用 RealTimeStylus 实时触摸
public partial class App : Application
{
public App()
{
AppContext.SetSwitch("Switch.System.Windows.Input.Stylus.DisableStylusAndTouchSupport", true);
}
}
为了更加方便调用 Win32 函数,按照 dotnet 使用 CsWin32 库简化 Win32 函数调用逻辑 博客的方法,安装 Microsoft.Windows.CsWin32 库用来减少编写 PInvoke 的定义方法
这里采用 .NET 7 的 WPF 项目,可以编辑 csproj 用来安装 Microsoft.Windows.CsWin32 库,十分方便,修改 csproj 项目文件为以下代码
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net7.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Windows.CsWin32" PrivateAssets="all" Version="0.2.63-beta" />
</ItemGroup>
</Project>
根据 dotnet 使用 CsWin32 库简化 Win32 函数调用逻辑 博客提到的方法,需要在项目新建一个名为 NativeMethods.txt 的文件,在此文件里面写入需要使用的 Win32 函数。此时 CsWin32 库将使用 SourceGenerator 技术生成这些写入的 Win32 函数的定义
下面是在 NativeMethods.txt 写入的代码
RegisterTouchWindow
GetMessageTime
GetTouchInputInfo
进入到 MainWindow 函数里面监听 SourceInitialized 事件。在 WPF 框架里面,约定了在 SourceInitialized 事件里就是创建完成了 Win32 窗口之后触发的,在此事件里面使用 Win32 窗口相关方法是安全的
public MainWindow()
{
InitializeComponent();
SourceInitialized += MainWindow_SourceInitialized;
}
private void MainWindow_SourceInitialized(object? sender, EventArgs e)
{
}
在 MainWindow_SourceInitialized 方法里面调用 RegisterTouchWindow 用来注册 WM_Touch 消息,代码如下
var windowInteropHelper = new WindowInteropHelper(this);
var hwnd = windowInteropHelper.Handle;
// 如果启用了 TWF_WANTPALM ,则不会缓冲触摸输入中的数据包,并且不会在将数据包发送到应用程序之前执行手掌检测。 如果要在处理 WM_TOUCH 消息时实现最小延迟,则启用 TWF_WANTPALM 最有用
PInvoke.RegisterTouchWindow(new HWND(hwnd), REGISTER_TOUCH_WINDOW_FLAGS.TWF_WANTPALM);
这里传入了 TWF_WANTPALM 参数,传入这个参数可以减少触摸消息延迟
接着根据 WPF 添加窗口消息钩子方法 博客接收 Windows 消息,代码如下
private void MainWindow_SourceInitialized(object? sender, EventArgs e)
{
var windowInteropHelper = new WindowInteropHelper(this);
var hwnd = windowInteropHelper.Handle;
// 如果启用了 TWF_WANTPALM ,则不会缓冲触摸输入中的数据包,并且不会在将数据包发送到应用程序之前执行手掌检测。 如果要在处理 WM_TOUCH 消息时实现最小延迟,则启用 TWF_WANTPALM 最有用
PInvoke.RegisterTouchWindow(new HWND(hwnd), REGISTER_TOUCH_WINDOW_FLAGS.TWF_WANTPALM);
HwndSource source = HwndSource.FromHwnd(hwnd)!; // 这里在 SourceInitialized 一定是存在的
source.AddHook(Hook);
}
private IntPtr Hook(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
{
// 忽略代码
}
在 Hook 函数里面,判断收到的消息是否 WM_Touch 消息,如果是那就记录当前的消息时间,用来判断两条 WM_Touch 消息之间的延迟
private IntPtr Hook(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
{
if (msg == WM_TOUCH)
{
// 触摸进来的
var currentMessageTime = PInvoke.GetMessageTime();
if (_lastTouchMessageTime != 0)
{
var delay = currentMessageTime - _lastTouchMessageTime;
// 这就是消息的延迟
}
_lastTouchMessageTime = currentMessageTime;
}
return IntPtr.Zero;
}
private int _lastTouchMessageTime;
private const int WM_TOUCH = 0x0240;
在自己的电脑上运行代码,即可用来测试 WM_Touch 触摸的延迟
我使用以上代码在我的 Demo 上测试和在我的一个复杂项目上测试,结果就是在 Demo 上的触摸延迟是 WM_Touch 和 RealTimeStylus 实时触摸几乎一样。但是在复杂的项目上,由于 Windows 消息太多或者是主线程忙碌,触摸延迟是 WM_Touch 比 RealTimeStylus 实时触摸大许多
可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin f006732c9f97f370f5c063de024125b201313bd3
以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码
git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin f006732c9f97f370f5c063de024125b201313bd3
获取代码之后,进入 WalqujemjelNekokelhuwererere 文件夹
更多触摸请看 WPF 触摸相关
WPF 编写一个测试 WM_TOUCH 触摸消息延迟的应用的更多相关文章
- 通过 AppSwitch 禁用 WPF 内置的触摸让 WPF 程序可以处理 Windows 触摸消息
原文:通过 AppSwitch 禁用 WPF 内置的触摸让 WPF 程序可以处理 Windows 触摸消息 WPF 框架自己实现了一套触摸机制,但同一窗口只能支持一套触摸机制,于是这会禁用系统的触摸消 ...
- python+pytest接口自动化(12)-自动化用例编写思路 (使用pytest编写一个测试脚本)
经过之前的学习铺垫,我们尝试着利用pytest框架编写一条接口自动化测试用例,来厘清接口自动化用例编写的思路. 我们在百度搜索天气查询,会出现如下图所示结果: 接下来,我们以该天气查询接口为例,编写接 ...
- wpf编写一个简单的PDF转换的程序
wpf 调用Spire.Pdf将PDF文件转换为其他文件模式 首先在Nuget里下载该第三方包Spire.Pdf. 然后可以编写程序 //这里我调用的是解析成流模式,这是因为我要使用ProgressB ...
- 按要求编写一个Java应用程序: (1)定义一个类,描述一个矩形,包含有长、宽两种属性,和计算面积方法。 (2)编写一个类,继承自矩形类,同时该类描述长方体,具有长、宽、高属性, 和计算体积的方法。 (3)编写一个测试类,对以上两个类进行测试,创建一个长方体,定义其长、 宽、高,输出其底面积和体积。
package jvxing; public class Jvxing { //成员变量 private double width; private double chang; public doub ...
- 28.按要求编写一个Java应用程序: (1)定义一个类,描述一个矩形,包含有长、宽两种属性,和计算面积方法。 (2)编写一个类,继承自矩形类,同时该类描述长方体,具有长、宽、高属性, 和计算体积的方法。 (3)编写一个测试类,对以上两个类进行测试,创建一个长方体,定义其长、 宽、高,输出其底面积和体积。
//矩形父类 package d922A; public class Rect { private double l,w; Rect(double c,double k) { l=c; w=k; } ...
- 编写一个通用的Makefile文件
1.1在这之前,我们需要了解程序的编译过程 a.预处理:检查语法错误,展开宏,包含头文件等 b.编译:*.c-->*.S c.汇编:*.S-->*.o d.链接:.o +库文件=*.exe ...
- 利用javafx编写一个时钟制作程序
1.首先创建一个时钟类,用于编写时钟的各种特有属性 package javaclock; /** * * @author admin */import java.util.Calendar;impor ...
- Prism for WPF 搭建一个简单的模块化开发框架(五)添加聊天、消息模块
原文:Prism for WPF 搭建一个简单的模块化开发框架(五)添加聊天.消息模块 中秋节假期没事继续搞了搞 做了各聊天的模块,需要继续优化 第一步画页面 页面参考https://github.c ...
- 22.编写一个类A,该类创建的对象可以调用方法showA输出小写的英文字母表。然后再编写一个A类的子类B,子类B创建的对象不仅可以调用方法showA输出小写的英文字母表,而且可以调用子类新增的方法showB输出大写的英文字母表。最后编写主类C,在主类的main方法 中测试类A与类B。
22.编写一个类A,该类创建的对象可以调用方法showA输出小写的英文字母表.然后再编写一个A类的子类B,子类B创建的对象不仅可以调用方法showA输出小写的英文字母表,而且可以调用子类新增的方法sh ...
- Java基础-继承-编写一个Java应用程序,设计一个汽车类Vehicle,包含的属性有车轮个数 wheels和车重weight。小车类Car是Vehicle的子类,其中包含的属性有载人数 loader。卡车类Truck是Car类的子类,其中包含的属性有载重量payload。每个 类都有构造方法和输出相关数据的方法。最后,写一个测试类来测试这些类的功 能。
#29.编写一个Java应用程序,设计一个汽车类Vehicle,包含的属性有车轮个数 wheels和车重weight.小车类Car是Vehicle的子类,其中包含的属性有载人数 loader.卡车类T ...
随机推荐
- python高级技术(线程)
一 线程理论 1 有了进程为什么要有线程 进程有很多优点,它提供了多道编程,让我们感觉我们每个人都拥有自己的CPU和其他资源,可以提高计算机的利用率.很多人就不理解了,既然进程这么优秀,为什么还要线程 ...
- C#中字典集合的两种遍历
记录一下 Dictionary<string, string> dictionary = new Dictionary<string,string>(); foreach (s ...
- C# AES CBC模式 加密和解密
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.S ...
- Fastjson反序列化分析
依赖 先研究1.2.24版本的,版本高了就有waf了,不过也能绕,高版本以后再说 <dependency> <groupId>com.alibaba</groupId&g ...
- 绚烂之境:Python Rich,让终端输出更炫酷!
转载请注明出处️ 作者:测试蔡坨坨 原文链接:caituotuo.top/c8c7bd95.html 初识rich 你好,我是测试蔡坨坨. 在代码的世界里,每一行都是一个故事,每一个变量都是一个角色, ...
- 我们正在被 DDoS 攻击,但是我们啥也不干,随便攻击...
最近,一场激烈的攻防大战在网络世界悄然上演. 主角不是什么国家安全局或者黑客组织,而是一家名不见经传的创业公司--TablePlus. DDoS 攻击者们摩拳擦掌,跃跃欲试.他们从四面八方蜂拥而至,誓 ...
- python---nltk工具包安装
先在pycharm里安装nltk cmd进入Python输入 import nltk nltk.download()如果下载失败在github上下载语料库:https://github.com/nlt ...
- [Android开发学iOS系列] 删除storyboard需要几步
删除iOS项目中的storyboard 删除项目中的storyboard, (变成一个纯代码的iOS UIKit项目), 需要几步? 找到storyboard, 删掉它. 直接用ViewControl ...
- 【福利活动】深度体验OpenHarmony对接华为云IoT
本文主要介绍基于OpenHarmony 3.0来接入IoTDA,以BearPi-HM_Nano开发板为例,使用huaweicloud_iot_link SDK对接华为云物联网平台的简单流程.文末为 ...
- 稀疏镜像在OpenHarmony上的应用
一.稀疏镜像升级背景 常用系统镜像格式为原始镜像,即RAW格式.镜像体积比较大,在烧录固件或者升级固件时比较耗时,而且在移动设备升级过程时比较耗费流量.为此,将原始镜像用稀疏描述,可以大大地缩减镜像体 ...