thanasispap
thanasispap

Reputation: 43

Get Raw Mouse Movement in Qt

After working on this and QAbstractNativeEventFilter class I finally got native events from HID (both mouse and keyboard).

I've read many similar questions but none solved my problem. I try to get mouse movement based on dpi. I work on Qt 5.5 cause my whole project built there.

I can't separate mouse movement events from other HID events (mouse and keyboard) even with RIM_TYPEMOUSE flag.

Here is some code from my implementation:

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;
}

Also here is my constructor

    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
    }

Output shows me zeros (0) all time.

Whats going on with hWnd. I tried to give this:

HWND hWnd =::GetConsoleWindow();

but I had the same result.

In main.cpp I install native Filter

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

I try for days and I could not find the solution. Is there anyone...(???)

Upvotes: 1

Views: 2550

Answers (2)

thanasispap
thanasispap

Reputation: 43

@nnatarr your help was substantial! Thank you!!!

I finally find the solution.

I had to call RegisterRawInputDevices in main.cpp and change lot of things.

Here is 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();
}

And here is a part from 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;
}

Upvotes: 2

teapot_of_wine
teapot_of_wine

Reputation: 526

As the GetRawInputData MSDN page states, first parameter of this function is

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

So, you need to check first if message you are processing is a WM_INPUT message (msg->message == WM_INPUT) and only then try to extract raw input data. Next, the lParam of WM_INPUT message is

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

as it says on WM_INPUT MSDN page. You need to use this handle in GetRawInputData function. Right now, you are using incorrect data handle so GetRawInputData do not return any valid information to you (it just doesn't know where to take data to process).

You should read article MSDN: Using Raw Input. There you can find sample code for the keybaord and mouse raw input processing.

Useful links:

One more thing. You can use equality operator to compare QByteArray instance to a string, in your case it will be like this: if (eventType == "windows_generic_MSG") {...}. This is because QByteArray has the overloaded equality operator:

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

You can read about it at this page: QByteArray::operator==.

UPDATE

MSDN: RAWINPUTDEVICE page notes that

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.

You have the INVALID_HANDLE_ERROR error because you need to specify hWnd of your window. What is MainWindow class? Do you inherit from QMainWindow or QWidget? Every widget in Qt have the winId property (WId QWidget::winId() const) which is the very hWnd you are looking for. So you need to take winId() of your window, cast it to HWND and write into the Rid structure like this:

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

If it won't help, then you need to provide a Minimal, Complete, and Verifiable example for further investigation.

Upvotes: 1

Related Questions