WPF 通过 RawInput 获取触摸消息
触摸在 Windows 下属于比较特殊的输入,不同于键盘和鼠标,键盘和鼠标可以通过全局 Hook 的方式获取到鼠标和键盘的输入消息。而触摸则没有直接的 Hook 的方法。如果期望自己的应用,可以在没有作为前台获取焦点的应用时,可以抓取到全局的触摸消息,抓取到其他应用程序的触摸输入,那么可以尝试使用 RawInput 的方式。通过 RawInput 的方式,可以让一个没有任何激活的、触摸直接命中的窗口的应用程序接收到全局的所有触摸消息
在上一篇博客,介绍了 WPF 使用 RawInput 接收裸数据 的方法,但是里面只是和大家演示了如何抓取鼠标和键盘消息
其实通过 RawInput 是可以在注册设备时,声明需要获取 TouchScreen 触摸屏输入,和 Pen 笔输入的。如以下代码
RawInputDevice.RegisterDevice(HidUsageAndPage.TouchScreen,
RawInputDeviceFlags.ExInputSink | RawInputDeviceFlags.DevNotify, hwnd);
RawInputDevice.RegisterDevice(HidUsageAndPage.Pen,
RawInputDeviceFlags.ExInputSink | RawInputDeviceFlags.DevNotify, hwnd);
以上的代码有所省略,没关系,大家可以在本文最后获取到所有的源代码
注册完成之后,即可在消息循环里面,收到 Windows 调度的消息。基于 rawinput-sharp: C# wrapper library for Raw Input 项目的 RawInput.Sharp 库的自动转换,即可通过判断 RawInputHidData 的方式,过滤出触摸的输入,代码如下
private IntPtr Hook(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
{
const int WM_INPUT = 0x00FF;
// You can read inputs by processing the WM_INPUT message.
if (msg == WM_INPUT)
{
// Create an RawInputData from the handle stored in lParam.
var data = RawInputData.FromHandle(lparam);
// The data will be an instance of either RawInputMouseData, RawInputKeyboardData, or RawInputHidData.
// They contain the raw input data in their properties.
switch (data)
{
case RawInputHidData hid:
Debug.WriteLine($"Hid {hid.Hid}");
TextBlock.Text = @$"DevicePath: {hid.Device.DevicePath}
VID:{hid.Device.VendorId:X2} PID:{hid.Device.ProductId:X2}
RawData:{hid.Hid}
";
if (hid is RawInputDigitizerData rawInputDigitizerData)
{
foreach (var rawInputDigitizerContact in rawInputDigitizerData.Contacts)
{
TextBlock.Text += rawInputDigitizerContact.ToString() + "\r\n";
}
}
break;
}
}
return IntPtr.Zero;
}
如上面代码,可以看到,在获取输入信息时,还可以获取到是哪个触摸框的输入,通过触摸框的 DevicePath 或者是 ProductId 等判断。同时通过 RawInput 的此方法,也可以用来支持双触摸屏同时进行触摸输入
以下是更多代码细节
在使用之前,安装 NuGet 包。如果是 SDK 风格的 csproj 项目格式,可以在项目文件添加以下代码安装
<ItemGroup>
<PackageReference Include="RawInput.Sharp" Version="0.0.2" />
</ItemGroup>
以下是 MainWindow.xaml.cs 的例子代码
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Linearstar.Windows.RawInput;
namespace RaicheadoherneanuNalokearwherno;
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
SourceInitialized += MainWindow_SourceInitialized;
}
private void MainWindow_SourceInitialized(object? sender, EventArgs e)
{
var windowInteropHelper = new WindowInteropHelper(this);
var hwnd = windowInteropHelper.Handle;
// Get the devices that can be handled with Raw Input.
var devices = RawInputDevice.GetDevices();
// register the keyboard device and you can register device which you need like mouse
RawInputDevice.RegisterDevice(HidUsageAndPage.Keyboard,
RawInputDeviceFlags.ExInputSink | RawInputDeviceFlags.NoLegacy, hwnd);
RawInputDevice.RegisterDevice(HidUsageAndPage.TouchScreen,
RawInputDeviceFlags.ExInputSink | RawInputDeviceFlags.DevNotify, hwnd);
RawInputDevice.RegisterDevice(HidUsageAndPage.Pen,
RawInputDeviceFlags.ExInputSink | RawInputDeviceFlags.DevNotify, hwnd);
HwndSource source = HwndSource.FromHwnd(hwnd);
source.AddHook(Hook);
}
private IntPtr Hook(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
{
const int WM_INPUT = 0x00FF;
// You can read inputs by processing the WM_INPUT message.
if (msg == WM_INPUT)
{
// Create an RawInputData from the handle stored in lParam.
var data = RawInputData.FromHandle(lparam);
// You can identify the source device using Header.DeviceHandle or just Device.
var sourceDeviceHandle = data.Header.DeviceHandle;
var sourceDevice = data.Device;
// The data will be an instance of either RawInputMouseData, RawInputKeyboardData, or RawInputHidData.
// They contain the raw input data in their properties.
switch (data)
{
case RawInputMouseData mouse:
Debug.WriteLine($"Mouse {mouse.Mouse}");
break;
case RawInputKeyboardData keyboard:
Debug.WriteLine(keyboard.Keyboard);
break;
case RawInputHidData hid:
Debug.WriteLine($"Hid {hid.Hid}");
TextBlock.Text = @$"DevicePath: {hid.Device.DevicePath}
VID:{hid.Device.VendorId:X2} PID:{hid.Device.ProductId:X2}
RawData:{hid.Hid}
";
if (hid is RawInputDigitizerData rawInputDigitizerData)
{
foreach (var rawInputDigitizerContact in rawInputDigitizerData.Contacts)
{
TextBlock.Text += rawInputDigitizerContact.ToString() + "\r\n";
}
}
break;
}
}
return IntPtr.Zero;
}
}
可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin bc08596b5f3b261ff621fcdb1426c953e3514b69
以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码
git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin bc08596b5f3b261ff621fcdb1426c953e3514b69
获取代码之后,进入 RaicheadoherneanuNalokearwherno 文件夹
更多 WPF 相关博客,请参阅我的 博客导航
WPF 通过 RawInput 获取触摸消息的更多相关文章
- 通过 AppSwitch 禁用 WPF 内置的触摸让 WPF 程序可以处理 Windows 触摸消息
原文:通过 AppSwitch 禁用 WPF 内置的触摸让 WPF 程序可以处理 Windows 触摸消息 WPF 框架自己实现了一套触摸机制,但同一窗口只能支持一套触摸机制,于是这会禁用系统的触摸消 ...
- 通过解读 WPF 触摸源码,分析 WPF 插拔设备触摸失效的问题(问题篇)
在 .NET Framework 4.7 以前,WPF 程序的触摸处理是基于操作系统组件但又自成一套的,这其实也为其各种各样的触摸失效问题埋下了伏笔.再加上它出现得比较早,触摸失效问题也变得更加难以解 ...
- 2019-11-29-WPF-从触摸消息转触摸事件
原文:2019-11-29-WPF-从触摸消息转触摸事件 title author date CreateTime categories WPF 从触摸消息转触摸事件 lindexi 2019-11- ...
- 2019-5-13-WPF-从触摸消息转触摸事件
title author date CreateTime categories WPF 从触摸消息转触摸事件 lindexi 2019-05-13 09:43:48 +0800 2019-05-12 ...
- WPF中的多点触摸事件
UIElement在WPF4下添加了很多支持多点触摸的事件,通过它们可以在硬件支持的情况下处理多点触摸,以下通过代码来说明通过处理这些事件,我们可以做些什么: 一.触摸相关的多种事件,跟鼠标事件是对应 ...
- WPF编程,获取句柄将外部程序嵌入到WPF界面。
原文:WPF编程,获取句柄将外部程序嵌入到WPF界面. 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net/qq_43307934/article/details ...
- 2dx关于js响应layer触摸消息的bug
cocos2dx关于js响应layer触摸消息的bug cocos2d-x 3.7 问题描述: 目前这个版本中(3.7),c++层的layer触摸消息只能通过消息的方式发送给js,不能像lua一样直接 ...
- XMPP系列(四)---发送和接收文字消息,获取历史消息功能
今天开始做到最主要的功能发送和接收消息.获取本地历史数据. 先上到目前为止的效果图: 首先是要在XMPPFramework.h中引入数据存储模块: //聊天记录模块的导入 # ...
- Xmpp获取离线消息
文章只是选取了其中一段,无XMPP基础的人可能看起来有点复杂; 假设我们注册了一个用户,用户名叫shimiso,那么我们如何让shimiso这个用户一登陆就取到离线消息呢? PPConnection. ...
- VS编程,WPF中,获取鼠标相对于当前屏幕坐标的一种方法
原文:VS编程,WPF中,获取鼠标相对于当前屏幕坐标的一种方法 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net/qq_43307934/article/det ...
随机推荐
- Rust Rocket简单入门
目录 简介 hello world 常用功能 动态路径 多个片段(segments) 静态文件服务器 简单WebAPI示例 添加依赖 实现接口 接口测试 参考链接 简介 Rust中最知名的两个web框 ...
- 记录--封装一个通过js调用的全局vue组件
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前言 在使用vue项目编写的时候,不可避免的会碰到需要时js api来调用组件进行显示的情况 例如饿了么element ui 的 Noti ...
- KingbaseES V8R6 等待事件之CLogControlLock
前言 Kingbase数据库的tuple行头部来标识这条记录的事务结束状态(未知.已提交.已回滚),在事务提交时如果并发更新100万行记录,需要对多个page的tuple进行更改,这种繁重的操作会对数 ...
- JS实现打开报表时默认为最后一次查询参数
问题描述 普通报表在打开时希望参数面板中的参数控件的值可以默认是上一次页面关闭前最后一次查询所选择的值. 解决方案 每次在页面关闭时将参数值保存到浏览器缓存中(适用用非FS平台),或每次点击查询后将参 ...
- Python正则表达式提取方法
- #构造,黑白染色#AT4378 [AGC027D] Modulo Matrix
题目 构造一个 \(n*n(n\leq 500)\) 的矩阵,满足元素均为正整数,不超过 \(10^15\) 且互不相同, 并且相邻两数若较大的为 \(x\),较小的为 \(y\),那么任意相邻两数 ...
- #背包#洛谷 4026 [SHOI2008]循环的债务
题目 分析 设\(dp[t][n][m]\)表示前\(t\)种钞票\(\text{Alice,Bob}\)分别拥有\(n,m\)元所需最小交换钞票数, 枚举\(\text{Alice,Bob}\)最后 ...
- JDK 14的新特性:switch表达式
目录 简介 写在前面 连写case switch返回值 yield 总结 简介 switch的新特性可是源远流长,早在JDK 12就以预览功能被引入了,最终在JDK 14成为了正式版本的功能:JEP ...
- 【Learning eBPF-3】一个 eBPF 程序的深入剖析
从这一章开始,我们先放下 BCC 框架,来看仅通过 C 语言如何实现一个 eBPF.如此一来,你会更加理解 BCC 所做的底层工作. 在这一章中,我们会讨论一个 eBPF 程序被执行的完整流程,如下图 ...
- HMS Core电商解决方案之商品3D商品展示
传统电商商品展示采用图文结合的形式,文案介绍产品的相关参数,搭配精美图片去吸引客户眼球.但图文商品展示由于色差.尺寸不符等原因,会让消费者产生图片和实物不一致的疑虑,且消费者需要消耗大量精力阅读和比较 ...