1
votes

I'm using raw input to handle input for generic devices, thus far all of my test cases have worked (keyboards, game pads and mice), but my laptops track pad is giving me a weird problem. When I get a 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

I'm getting all available HID devices through GetRawInputDeviceList (with RID_DEVICE_INFO) and WM_INPUT_DEVICE_CHANGE messages. I believe the track pad is found by the first method (mouse HID with 2 buttons, index 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);
}

I'm expecting the WM_INPUT message to give me a valid device handle but it doesn't.

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

Notifications from my integrated keyboard seem to be correct

Received WM_INPUT from 0x00010041.
1
Hard to answer without seeing your full device list, or how you register devices, or how OnInputEvent.Post() processes eventsRemy Lebeau
I've added the result of GetRawInputDeviceList to the question and I've added by device registration, the data is already invalid before OnInputEvent.Post() triggers so I don't think this code is affecting my issue.Arzana
This question has been voted as off-topic, I suggest you post a new question and you had better attention the reason above.Strive Sun
@Arzana You're supposed to improve your post here to get it reopened, not to post a new one.πάντα ῥεῖ
I've completely updated my post, with a new code example that should run out of the box and with more information than before. I've also removed the new post, which was made by recommendation of @StriveSun-MSFTArzana

1 Answers

1
votes

The problem was that my touchpad is a precision touchpad, which means that there are some filters/transformations applied to it before the WM_INPUT notification. This was intended behaviour by the API but not documented (as far as I know).

Massive thanks to Eric Brown for answering this questions! Check the comment he left for the answer.