在 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。您可以在那里找到键盘和鼠标原始输入处理的示例代码。
有用的链接:
- MSDN: GetRawInputData
- MSDN: WM_INPUT
- MSDN: RegisterRawInputDevices – 您应该将您的应用程序与原始输入相关联以接收 WM_INPUT 消息
- 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;
}
在处理 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。您可以在那里找到键盘和鼠标原始输入处理的示例代码。
有用的链接:
- MSDN: GetRawInputData
- MSDN: WM_INPUT
- MSDN: RegisterRawInputDevices – 您应该将您的应用程序与原始输入相关联以接收 WM_INPUT 消息
- 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;
}