在 Qt 中获取原始鼠标移动

Get Raw Mouse Movement in Qt

在处理 this and QAbstractNativeEventFilter class 之后,我终于从 HID(鼠标和键盘)获得了本机事件。

我读过很多类似的问题,但 none 解决了我的问题。我尝试根据 dpi 移动鼠标。我在 Qt 5.5 上工作,因为我的整个项目都是在那里构建的。

即使使用 RIM_TYPEMOUSE 标志,我也无法将鼠标移动事件与其他 HID 事件(鼠标和键盘)分开。

这是我的一些实现代码:

bool MouseRawMovement::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
{   
    if(eventType == "windows_generic_MSG")
    {
        MSG *msg = reinterpret_cast<MSG*>(message);
        qDebug()<<msg->message; // It prints numbers such as 6,26,28,141 on each event
        if(msg->message == WM_INPUT) //it never gets in
        {
        UINT dwSize = 40;
        static BYTE lpb[40];
        GetRawInputData((HRAWINPUT)msg->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;

            qDebug()<<xPosRelative<<yPosRelative ;
        }
        }
    }
    return false;
}

还有我的构造函数

    MouseRawMovement::MouseRawMovement()
    {
       Rid[0].usUsagePage = 0x01;
       Rid[0].usUsage = 0x02;
       Rid[0].dwFlags = RIDEV_INPUTSINK;
       Rid[0].hwndTarget = 0;
       if(!RegisterRawInputDevices(Rid, 1, sizeof(Rid[0])))
           qDebug()<<QString::number(GetLastError()); //I see error msg 6 - Ref. ERROR_INVALID_HANDLE
    }

输出始终显示零 (0)。

hWnd 是怎么回事。我试着给这个:

HWND hWnd =::GetConsoleWindow();

但我得到了相同的结果。

在main.cpp我安装原生过滤器

MainWindow w;
a.installNativeEventFilter(&w.mm);

我试了好几天都找不到解决办法。有没有人...(???)

GetRawInputData MSDN 页面所述,此函数的第一个参数是

hRawInput [in]
Type: HRAWINPUT
A handle to the RAWINPUT structure. This comes from the lParam in WM_INPUT.

因此,您需要首先检查您正在处理的消息是否是 WM_INPUT 消息 (msg->message == WM_INPUT),然后才尝试提取原始输入数据。 接下来,WM_INPUT 消息的 lParam

lParam
A handle to the RAWINPUT structure that contains the raw input from the device.

WM_INPUT MSDN 页面上所述。您需要在 GetRawInputData 函数中使用此句柄。现在,您使用的数据句柄不正确,因此 GetRawInputData 不会 return 向您提供任何有效信息(它只是不知道将数据带到何处进行处理)。

您应该阅读文章 MSDN: Using Raw Input。您可以在那里找到键盘和鼠标原始输入处理的示例代码。

有用的链接:

还有一件事。您可以使用相等运算符将 QByteArray 实例与字符串进行比较,在您的情况下它将是这样的:if (eventType == "windows_generic_MSG") {...}。这是因为 QByteArray 具有重载的相等运算符:

bool QByteArray::operator==(const QString & str) const

您可以在此页面上阅读相关信息:QByteArray::operator==

更新

MSDN: RAWINPUTDEVICE 页面注释

RIDEV_INPUTSINK 0x00000100
If set, this enables the caller to receive the input even when the caller is not in the foreground. Note that hwndTarget must be specified.

您遇到 INVALID_HANDLE_ERROR 错误,因为您需要指定 window 的 hWnd。 什么是 MainWindow class?你继承自 QMainWindow 还是 QWidget? Qt 中的每个小部件都有 winId 属性 (WId QWidget::winId() const),这正是您正在寻找的 hWnd。所以你需要把你的 window 的 winId() 转换为 HWND 并像这样写入 Rid 结构:

Rid[0].hwndTarget = (HWND)w->winId();

如果没有帮助,那么您需要提供一个 Minimal, Complete, and Verifiable example 以供进一步调查。

@nnatarr 你的帮助是巨大的!谢谢!!!

我终于找到了解决办法。

我不得不在 main.cpp 中调用 RegisterRawInputDevices 并更改了很多东西。

这里是main.cpp

#include "mainwindow.h"
#include <QApplication>
#include <windows.h>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    a.installNativeEventFilter(&w.mm);
    w.show();

    UINT nDevices;
   PRAWINPUTDEVICELIST pRawInputDeviceList;

   if (!GetRawInputDeviceList(NULL, &nDevices, sizeof(RAWINPUTDEVICELIST)))
   {
      qDebug() << "ERROR -- GetRawInputDeviceList ...";
      return 1;
   }

   if (!(pRawInputDeviceList = (PRAWINPUTDEVICELIST)malloc(sizeof(RAWINPUTDEVICELIST) * nDevices)))
   {
      qDebug() << "Initialization failed...";
      return 1;
   }

    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 = (HWND)w.effectiveWinId();
    if(!RegisterRawInputDevices(Rid, 1, sizeof(Rid[0])))
        qDebug()<<"Huston Problem.";
    qDebug()<<QString::number(GetLastError());

    return a.exec();
}

这是 Mouse Handlig 的一部分 Class

bool MouseRawMovement::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
{
    if(eventType == "windows_generic_MSG")
    {
        MSG *msg = reinterpret_cast<MSG*>(message);

        if(msg->message == WM_INPUT)
        {
            UINT dwSize = 40;
            static BYTE lpb[40];
            if(!GetRawInputData((HRAWINPUT)msg->lParam, RID_INPUT,lpb, &dwSize, sizeof(RAWINPUTHEADER)))
                qDebug()<<"Error GetRawInputData";
            else
            {
                RAWINPUT* raw = (RAWINPUT*)lpb;
                if (raw->header.dwType == RIM_TYPEMOUSE)
                {
                    int xPosRelative = raw->data.mouse.lLastX;
                    int yPosRelative = raw->data.mouse.lLastY;
                    //qDebug()<<xPosRelative<<yPosRelative;
                }
            }

        }
    }
    return false;
}