从 Unity window 获取 WM_INPUT

Get WM_INPUT from Unity window

关于

我正在尝试为 Unity 构建自定义鼠标输入,以直接从 HID 获取数据。我这样做是因为我想尝试一下(当使用我自己的自定义鼠标输入时)与给我原始鼠标输入的 Unity API 是否有任何区别。

另外我需要说的是,我现在所做的一切都不会发生在 Unity 中。我想构建一个 C++ 应用程序,然后将数据传递给 Unity(这不是这个问题的一部分)。

这个 link (MSDN High-Definition Mouse Movement) 表明我可以使用三种不同类型的消息。由于我需要所谓的 "High-Definition Mouse Movement" 我需要使用 WM_INPUT.

如文档所述,可以使用 WinProc 处理程序捕获此消息。在该回调中,可以访问原始鼠标数据。这就是我想要实现的目标,也是我需要帮助的地方。

我目前的做法

文档(上面的link)给了我这个注册鼠标的例子:

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]));

下面两行是我修改的:

Rid[0].hwndTarget = gameWindowHandle;

在那里我将 Unity window 定义为目标。 gameWindowHandleEnumWindows.

设置

由于语法错误(缺少括号),我更改的另一行是最后一行。

据我对文档的理解,应该是这样。现在,当有 WM_INPUT 条消息发送到 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;
}

我的问题

我遇到的第一个问题是调用这个

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

不 return 正确。相反,它 returns false 和 GetLastError 给我错误 87(谷歌搜索后我发现它与错误的参数有关)。

文档说要这样做,但不幸的是,它并不像我那样工作。

另一个问题是如何保持应用程序的存活。注册设备后,我需要等待回调触发(如果它们可以工作)。我怎样才能让应用程序只等待回调?

我的方法是否合理,或者我做的完全错了,必须使用不同的 APIs?

你的做法是错误的。首先,RawInput 需要 Window。由您自己的 WndProc 控制的 Window。因此,在您的 C++ 库中,您应该定义一个 window 过程。启动线程。在这个线程中用那个程序注册window class。在您成功注册您的 class 后,创建 HWND_MESSAGE window,注册您的设备并进入 while GetMessage... DispatchMessage 循环。这应该在一个单独的线程中完成。在您的 window 过程中,您现在必须捕获 WM_INPUT 消息。享受。