Get WM_INPUT from Unity window

2019-07-24 11:24发布

问题:

About

I am trying to build a custom mouse input for Unity that gets the data directly from the HID. I do this because I want to try if there is any difference (when using my own custom mouse input) to the Unity API that gives me raw mouse input.

Also I need to say that everything I am doing right now does not happen within Unity. I want to build an C++ application and then pass the data to Unity (that's not a part of this question).

This link (MSDN High-Definition Mouse Movement) shows that there are three different types of messages I can use. Due to I need so called "High-Definition Mouse Movement" I need to go with WM_INPUT.

This message can be caught with the WinProc handler as the documentation says. Within that callback the raw mouse data can be accessed. This is what I want to achieve and where I need help.

My current approach

The documentation (link above) gives me this example to register the mouse:

RAWINPUTDEVICE Rid[1];
Rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC;
Rid[0].usUsage = HID_USAGE_GENERIC_MOUSE;
Rid[0].dwFlags = RIDEV_INPUTSINK;
Rid[0].hwndTarget = gameWindowHandle;

regDeviceDone = RegisterRawInputDevices(Rid, 1, sizeof(Rid[0]));

The following two lines were modified by me:

Rid[0].hwndTarget = gameWindowHandle;

There I define the Unity window as target. gameWindowHandle is set by EnumWindows.

The other line I changed is the last one due to there is a syntax error (missing parenthesis).

As far as I understood the documentation right this should be it. Now the following callback should be called when there are WM_INPUT messages sent to the Unity window.

LRESULT CALLBACK WindowProc(
    _In_ HWND   hwnd,
    _In_ UINT   uMsg,
    _In_ WPARAM wParam,
    _In_ LPARAM lParam
) {
    printf("%d", uMsg);
    switch (uMsg) { 
        case WM_INPUT:
            UINT dwSize = 40;
            static BYTE lpb[40];

            GetRawInputData((HRAWINPUT)lParam, RID_INPUT,
                lpb, &dwSize, sizeof(RAWINPUTHEADER));

            RAWINPUT* raw = (RAWINPUT*)lpb;

            if (raw->header.dwType == RIM_TYPEMOUSE)
            {
                int xPosRelative = raw->data.mouse.lLastX;
                int yPosRelative = raw->data.mouse.lLastY;

                printf("X: %d, Y: %d", xPosRelative, yPosRelative);
            }
            break;
    }

    return NULL;
}

My problems

The first problem I have is that calling this

regDeviceDone = RegisterRawInputDevices(Rid, 1, sizeof(Rid[0]));

does not return true as it should. Instead it returns false and GetLastError gives me error 87 (after googling this I found out it has to do with wrong parameters).

The documentation says to do so but unfortunately it does not work the way I do it.

Another problem is how to keep the application alive. After registering the device I need to wait for the callbacks to trigger (if they would work). How can I achieve that the application does nothing than waiting for the callbacks?

Is my approach even reasonable or am I doing completely wrong and have to use different APIs?

回答1:

Your approach is wrong. First, RawInput requires Window. A Window under your control with your own WndProc. Hence in your C++ library, you should define a window procedure. Start a thread. In this thread register window class with that procedure. After you succeed in registering your class, create HWND_MESSAGE window, register your devices and enter a while GetMessage... DispatchMessage loop. This should be done in a separate thread. In your window procedure you must now catch WM_INPUT messages. Enjoy.