在Qt中获取原始鼠标移动

Get Raw Mouse Movement in Qt

本文关键字:鼠标 移动 原始 获取 Qt      更新时间:2023-10-16

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

我读过很多类似的问题,但没有一个能解决我的问题。我试着让鼠标移动基于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);

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

@nnatar您的帮助是巨大的!非常感谢。

我终于找到了解决办法。

我不得不在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;
}

正如GetRawInputData MSDN页面所述,该函数的第一个参数是

hRawInput[in]
类型:HRAWMINPUT
RAWMINPUT结构的句柄。这来自WM_INPUT中的lParam。

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

lParam
RAWMINPUT结构的句柄,包含来自设备的原始输入。

正如WM_INPUT MSDN页面上所说。您需要在GetRawInputData函数中使用此句柄。现在,您使用的数据句柄不正确,因此GetRawInputData不会向您返回任何有效信息(它只是不知道在哪里处理数据)。

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

有用的链接:

  • MSDN:GetRawInputData
  • MSDN:WM_INPUT
  • MSDN:RegisterRawInputDevices–您应该将应用程序与原始输入相关联,以接收WM_input消息
  • MSDN:使用原始输入–用于注册原始输入和原始输入处理的示例代码

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

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

你可以在这个页面上阅读:QByteArray::operator==。

更新

MSDN:RAWINPUTDEVICE页面指出

RIDEV_INPUTSINK 0x00000100
如果设置,这将使调用方能够接收即使当呼叫者不在前台时输入。请注意必须指定hwndTarget。

您有INVALID_HANDLE_ERROR错误,因为您需要指定窗口的hWnd。什么是MainWindow类?您继承了QMainWindow还是QWidget?Qt中的每个小部件都有winId属性(WIdQWidget::winId()const),这正是您要查找的hWnd。因此,您需要获取窗口的winId(),将其强制转换为HWND,然后像这样写入Rid结构:

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

如果它没有帮助,那么你需要提供一个最小、完整和可验证的例子来进行进一步的调查。