我正在使用原始输入来处理通用设备的输入,到目前为止,我的所有测试用例(键盘,游戏手柄和鼠标)都可以使用,但是我的笔记本电脑触控板给我带来了一个奇怪的问题。当我从触控板收到WM_INPUT消息(移动或按下按钮)时,我收到几乎所有正确的信息,但RAWINPUT header 中的hDevice除外

我正在通过GetRawInputDeviceList(带有RID_DEVICE_INFO)和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通知之前已对其应用了一些过滤器/转换。这是API的预期行为,但没有记录(据我所知)。

非常感谢Eric Brown回答了这个问题!检查他留下的答案的评论。

10-08 00:43