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 ...
随机推荐
- 记录--手写一个 v-tooltip 指令
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前言 日常开发中,我们经常遇到过tooltip这种需求.文字溢出.产品文案.描述说明等等,每次都需要写一大串代码,那么有没有一种简单的方式 ...
- 《On Java 8》笔记
第一章 对象的概念 复用 组合和聚合 组合(Composition)经常用来表示"拥有"关系(has-a relationship).例如,"汽车拥有引擎" 聚 ...
- C# WinForm 获取执行路径的几种常见方法
//1.获取模块的完整路径. string path1 = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName; Co ...
- vue中$forceUpdate()的使用
刷新数组的作用 this.$forceUpdate(); 具体请看:vue中$forceUpdate()的使用 - 简书 (jianshu.com)
- veriog之四位全加器
verilog之四位全加器 1.简易代码 module adder_4bit ( cout,sum,ina,inb,cin ); output[3:0] sum; output cout; input ...
- Lab1:Xv6 and Unix utilities
Sleep功能 通过接受时间参数,调用system_call 指令 sleep实现该功能 #include "kernel/types.h" #include "kern ...
- 第一次画pcb学到的知识
第一次画pcb学到的知识 1. Typec (6针) 其中的CC1.CC2引脚为快充协议的引脚,用不到的时候串个5.1K的电阻接地s 2. AMS117降压电路 AMS1117芯片的输入电压都要一个1 ...
- Android弹出UI界面---Toast
1.默认展示 1 // 第一个参数:当前的上下文环境.可用getApplicationContext()或this 2 // 第二个参数:要显示的字符串.也可是R.string中字符串ID 3 // ...
- #排列组合,背包#CF232B Table
题目 有一个 \(n\times m\) 的矩阵,求使得每个 \(n\times n\) 的矩阵中都有正好 \(k\) 个点的方案数. 分析 考虑到如果确定了前 \(n\) 列的选点个数,那么对于一列 ...
- 使用OHOS SDK构建tinyexr
参照OHOS IDE和SDK的安装方法配置好开发环境. 从github下载源码. 执行如下命令: git clone https://github.com/syoyo/tinyexr.git 进入源码 ...