Skip to content

Commit 1d4bc79

Browse files
committed
Windows - register native event handler for WM_INPUT to track 3d mouse
1 parent e1e2c20 commit 1d4bc79

8 files changed

Lines changed: 199 additions & 3 deletions

File tree

occt-qopenglwidget/OcctQOpenGLWidgetViewer.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,23 @@ OcctQOpenGLWidgetViewer::~OcctQOpenGLWidgetViewer()
114114
aDisp.Nullify();
115115
}
116116

117+
// ================================================================
118+
// Function : nativeEventFilter
119+
// ================================================================
120+
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
121+
bool OcctQOpenGLWidgetViewer::nativeEventFilter(const QByteArray& theEventType, void* theMsg, qintptr* )
122+
#else
123+
bool OcctQOpenGLWidgetViewer::nativeEventFilter(const QByteArray& theEventType, void* theMsg, long* )
124+
#endif
125+
{
126+
if (OcctQtTools::qtHandleNativeEvent(*this, myView, theEventType, theMsg))
127+
{
128+
updateView();
129+
return true;
130+
}
131+
return false;
132+
}
133+
117134
// ================================================================
118135
// Function : event
119136
// ================================================================
@@ -334,6 +351,12 @@ void OcctQOpenGLWidgetViewer::initializeGL()
334351
dumpGlInfo(true, true);
335352
if (isFirstInit)
336353
{
354+
// handle raw WM_INPUT events to catch input from WNT_HIDSpaceMouse (HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER);
355+
// the same could be done also done for tracking precise mouse input (HID_USAGE_GENERIC_MOUSE RIM_TYPEMOUSE)
356+
if (OcctQtTools::qtRegisterRawInput(aNativeWin))
357+
QCoreApplication::instance()->installNativeEventFilter(this);
358+
359+
// auxiliary objects
337360
myContext->Display(myViewCube, 0, 0, false);
338361

339362
// dummy shape for testing

occt-qopenglwidget/OcctQOpenGLWidgetViewer.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#define _OcctQOpenGLWidgetViewer_HeaderFile
55

66
#include <Standard_WarningsDisable.hxx>
7+
#include <QAbstractNativeEventFilter>
78
#include <QOpenGLWidget>
89
#include <Standard_WarningsRestore.hxx>
910

@@ -22,7 +23,7 @@ class AIS_ViewCube;
2223
//! Inheritance from AIS_ViewController is used to translate
2324
//! user input events (mouse, keyboard, window resize, etc.)
2425
//! to 3D Viewer (panning, rotation, zooming, etc.).
25-
class OcctQOpenGLWidgetViewer : public QOpenGLWidget, public AIS_ViewController
26+
class OcctQOpenGLWidgetViewer : public QOpenGLWidget, public QAbstractNativeEventFilter, public AIS_ViewController
2627
{
2728
Q_OBJECT
2829
public:
@@ -71,6 +72,13 @@ class OcctQOpenGLWidgetViewer : public QOpenGLWidget, public AIS_ViewController
7172
virtual void mouseMoveEvent(QMouseEvent* theEvent) override;
7273
virtual void wheelEvent(QWheelEvent* theEvent) override;
7374

75+
//! Handle native events (QAbstractNativeEventFilter interface).
76+
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
77+
virtual bool nativeEventFilter(const QByteArray& theEventType, void* theMsg, qintptr* theRes) override;
78+
#else
79+
virtual bool nativeEventFilter(const QByteArray& theEventType, void* theMsg, long* theRes) override;
80+
#endif
81+
7482
private:
7583
//! Dump OpenGL info.
7684
void dumpGlInfo(bool theIsBasic, bool theToPrint);

occt-qt-tools/OcctQtTools.cpp

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
// Copyright (c) 2025 Kirill Gavrilov
22

3+
#ifdef _WIN32
4+
// should be included before other headers to avoid missing definitions
5+
#include <windows.h>
6+
#endif
7+
38
#include "OcctQtTools.h"
49

510
#include <Aspect_ScrollDelta.hxx>
611
#include <Message.hxx>
12+
#include <NCollection_LocalArray.hxx>
713
#include <OpenGl_Caps.hxx>
814
#include <OSD_Environment.hxx>
915
#include <Standard_Version.hxx>
1016
#include <V3d_View.hxx>
17+
#include <WNT_HIDSpaceMouse.hxx>
1118

1219
#include <Standard_WarningsDisable.hxx>
1320
#include <QCoreApplication>
@@ -366,6 +373,75 @@ bool OcctQtTools::qtHandleTouchEvent(Aspect_WindowInputListener& theListener,
366373
return hasUpdates;
367374
}
368375

376+
// ================================================================
377+
// Function : qtRegisterRawInput
378+
// ================================================================
379+
bool OcctQtTools::qtRegisterRawInput(Aspect_Drawable theWinId)
380+
{
381+
#ifdef _WIN32
382+
// handle raw WM_INPUT events to catch input from WNT_HIDSpaceMouse (HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER);
383+
// the same could be done also done for tracking precise mouse input (HID_USAGE_GENERIC_MOUSE RIM_TYPEMOUSE)
384+
RAWINPUTDEVICE aRawSpace = {};
385+
aRawSpace.usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC from hidusage.h
386+
aRawSpace.usUsage = 0x08; // HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER
387+
aRawSpace.dwFlags = 0; // RIDEV_DEVNOTIFY
388+
aRawSpace.hwndTarget = (HWND )theWinId;
389+
if (!RegisterRawInputDevices(&aRawSpace, 1, sizeof(aRawSpace)))
390+
{
391+
Message::SendTrace() << "Warning: RegisterRawInputDevices() failed to register RAW multi-axis controller input";
392+
return false;
393+
}
394+
return true;
395+
#else
396+
return false;
397+
#endif
398+
}
399+
400+
// ================================================================
401+
// Function : qtHandleNativeEvent
402+
// ================================================================
403+
bool OcctQtTools::qtHandleNativeEvent(Aspect_WindowInputListener& theListener,
404+
const Handle(V3d_View)& theView,
405+
const QByteArray& theEventType,
406+
void* theMsg)
407+
{
408+
(void)theEventType, (void)theMsg, (void)theView, (void)theListener;
409+
#ifdef _WIN32
410+
if (theEventType == "windows_generic_MSG")
411+
{
412+
MSG* aMsg = reinterpret_cast<MSG*>(theMsg);
413+
if (aMsg->message != WM_INPUT)
414+
return false;
415+
416+
UINT aSize = 0;
417+
::GetRawInputData((HRAWINPUT )aMsg->lParam, RID_INPUT, nullptr, &aSize, sizeof(RAWINPUTHEADER));
418+
NCollection_LocalArray<BYTE> aRawData(aSize);
419+
if (aSize == 0 || ::GetRawInputData((HRAWINPUT )aMsg->lParam, RID_INPUT, aRawData, &aSize, sizeof(RAWINPUTHEADER)) != aSize)
420+
return false;
421+
422+
const RAWINPUT* aRawInput = (RAWINPUT* )(BYTE* )aRawData;
423+
if (aRawInput->header.dwType != RIM_TYPEHID)
424+
return false;
425+
426+
RID_DEVICE_INFO aDevInfo;
427+
aDevInfo.cbSize = sizeof(RID_DEVICE_INFO);
428+
UINT aDevInfoSize = sizeof(RID_DEVICE_INFO);
429+
if (::GetRawInputDeviceInfoW (aRawInput->header.hDevice, RIDI_DEVICEINFO, &aDevInfo, &aDevInfoSize) != sizeof(RID_DEVICE_INFO)
430+
|| (aDevInfo.hid.dwVendorId != WNT_HIDSpaceMouse::VENDOR_ID_LOGITECH
431+
&& aDevInfo.hid.dwVendorId != WNT_HIDSpaceMouse::VENDOR_ID_3DCONNEXION))
432+
return false;
433+
434+
// see also 3d mouse input settings in AIS_ViewController to tune behavior
435+
WNT_HIDSpaceMouse aSpaceData(aDevInfo.hid.dwProductId, aRawInput->data.hid.bRawData, aRawInput->data.hid.dwSizeHid);
436+
if (theListener.Update3dMouse(aSpaceData))
437+
return true;
438+
439+
return false;
440+
}
441+
#endif
442+
return false;
443+
}
444+
369445
// ================================================================
370446
// Function : qtMouseButtons2VKeys
371447
// ================================================================

occt-qt-tools/OcctQtTools.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#ifndef _OcctQtTools_HeaderFile
44
#define _OcctQtTools_HeaderFile
55

6+
#include <Aspect_Drawable.hxx>
67
#include <Aspect_WindowInputListener.hxx>
78
#include <Message_Gravity.hxx>
89
#include <Quantity_ColorRGBA.hxx>
@@ -91,6 +92,15 @@ class OcctQtTools
9192
const Handle(V3d_View)& theView,
9293
const QTouchEvent* theEvent);
9394

95+
//! Register raw input events (like WM_INPUT from 3d mouse).
96+
static bool qtRegisterRawInput(Aspect_Drawable theWinId);
97+
98+
//! Queue Qt native event (like WM_INPUT from 3d mouse) to OCCT listener.
99+
static bool qtHandleNativeEvent(Aspect_WindowInputListener& theListener,
100+
const Handle(V3d_View)& theView,
101+
const QByteArray& theEventType,
102+
void* theMsg);
103+
94104
//! Map Qt buttons bitmask to virtual keys.
95105
static Aspect_VKeyMouse qtMouseButtons2VKeys(Qt::MouseButtons theButtons);
96106

occt-qtquick/OcctQQuickFramebufferViewer.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
#include <Aspect_DisplayConnection.hxx>
2424
#include <BRepPrimAPI_MakeBox.hxx>
2525
#include <Message.hxx>
26+
#include <NCollection_LocalArray.hxx>
2627
#include <OpenGl_GraphicDriver.hxx>
28+
#include <WNT_HIDSpaceMouse.hxx>
2729

2830
#if !defined(__APPLE__) && !defined(_WIN32) && defined(__has_include)
2931
#if __has_include(<Xw_DisplayConnection.hxx>)
@@ -86,6 +88,9 @@ OcctQQuickFramebufferViewer::OcctQQuickFramebufferViewer(QQuickItem* theParent)
8688
setAcceptHoverEvents(true);
8789
setMirrorVertically(true);
8890

91+
// signals and slots
92+
connect(this, SIGNAL(windowChanged(QQuickWindow*)), this, SLOT(onWindowChanged(QQuickWindow*)));
93+
8994
// GUI elements cannot be created from GL rendering thread - make queued connection
9095
connect(this, &OcctQQuickFramebufferViewer::glCriticalError, this, [this](QString theMsg)
9196
{
@@ -115,6 +120,37 @@ OcctQQuickFramebufferViewer::~OcctQQuickFramebufferViewer()
115120
aDisp.Nullify();
116121
}
117122

123+
// ================================================================
124+
// Function : onWindowChanged
125+
// ================================================================
126+
void OcctQQuickFramebufferViewer::onWindowChanged(QQuickWindow* theWin)
127+
{
128+
if (theWin == nullptr)
129+
return;
130+
131+
// handle raw WM_INPUT events to catch input from WNT_HIDSpaceMouse (HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER);
132+
// the same could be done also done for tracking precise mouse input (HID_USAGE_GENERIC_MOUSE RIM_TYPEMOUSE)
133+
if (OcctQtTools::qtRegisterRawInput((Aspect_Drawable)theWin->winId()))
134+
QCoreApplication::instance()->installNativeEventFilter(this);
135+
}
136+
137+
// ================================================================
138+
// Function : nativeEventFilter
139+
// ================================================================
140+
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
141+
bool OcctQQuickFramebufferViewer::nativeEventFilter(const QByteArray& theEventType, void* theMsg, qintptr* )
142+
#else
143+
bool OcctQQuickFramebufferViewer::nativeEventFilter(const QByteArray& theEventType, void* theMsg, long* )
144+
#endif
145+
{
146+
if (OcctQtTools::qtHandleNativeEvent(*this, myView, theEventType, theMsg))
147+
{
148+
updateView();
149+
return true;
150+
}
151+
return false;
152+
}
153+
118154
// ================================================================
119155
// Function : event
120156
// ================================================================

occt-qtquick/OcctQQuickFramebufferViewer.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "../occt-qt-tools/OcctQtTools.h"
77

88
#include <Standard_WarningsDisable.hxx>
9+
#include <QAbstractNativeEventFilter>
910
#include <QQuickFramebufferObject>
1011
#include <Standard_WarningsRestore.hxx>
1112

@@ -24,7 +25,7 @@ class AIS_ViewCube;
2425
//! Inheritance from AIS_ViewController is used to translate
2526
//! user input events (mouse, keyboard, window resize, etc.)
2627
//! to 3D Viewer (panning, rotation, zooming, etc.).
27-
class OcctQQuickFramebufferViewer : public QQuickFramebufferObject, public AIS_ViewController
28+
class OcctQQuickFramebufferViewer : public QQuickFramebufferObject, public QAbstractNativeEventFilter, public AIS_ViewController
2829
{
2930
Q_OBJECT
3031

@@ -100,6 +101,17 @@ class OcctQQuickFramebufferViewer : public QQuickFramebufferObject, public AIS_V
100101
virtual void hoverLeaveEvent(QHoverEvent* theEvent) override;
101102
//virtual void touchEvent(QTouchEvent* theEvent) override;
102103

104+
//! Handle native events (QAbstractNativeEventFilter interface).
105+
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
106+
virtual bool nativeEventFilter(const QByteArray& theEventType, void* theMsg, qintptr* theRes) override;
107+
#else
108+
virtual bool nativeEventFilter(const QByteArray& theEventType, void* theMsg, long* theRes) override;
109+
#endif
110+
111+
private slots:
112+
//! Handle window change event.
113+
void onWindowChanged(QQuickWindow* theWin);
114+
103115
private:
104116
//! Dump OpenGL info.
105117
void dumpGlInfo(bool theIsBasic, bool theToPrint);

occt-qwidget/OcctQWidgetViewer.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,23 @@ OcctQWidgetViewer::~OcctQWidgetViewer()
102102
aDisp.Nullify();
103103
}
104104

105+
// ================================================================
106+
// Function : nativeEventFilter
107+
// ================================================================
108+
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
109+
bool OcctQWidgetViewer::nativeEventFilter(const QByteArray& theEventType, void* theMsg, qintptr* )
110+
#else
111+
bool OcctQWidgetViewer::nativeEventFilter(const QByteArray& theEventType, void* theMsg, long* )
112+
#endif
113+
{
114+
if (OcctQtTools::qtHandleNativeEvent(*this, myView, theEventType, theMsg))
115+
{
116+
updateView();
117+
return true;
118+
}
119+
return false;
120+
}
121+
105122
// ================================================================
106123
// Function : event
107124
// ================================================================
@@ -342,6 +359,12 @@ void OcctQWidgetViewer::initializeGL()
342359

343360
if (isFirstInit)
344361
{
362+
// handle raw WM_INPUT events to catch input from WNT_HIDSpaceMouse (HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER);
363+
// the same could be done also done for tracking precise mouse input (HID_USAGE_GENERIC_MOUSE RIM_TYPEMOUSE)
364+
if (OcctQtTools::qtRegisterRawInput(aNativeWin))
365+
QCoreApplication::instance()->installNativeEventFilter(this);
366+
367+
// auxiliary objects
345368
myContext->Display(myViewCube, 0, 0, false);
346369

347370
// dummy shape for testing

occt-qwidget/OcctQWidgetViewer.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#define _OcctQWidgetViewer_HeaderFile
55

66
#include <Standard_WarningsDisable.hxx>
7+
#include <QAbstractNativeEventFilter>
78
#include <QWidget>
89
#include <Standard_WarningsRestore.hxx>
910

@@ -22,7 +23,7 @@ class AIS_ViewCube;
2223
//! Inheritance from AIS_ViewController is used to translate
2324
//! user input events (mouse, keyboard, window resize, etc.)
2425
//! to 3D Viewer (panning, rotation, zooming, etc.).
25-
class OcctQWidgetViewer : public QWidget, public AIS_ViewController
26+
class OcctQWidgetViewer : public QWidget, public QAbstractNativeEventFilter, public AIS_ViewController
2627
{
2728
Q_OBJECT
2829
public:
@@ -79,6 +80,13 @@ class OcctQWidgetViewer : public QWidget, public AIS_ViewController
7980
virtual void mouseMoveEvent(QMouseEvent* theEvent) override;
8081
virtual void wheelEvent(QWheelEvent* theEvent) override;
8182

83+
//! Handle native events (QAbstractNativeEventFilter interface).
84+
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
85+
virtual bool nativeEventFilter(const QByteArray& theEventType, void* theMsg, qintptr* theRes) override;
86+
#else
87+
virtual bool nativeEventFilter(const QByteArray& theEventType, void* theMsg, long* theRes) override;
88+
#endif
89+
8290
private:
8391
//! Dump OpenGL info.
8492
void dumpGlInfo(bool theIsBasic, bool theToPrint);

0 commit comments

Comments
 (0)