作为程序员,我们经常需要获取用户的输入信息,这个过程中会使用到很多API和工具。在Windows平台上,一个非常重要的API就是GetRawInputData。本文将围绕GetRawInputData讲解如何使用它来获取原始输入数据。
一、GetRawInputData 简介
GetRawInputData是一个用于获取原始输入数据的函数,它可以返回系统接收到的原始输入数据,这些数据包括鼠标、键盘、触摸屏等设备的输入数据。
GetRawInputData函数位于user32.dll中。它的函数原型如下所示:
BOOL GetRawInputData(
HRAWINPUT hRawInput,
UINT uiCommand,
LPVOID pData,
PUINT pcbSize,
UINT cbSizeHeader
);
参数说明:
HRAWINPUT hRawInput:输入设备的句柄,可以从WM_INPUT消息中获取。
UINT uiCommand:数据获取模式,最初需要将其设置为RID_INPUT。
LPVOID pData:用来接收输入数据的缓冲区。
PUINT pcbSize:用来存储接收到的输入数据大小的变量。
UINT cbSizeHeader:缓冲区头的大小。
在使用GetRawInputData之前,需要了解一下WM_INPUT消息,因为这个消息提供了关于输入设备的一些信息。
二、WM_INPUT消息
WM_INPUT消息(Windows Message Input)是Windows操作系统提供的一种窗口消息,它可以接收键盘、鼠标、游戏控制器等输入设备的信息。
当一个输入设备的状态发生改变时,Windows操作系统会自动发送WM_INPUT消息到系统队列中,让应用程序可以对输入设备的输入进行处理。每个WM_INPUT消息都包含有一个RAWINPUT结构体,这个结构体包含了一个输入设备产生的所有事件。
三、获取输入设备句柄
在使用GetRawInputData之前,需要首先获取输入设备的句柄,使用方法如下:
1. 创建一个窗口来接收WM_INPUT消息。
创建一个窗口之前,需要创建一个WNDCLASS结构体。
WNDCLASS wndclass = {
.style = CS_HREDRAW | CS_VREDRAW, // 窗口风格
.lpfnWndProc = WndProc, // 处理窗口消息的回调函数
.cbClsExtra = 0, // 额外的类空间
.cbWndExtra = 0, // 额外的窗口空间
.hInstance = hInstance, // 当前实例的句柄
.hIcon = LoadIcon(NULL, IDI_APPLICATION), // 应用程序图标
.hCursor = LoadCursor(NULL, IDC_ARROW), // 光标
.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1),// 背景颜色
.lpszMenuName = NULL, // 菜单的名称
.lpszClassName = _T("MyRawInputWndClass") // 窗口类的名称
};
ATOM atom = RegisterClass(&wndclass); // 注册窗口类
HWND hWnd = CreateWindow( // 创建窗口
_T("MyRawInputWndClass"), // 窗口类
_T("My Raw Input Window"), // 窗口标题
WS_OVERLAPPEDWINDOW, // 窗口风格
CW_USEDEFAULT, CW_USEDEFAULT, // 窗口位置
CW_USEDEFAULT, CW_USEDEFAULT, // 窗口大小
NULL, NULL, // 父窗口和菜单句柄
hInstance, NULL // 应用程序实例和扩展数据
);
2. 向系统注册所需的输入设备。
RAWINPUTDEVICE Rid[1];
Rid[0].usUsagePage = 0x01; // 通用桌面控制
Rid[0].usUsage = 0x06; // 键盘
Rid[0].dwFlags = RIDEV_INPUTSINK;
Rid[0].hwndTarget = hWnd;
RegisterRawInputDevices(Rid, 1, sizeof(Rid[0]));
在注册输入设备时,需要给它们分配一个HWND,用来接收WM_INPUT消息。这需要将一个附有RIDEV_INPUTSINK标记的RAWINPUTDEVICE结构体传递给RegisterRawInputDevices函数。
3. 处理WM_INPUT消息。
在窗口的消息回调函数中,可以处理WM_INPUT消息,方法如下:
LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg) {
case WM_INPUT: {
// 处理输入数据
break;
}
case WM_DESTROY: {
PostQuitMessage(0);
break;
}
default: {
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
}
return 0;
}
在处理WM_INPUT消息时,需要调用GetRawInputData函数来获取原始输入数据。
四、使用 GetRawInputData 获取原始输入数据
获取原始输入数据的方法有两种,一种是直接在WM_INPUT消息中调用GetRawInputData函数,另一种是在WM_INPUT消息中缓存输入数据,并在主程序中调用GetRawInputData函数进行处理。
在WM_INPUT消息中获取原始输入数据的方法示例代码如下:
case WM_INPUT: {
UINT dataSize;
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dataSize, sizeof(RAWINPUTHEADER));
LPBYTE pData = new BYTE[dataSize];
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, pData, &dataSize, sizeof(RAWINPUTHEADER));
PRAWINPUT pRawInput = (PRAWINPUT)pData;
// 处理输入数据
delete[]pData;
return 0;
}
在这个示例代码中,每当收到WM_INPUT消息时,都会调用GetRawInputData函数。在调用这个函数前,首先需要通过第一次GetRawInputData函数调用获取数据的大小,然后通过第二次GetRawInputData函数调用来获取数据。
另一种处理输入数据的方法是在WM_INPUT消息中缓存输入数据,并使用一个全局变量来保存这些数据,供主程序进行使用。示例代码如下:
static RAWINPUT* g_pRawInput;
case WM_INPUT: {
UINT dataSize;
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dataSize, sizeof(RAWINPUTHEADER));
g_pRawInput = new RAWINPUT[dataSize];
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, g_pRawInput, &dataSize, sizeof(RAWINPUTHEADER));
return 0;
}
在主程序中,可以使用GetRawInputData函数来获取输入数据:
UINT dataSize;
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dataSize, sizeof(RAWINPUTHEADER));
if (dataSize > 0) {
LPBYTE pData = new BYTE[dataSize];
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, pData, &dataSize, sizeof(RAWINPUTHEADER));
PRAWINPUT pRawInput = (PRAWINPUT)pData;
// 处理输入数据
delete[]pData;
}
需要注意的是,在主程序中,如果要使用GetRawInputData函数获取输入数据,需要在WM_INPUT消息处理完成后使用PostMessage函数来发送消息到主程序中。
五、总结
本文主要介绍了如何使用GetRawInputData函数来获取原始输入数据。在使用GetRawInputData之前,需要了解一下WM_INPUT消息,因为这个消息提供了关于输入设备的一些信息。另外,在使用GetRawInputData的过程中,需要注意一些函数的使用方法和调用时机。
在实际的应用程序中,获取原始输入数据是一个很重要的操作,这可以帮助我们更好的了解用户行为、改进用户体验以及添加新的功能。希望本文对读者有所帮助。