Saturday, 5 February 2011

Using the 3DConnexion mouse with a Qt Application

This note describes my experiences getting a 3D mouse to work in a Qt application on Windows.

The 3DConnexion 3D mouse is a 6-DOF controller often used for CAD and engineering applications. 3DConnexion provide an SDK for windows which provides integration with MFC applications but not for Qt.


RAWINPUT support for Qt

The recommended method of supporting the 3DConnexion 3D mouse is to use Windows RAWINPUT message to receive the data from the mouse and then process those message to get the motion data.

There are 2 problems here

  • Qt has no native support for RAWINPUT - it is a windows only system and Qt has no corresponding Qt events for the 3D mouse
  • The "out-of-the-box" version of Qt does not forward RAWINPUT messages as they are received - at least up to Qt 4.6.2. On windows 7 Qt4.7.1 seemed to work with no modification.

The Raw Input API provides a "stable and robust way for applications to accept raw input from any HID, including the keyboard and mouse." [msdn] This enables the application to get the actual data sent by the HID device without any processing being done by windows first.

The application first registers to receive Raw Input from a particular device type, then when that device has data the application receives a WM_INPUT message in its event queue and the queue status flag QS_RAWINPUT is set. The application can then retrieve the data using the Raw Input API.

Raw Input was added in Windows XP, so is not available in Windows 2000
(Which is important -- see below.)

Raw Input and Qt

The problem with Qt (at least in 4.6.2) is that the version from the installer does not process Raw Input messages correctly. The way of collecting these the Raw Input messages is to set an event filter on the QApplication which gets the native windows messages. These can then be processed by the application using the Windows Raw Input API. However, the WM_INPUT messages are not being received by window/event filter the until some other event such as a mouse or timer event occurrs. Moving the 3D mouse causes no events to be received by the event filter but then if the normal mouse is moved (or key pressed etc)
all(?) the 3D mouse events arrive.

The problem can be traced to QEventDispatcherWin32?, which maps the windows messages onto Qt Events. Specifically, the line

   MsgWaitForMultipleObjectsEX(nCount, pHandles, INFINITE, QS_ALLINPUT,MWMO_ALERTABLE);

in the processEvents function of QEventDispatcherWin32. This is blocking and not waking on WM_INPUT events.

The windows documentation for this notes that QS_ALLINPUT, which includes QS_INPUT, “does not include QS_RAWINPUT in Windows2000.” Therefore, the problem is that the binary Qt installer is built to work on all windows platforms, so during the compile _WIN32_WINNT is defined to something less
that WinXP? (0×501) so that raw-input messages are not handled.

The fix is to re-compile Qt passing -D _WIN32_WINNT=0×501 to configure so that the WM_INPUT messages are correctly passed to the event filter when the 3D mouse is moved.

So this is not really a Qt bug, but rather that Qt is compiled for an "earlier" Windows platform which does not support Raw Input.

Sample Code for Qt and the 3D Mouse

I updated the 3DConennexion code for MFC to work with Qt. It uses an event filter to pick up the raw windows events then extracts the 3D Mouse information. This is then available as a Qt signal.

The zip file below contains a very simple application which displays the motion data in a window. This was tested with Qt 4.7.1.

3DMouse.zip

5 comments:

  1. Thanks David, it worked right out of the box. I didn't find any copyright message on it, assuming that it's OK for people to use, could you post a sentence explicitly stating there are no restrictions on using the code?

    ReplyDelete
  2. Hi Ben,
    I am glad that it was useful. I am happy for you to do whatever you like with the code. However, it was heavily based on the original 3D Connexion SDK which just supported MFC/ATL applications. That SDK is freely available (http://www.3dconnexion.com/service/software-developer.html) but has its own license agreement.

    ReplyDelete
  3. Hi David, first of all, thanks very much for posting the 3D Mouse code with Qt. I got this to work out of the box on my Win 7 x64 PC using Qt 4.8.1 for Desktop using MSVC2010 Release version as well as using Qt 4.8.0 (with MSVC 2010). I did get some errors using Mingw as a GCC for Windows on all Qt versions I tried it with (4.7.4, 4.8.0, 4.8.1), such as "'NEXTRAWINPUTBLOCK' was not declared in this scope" in Mouse3DInput.cpp - I'm trying to dig into a fix, but if you have experienced something similar, I'm all ears. :-) Again, thanks so much for posting this code.

    ReplyDelete
  4. Hi Tom, I am afraid that I only tried compiling this with MSVC. I did not try with Mingw, however, since the code uses some Microsoft specific headers I am not surprised that you get some errors from Mingw.

    ReplyDelete
  5. Hi,

    I would like to thank you for this. I have managed to implement this in a FOSS project called FreeCAD. It is released under LGPL, and each file has license info, so maybe you can help us out with this files. We can add you as original author (and/or your email and/or this address), but we need your permission to do that.

    Also, maybe you can generally help us out with license on this files, since I have no idea what to do:

    https://sourceforge.net/apps/phpbb/free-cad/viewtopic.php?f=10&t=2785

    Thanks again and Best Regards,
    Petar

    ReplyDelete