WM_INPUT 上的 RAWINPUTHEADER hDevice null for laptop trackpad
RAWINPUTHEADER hDevice null on WM_INPUT for laptop trackpad
我正在使用原始输入来处理通用设备的输入,到目前为止我的所有测试用例都有效(键盘、游戏手柄和鼠标),但我的笔记本电脑触控板给我带来了一个奇怪的问题。当我得到 WM_INPUT message from the track pad (movement or button presses) I receive almost all the correct information except for the hDevice in the RAWINPUT header
我正在通过 GetRawInputDeviceList (with RID_DEVICE_INFO) and WM_INPUT_DEVICE_CHANGE 消息获取所有可用的 HID 设备。我相信触控板是通过第一种方法找到的(带 2 个按钮的鼠标 HID,索引 6)。
HID: [0x00020043] active
HID: [0x00020047] active
HID: [0x00020049] active
HID: [0x0002004B] active
keyboard: [0x00010041] active
mouse: [0x0001003B] active
mouse: [0x00010039] active
mouse: [0x0001003B] added
mouse: [0x00010039] added
keyboard: [0x00010041] added
#ifndef UNICODE
#define UNICODE
#endif
#include <array>
#include <vector>
#include <Windows.h>
bool active = true;
const char* getTypeStr(DWORD type)
{
if (type == RIM_TYPEMOUSE) return "mouse";
else if (type == RIM_TYPEKEYBOARD) return "keyboard";
else return "HID";
}
LRESULT CALLBACK wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (msg == WM_INPUT)
{
if (GET_RAWINPUT_CODE_WPARAM(wParam) == RIM_INPUT) // Only handle foreground events.
{
const HRAWINPUT hRawInput = reinterpret_cast<HRAWINPUT>(lParam);
// Get the size of the data package.
UINT32 size = 0;
GetRawInputData(hRawInput, RID_INPUT, nullptr, &size, sizeof(RAWINPUTHEADER));
// Ignore empty packets.
if (size > 0)
{
PRAWINPUT input = reinterpret_cast<PRAWINPUT>(malloc(size));
GetRawInputData(hRawInput, RID_HEADER, input, &size, sizeof(RAWINPUTHEADER));
GetRawInputData(hRawInput, RID_INPUT, input, &size, sizeof(RAWINPUTHEADER));
printf("Received WM_INPUT from 0x%p.\n", input->header.hDevice);
free(input);
return 0;
}
}
}
else if (msg == WM_INPUT_DEVICE_CHANGE)
{
const HANDLE hDevice = reinterpret_cast<HANDLE>(lParam);
RID_DEVICE_INFO info;
info.cbSize = sizeof(RID_DEVICE_INFO);
UINT cbSize = info.cbSize;
GetRawInputDeviceInfo(hDevice, RIDI_DEVICEINFO, &info, &cbSize);
if (wParam == GIDC_ARRIVAL) printf("%s: [0x%p] added\n", getTypeStr(info.dwType), hDevice);
else printf("%s: [0x%p] removed\n", getTypeStr(info.dwType), hDevice);
}
else if (msg == WM_CLOSE)
{
active = false;
return 0;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
int main()
{
// Create the window.
const HINSTANCE hInstance = GetModuleHandle(nullptr);
WNDCLASSEX wndEx =
{
sizeof(WNDCLASSEX),
CS_DBLCLKS,
wndProc,
0,
0,
hInstance,
nullptr,
LoadCursor(nullptr, IDC_ARROW),
(HBRUSH)(COLOR_WINDOW + 1),
nullptr,
L"TestWindow",
nullptr
};
RegisterClassEx(&wndEx);
const HWND hWnd = CreateWindow(L"TestWindow", L"TestWindow", WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU, 0, 0, 600, 600, nullptr, nullptr, hInstance, nullptr);
ShowWindow(hWnd, SW_SHOW);
// Log the connected devices.
UINT32 deviceCnt;
GetRawInputDeviceList(nullptr, &deviceCnt, sizeof(RAWINPUTDEVICELIST));
std::vector<RAWINPUTDEVICELIST> devices{ deviceCnt };
GetRawInputDeviceList(devices.data(), &deviceCnt, sizeof(RAWINPUTDEVICELIST));
for (const RAWINPUTDEVICELIST cur : devices)
{
printf("%s: [0x%p] active\n", getTypeStr(cur.dwType), cur.hDevice);
}
// Register the raw input devices we want to get notifications from.
std::array<RAWINPUTDEVICE, 3> rawInputDevices
{
RAWINPUTDEVICE {
0x1,
0x2, // Mouse
RIDEV_DEVNOTIFY,
hWnd
},
RAWINPUTDEVICE {
0x1,
0x6, //Keyboard
RIDEV_DEVNOTIFY,
hWnd
},
RAWINPUTDEVICE {
0x1,
0x5, // Gamepad
RIDEV_DEVNOTIFY,
hWnd
}
};
RegisterRawInputDevices(rawInputDevices.data(), rawInputDevices.size(), sizeof(RAWINPUTDEVICE));
// Update loop.
MSG msg;
while (active)
{
while (PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
// Finalize.
DestroyWindow(hWnd);
UnregisterClass(L"TestWindow", hInstance);
}
我期待 WM_INPUT 消息给我一个有效的设备句柄,但它没有。
Received WM_INPUT from 0x00000000.
The result for a move
input:
header:
dwType = 0
dwSize = 48
hDevice = 0x0000000000000000
wParam = 0
data (mouse):
usFlags = 0
usButtons = 0
usButtonData = 0
ulRawButtons = 0
ILastX = 5
ILastY = -6
uIExtraInformation = 0
HID that's probably my track pad
hDevice = 0x0000000000010039
cbSize = 32
dwType = 0
mouse:
dwId = 128
dwNumberOfButtons = 2
dwSampleRate = 0
fHasHorizontalWheel = 0
来自我的集成键盘的通知似乎是正确的
Received WM_INPUT from 0x00010041.
问题是我的触摸板是精密触摸板,这意味着在 WM_INPUT 通知之前应用了一些 filters/transformations。这是 API 的预期行为,但没有记录(据我所知)。
非常感谢 Eric Brown 回答这个问题!查看他留下的评论以获得答案。
我正在使用原始输入来处理通用设备的输入,到目前为止我的所有测试用例都有效(键盘、游戏手柄和鼠标),但我的笔记本电脑触控板给我带来了一个奇怪的问题。当我得到 WM_INPUT message from the track pad (movement or button presses) I receive almost all the correct information except for the hDevice in the RAWINPUT header
我正在通过 GetRawInputDeviceList (with RID_DEVICE_INFO) and WM_INPUT_DEVICE_CHANGE 消息获取所有可用的 HID 设备。我相信触控板是通过第一种方法找到的(带 2 个按钮的鼠标 HID,索引 6)。
HID: [0x00020043] active
HID: [0x00020047] active
HID: [0x00020049] active
HID: [0x0002004B] active
keyboard: [0x00010041] active
mouse: [0x0001003B] active
mouse: [0x00010039] active
mouse: [0x0001003B] added
mouse: [0x00010039] added
keyboard: [0x00010041] added
#ifndef UNICODE
#define UNICODE
#endif
#include <array>
#include <vector>
#include <Windows.h>
bool active = true;
const char* getTypeStr(DWORD type)
{
if (type == RIM_TYPEMOUSE) return "mouse";
else if (type == RIM_TYPEKEYBOARD) return "keyboard";
else return "HID";
}
LRESULT CALLBACK wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (msg == WM_INPUT)
{
if (GET_RAWINPUT_CODE_WPARAM(wParam) == RIM_INPUT) // Only handle foreground events.
{
const HRAWINPUT hRawInput = reinterpret_cast<HRAWINPUT>(lParam);
// Get the size of the data package.
UINT32 size = 0;
GetRawInputData(hRawInput, RID_INPUT, nullptr, &size, sizeof(RAWINPUTHEADER));
// Ignore empty packets.
if (size > 0)
{
PRAWINPUT input = reinterpret_cast<PRAWINPUT>(malloc(size));
GetRawInputData(hRawInput, RID_HEADER, input, &size, sizeof(RAWINPUTHEADER));
GetRawInputData(hRawInput, RID_INPUT, input, &size, sizeof(RAWINPUTHEADER));
printf("Received WM_INPUT from 0x%p.\n", input->header.hDevice);
free(input);
return 0;
}
}
}
else if (msg == WM_INPUT_DEVICE_CHANGE)
{
const HANDLE hDevice = reinterpret_cast<HANDLE>(lParam);
RID_DEVICE_INFO info;
info.cbSize = sizeof(RID_DEVICE_INFO);
UINT cbSize = info.cbSize;
GetRawInputDeviceInfo(hDevice, RIDI_DEVICEINFO, &info, &cbSize);
if (wParam == GIDC_ARRIVAL) printf("%s: [0x%p] added\n", getTypeStr(info.dwType), hDevice);
else printf("%s: [0x%p] removed\n", getTypeStr(info.dwType), hDevice);
}
else if (msg == WM_CLOSE)
{
active = false;
return 0;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
int main()
{
// Create the window.
const HINSTANCE hInstance = GetModuleHandle(nullptr);
WNDCLASSEX wndEx =
{
sizeof(WNDCLASSEX),
CS_DBLCLKS,
wndProc,
0,
0,
hInstance,
nullptr,
LoadCursor(nullptr, IDC_ARROW),
(HBRUSH)(COLOR_WINDOW + 1),
nullptr,
L"TestWindow",
nullptr
};
RegisterClassEx(&wndEx);
const HWND hWnd = CreateWindow(L"TestWindow", L"TestWindow", WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU, 0, 0, 600, 600, nullptr, nullptr, hInstance, nullptr);
ShowWindow(hWnd, SW_SHOW);
// Log the connected devices.
UINT32 deviceCnt;
GetRawInputDeviceList(nullptr, &deviceCnt, sizeof(RAWINPUTDEVICELIST));
std::vector<RAWINPUTDEVICELIST> devices{ deviceCnt };
GetRawInputDeviceList(devices.data(), &deviceCnt, sizeof(RAWINPUTDEVICELIST));
for (const RAWINPUTDEVICELIST cur : devices)
{
printf("%s: [0x%p] active\n", getTypeStr(cur.dwType), cur.hDevice);
}
// Register the raw input devices we want to get notifications from.
std::array<RAWINPUTDEVICE, 3> rawInputDevices
{
RAWINPUTDEVICE {
0x1,
0x2, // Mouse
RIDEV_DEVNOTIFY,
hWnd
},
RAWINPUTDEVICE {
0x1,
0x6, //Keyboard
RIDEV_DEVNOTIFY,
hWnd
},
RAWINPUTDEVICE {
0x1,
0x5, // Gamepad
RIDEV_DEVNOTIFY,
hWnd
}
};
RegisterRawInputDevices(rawInputDevices.data(), rawInputDevices.size(), sizeof(RAWINPUTDEVICE));
// Update loop.
MSG msg;
while (active)
{
while (PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
// Finalize.
DestroyWindow(hWnd);
UnregisterClass(L"TestWindow", hInstance);
}
我期待 WM_INPUT 消息给我一个有效的设备句柄,但它没有。
Received WM_INPUT from 0x00000000.
The result for a move
input:
header:
dwType = 0
dwSize = 48
hDevice = 0x0000000000000000
wParam = 0
data (mouse):
usFlags = 0
usButtons = 0
usButtonData = 0
ulRawButtons = 0
ILastX = 5
ILastY = -6
uIExtraInformation = 0
HID that's probably my track pad
hDevice = 0x0000000000010039
cbSize = 32
dwType = 0
mouse:
dwId = 128
dwNumberOfButtons = 2
dwSampleRate = 0
fHasHorizontalWheel = 0
来自我的集成键盘的通知似乎是正确的
Received WM_INPUT from 0x00010041.
问题是我的触摸板是精密触摸板,这意味着在 WM_INPUT 通知之前应用了一些 filters/transformations。这是 API 的预期行为,但没有记录(据我所知)。
非常感谢 Eric Brown 回答这个问题!查看他留下的评论以获得答案。