The platform dependant stuff is in different files chosen by the build system. Building on Linux/Qt5 works without libspacenav, with the X11 interface and the polling interface. All run. Spacemouse works with the polling interface and should work with the X11 interface under a real X system.

This commit is contained in:
Torsten Sadowski
2018-10-20 17:13:45 +02:00
committed by wmayer
parent 2acb6996b8
commit 48b305cd75
12 changed files with 422 additions and 157 deletions

View File

@@ -0,0 +1,11 @@
public:
GuiNativeEvent(GUIApplicationNativeEventAware *app);
~GuiNativeEvent();
void initSpaceball(QMainWindow *window);
private:
GuiNativeEvent();
GuiNativeEvent(const GuiNativeEvent&);
GuiNativeEvent& operator=(const GuiNativeEvent&);
GUIApplicationNativeEventAware *mainApp;
int motionDataArray[6];

View File

@@ -5,7 +5,6 @@ Implementation by Torsten Sadowski 2018
#include "GuiNativeEventLinux.h"
#include "GuiApplicationNativeEventAware.h"
#include "SpaceballEvent.h"
#include <FCConfig.h>
#include <Base/Console.h>
#include <QMainWindow>
@@ -46,34 +45,22 @@ void Gui::GuiNativeEvent::pollSpacenav()
spnav_event ev;
while(spnav_poll_event(&ev))
{
QWidget *currentWidget = mainApp->focusWidget();
if (!currentWidget)
return;
//if (!setOSIndependentMotionData()) return;
//importSettings();
switch (ev.type)
{
case SPNAV_EVENT_MOTION:
{
Spaceball::MotionEvent *motionEvent = new Spaceball::MotionEvent();
motionEvent->setTranslations(ev.motion.x, ev.motion.y, ev.motion.z);
motionEvent->setRotations(ev.motion.rx, ev.motion.ry, ev.motion.rz);
mainApp->postEvent(currentWidget, motionEvent);
motionDataArray[0] = -ev.motion.x;
motionDataArray[1] = -ev.motion.z;
motionDataArray[2] = -ev.motion.y;
motionDataArray[3] = -ev.motion.rx;
motionDataArray[4] = -ev.motion.rz;
motionDataArray[5] = -ev.motion.ry;
mainApp->postMotionEvent(&motionDataArray[0]);
break;
}
case SPNAV_EVENT_BUTTON:
{
Spaceball::ButtonEvent *buttonEvent = new Spaceball::ButtonEvent();
buttonEvent->setButtonNumber(ev.button.bnum);
if (ev.button.press)
{
buttonEvent->setButtonStatus(Spaceball::BUTTON_PRESSED);
}
else
{
buttonEvent->setButtonStatus(Spaceball::BUTTON_RELEASED);
}
mainApp->postEvent(currentWidget, buttonEvent);
mainApp->postButtonEvent(ev.button.bnum, ev.button.press);
break;
}
}

View File

@@ -12,15 +12,9 @@ namespace Gui
class GuiNativeEvent : public QObject
{
public:
GuiNativeEvent(GUIApplicationNativeEventAware *app);
~GuiNativeEvent();
void initSpaceball(QMainWindow *window);
#include "GuiNativeEventCommon.h"
private:
GuiNativeEvent();
GuiNativeEvent(GuiNativeEvent*);
void pollSpacenav();
GUIApplicationNativeEventAware *mainApp;
};
}

View File

@@ -0,0 +1,244 @@
/*
Implementation by Torsten Sadowski 2018
*/
#include "GuiNativeEventLinuxX11.h"
#include "GuiApplicationNativeEventAware.h"
#include "SpaceballEvent.h"
#include <FCConfig.h>
#include <Base/Console.h>
#include <QMainWindow>
#include <QX11Info>
#include <spnav.h>
#if QT_VERSION >= 0x050000
#include <X11/Xlib.h>
#include "GuiRawInputEventFilter.h"
#undef Bool
#undef CursorShape
#undef Expose
#undef KeyPress
#undef KeyRelease
#undef FocusIn
#undef FocusOut
#undef FontChange
#undef None
#undef Status
#undef Unsorted
#undef False
#undef True
#undef Complex
#endif // #if QT_VERSION >= 0x050000
Gui::GuiNativeEvent::GuiNativeEvent(Gui::GUIApplicationNativeEventAware *app)
: QObject(app)
{
mainApp = app;
}
Gui::GuiNativeEvent::~GuiNativeEvent()
{
if (spnav_close())
Base::Console().Log("Couldn't disconnect from spacenav daemon\n");
else
Base::Console().Log("Disconnected from spacenav daemon\n");
}
void Gui::GuiNativeEvent::initSpaceball(QMainWindow *window)
{
if (spnav_x11_open(QX11Info::display(), window->winId()) == -1) {
Base::Console().Log("Couldn't connect to spacenav daemon\n");
} else {
Base::Console().Log("Connected to spacenav daemon\n");
mainApp->setSpaceballPresent(true);
#if QT_VERSION >= 0x050000
static auto evFilter( [](void *msg, long *result){
Q_UNUSED(result);
auto inst(dynamic_cast<Gui::GUIApplicationNativeEventAware *>(QApplication::instance()));
if (inst) {
return inst->nativeEvent->xcbEventFilter(static_cast<const xcb_client_message_event_t *>(msg));
} else {
return false;
}
} );
mainApp->installNativeEventFilter(new Gui::RawInputEventFilter(evFilter));
#endif // #if QT_VERSION >= 0x050000
}
}
#if QT_VERSION >= 0x050000
bool Gui::GuiNativeEvent::xcbEventFilter(const xcb_client_message_event_t *xcb_ev)
{
spnav_event navEvent;
// Qt4 used XEvents in native event filters, but Qt5 changed to XCB. The
// SpaceNavigator API only works with XEvent, so we need to construct a
// temporary XEvent with just enough information for spnav_x11_event()
if ((xcb_ev->response_type & 0x7F) == XCB_CLIENT_MESSAGE) {
XClientMessageEvent xev;
xev.type = ClientMessage;
xev.message_type = xcb_ev->type;
memcpy(xev.data.b, xcb_ev->data.data8, sizeof(xev.data.b));
xev.serial = 0; // These are just to squash warnings...
xev.send_event = 0;
xev.display = 0;
xev.window = 0;
xev.format = 0;
if (!spnav_x11_event(reinterpret_cast<XEvent *>(&xev), &navEvent)) {
return false;
}
} else {
return false;
}
// navEvent is now initialised
switch (navEvent.type) {
case SPNAV_EVENT_MOTION:
{
motionDataArray[0] = -navEvent.motion.x;
motionDataArray[1] = -navEvent.motion.z;
motionDataArray[2] = -navEvent.motion.y;
motionDataArray[3] = -navEvent.motion.rx;
motionDataArray[4] = -navEvent.motion.rz;
motionDataArray[5] = -navEvent.motion.ry;
mainApp->postMotionEvent(&motionDataArray[0]);
return true;
}
case SPNAV_EVENT_BUTTON:
{
auto buttonEvent(new Spaceball::ButtonEvent());
buttonEvent->setButtonNumber(navEvent.button.bnum);
if (navEvent.button.press) {
buttonEvent->setButtonStatus(Spaceball::BUTTON_PRESSED);
} else {
buttonEvent->setButtonStatus(Spaceball::BUTTON_RELEASED);
}
mainApp->postButtonEvent(navEvent.button.bnum, navEvent.button.press);
return true;
}
default:
Base::Console().Log("Unknown spaceball event\n");
return true;
} // end switch (navEvent.type) {
}
#else // if QT_VERSION >= 0x050000
bool Gui::GuiNativeEvent::x11EventFilter(XEvent *event)
{
/*
First we check if we have a motion flush event:
- If there are unprocessed motion events we are in a flooding situation.
In that case we wait with generating a Spaceball event.
- A motion event counter of 0 indicates that FreeCAD is ready to process
the event. A Spaceball event, using the saved motion data, is posted.
*/
static Display* display = QX11Info::display();
static Atom motion_flush_event = XInternAtom(display, "FCMotionFlushEvent", false);
static int nMotionEvents = 0;
if (event->type == ClientMessage)
{
Atom message_type = event->xclient.message_type;
if (message_type == motion_flush_event)
{
nMotionEvents--;
if (nMotionEvents == 0)
{
mainApp->postMotionEvent(&motionDataArray);
}
return true;
} // XEvent: motion_flush_event
} // XEvent: ClientMessage
/*
From here on we deal with spacenav events only:
- motion: The event data is saved and a self addressed flush event
is sent through the window system (XEvent).
In the case of an event flooding, the motion data is added up.
- button: A Spaceball event is posted (QInputEvent).
*/
spnav_event navEvent;
if (!spnav_x11_event(event, &navEvent))
return false;
if (navEvent.type == SPNAV_EVENT_MOTION)
{
/*
If the motion data of the preceding event has not been processed
through posting an Spaceball event (flooding situation),
the motion data provided by the incoming event is added to the saved data.
*/
int dx, dy, dz, drx, dry, drz;
if (nMotionEvents == 0)
{
dx = 0;
dy = 0;
dz = 0;
drx = 0;
dry = 0;
drz = 0;
}
else
{
dx = motionDataArray[0];
dy = motionDataArray[1];
dz = motionDataArray[2];
drx = motionDataArray[3];
dry = motionDataArray[4];
drz = motionDataArray[5];
}
motionDataArray[0] = -navEvent.motion.x;
motionDataArray[1] = -navEvent.motion.z;
motionDataArray[2] = -navEvent.motion.y;
motionDataArray[3] = -navEvent.motion.rx;
motionDataArray[4] = -navEvent.motion.rz;
motionDataArray[5] = -navEvent.motion.ry;
motionDataArray[0] += dx;
motionDataArray[1] += dy;
motionDataArray[2] += dz;
motionDataArray[3] += drx;
motionDataArray[4] += dry;
motionDataArray[5] += drz;
/*
Send a self addressed flush event through the window system. This will
trigger a Spaceball event if FreeCAD is ready to do so.
*/
nMotionEvents++;
XClientMessageEvent flushEvent;
flushEvent.display = display;
flushEvent.window = event->xclient.window;
flushEvent.type = ClientMessage;
flushEvent.format = 8;
flushEvent.message_type = motion_flush_event;
XSendEvent (display, flushEvent.window, False, 0, (XEvent*)&flushEvent); // siehe spnavd, False, 0
return true;
}
if (navEvent.type == SPNAV_EVENT_BUTTON)
{
this->postButtonEvent(navEvent.button.bnum, navEvent.button.press);
return true;
}
Base::Console().Log("Unknown spaceball event\n");
return true;
}
#endif // if/else QT_VERSION >= 0x050000

View File

@@ -0,0 +1,32 @@
#ifndef GUINATIVEEVENT_H
#define GUINATIVEEVENT_H
#include <QObject>
#if QT_VERSION >= 0x050000
#include <QAbstractNativeEventFilter>
#include <xcb/xcb.h>
#include <xcb/xproto.h>
#endif
class QMainWindow;
class GUIApplicationNativeEventAware;
namespace Gui
{
class GUIApplicationNativeEventAware;
class GuiNativeEvent : public QObject
{
#include "GuiNativeEventCommon.h"
public:
#if QT_VERSION >= 0x050000
bool xcbEventFilter(const xcb_client_message_event_t *message);
#else
bool x11EventFilter(XEvent *event);
#endif // if/else QT_VERSION >= 0x050000
};
}
#endif //GUINATIVEEVENT_H

View File

@@ -46,25 +46,17 @@ uint32_t Gui::GUIApplicationNativeEventAware::lastButtons = 0;
//printf("msg->client: %d, tdxClientID: %d\n", msg->client, tdxClientID);
if (msg->client == tdxClientID)
{
Gui::GUIApplicationNativeEventAware* qapp = static_cast<Gui::GUIApplicationNativeEventAware *>(Gui::GUIApplicationNativeEventAware::instance());
if (!qapp) return;
switch (msg->command)
{
case kConnexionCmdHandleAxis:
{
//printf("TX: %d\n", msg->axis[0]);
//printf("TY: %d\n", msg->axis[1]);
//printf("TZ: %d\n", msg->axis[2]);
//printf("RX: %d\n", msg->axis[3]);
//printf("RY: %d\n", msg->axis[4]);
//printf("RZ: %d\n", msg->axis[5]);
qapp->motionDataArray[0] = msg->axis[0];
qapp->motionDataArray[1] = msg->axis[1];
qapp->motionDataArray[2] = msg->axis[2];
qapp->motionDataArray[3] = msg->axis[3];
qapp->motionDataArray[4] = msg->axis[4];
qapp->motionDataArray[5] = msg->axis[5];
qapp->Move3d();
motionDataArray[0] = -msg->axis[0];
motionDataArray[1] = msg->axis[1];
motionDataArray[2] = msg->axis[2];
motionDataArray[3] = -msg->axis[3];
motionDataArray[4] = msg->axis[4];
motionDataArray[5] = msg->axis[5];
mainApp->postMotionEvent(&motionDataArray[0])
break;
}
@@ -78,13 +70,13 @@ uint32_t Gui::GUIApplicationNativeEventAware::lastButtons = 0;
for (uint8_t bt = 0; bt < 32; bt++)
{
if (pressedButtons & 1)
qapp->Button3d(true, bt);
mainApp->postButtonEvent(bt, 1);
pressedButtons = pressedButtons>>1;
}
for (uint8_t bt = 0; bt < 32; bt++)
{
if (releasedButtons & 1)
qapp->Button3d(false, bt);
mainApp->postButtonEvent(bt, 0);
releasedButtons = releasedButtons>>1;
}
lastButtons = msg->buttons;
@@ -160,53 +152,3 @@ void Gui::GuiNativeEvent::initSpaceball(QMainWindow *window)
spaceballPresent = true;
}
/*!
Called with the processed motion data when a 3D mouse event is received
The default implementation emits a Move3d signal with the motion data
*/
void Gui::GUIApplicationNativeEventAware::Move3d()
{
QWidget *currentWidget = this->focusWidget();
if (!currentWidget)
return;
//currentWidget = mainWindow;
if (!setOSIndependentMotionData()) return;
importSettings();
Spaceball::MotionEvent *motionEvent = new Spaceball::MotionEvent();
motionEvent->setTranslations(motionDataArray[0], motionDataArray[1], motionDataArray[2]);
motionEvent->setRotations(motionDataArray[3], motionDataArray[4], motionDataArray[5]);
this->postEvent(currentWidget, motionEvent);
}
/*!
Called when a 3D mouse key is pressed or released
The default implementation emits a On3dmouseKeyDown signal with the key code.
*/
void Gui::GUIApplicationNativeEventAware::Button3d(bool buttonDown, int buttonNumber)
{
QWidget *currentWidget = this->focusWidget();
if (!currentWidget)
return;
// currentWidget = mainWindow;
Spaceball::ButtonEvent *buttonEvent = new Spaceball::ButtonEvent();
buttonEvent->setButtonNumber(buttonNumber);
if (buttonDown)
{
//printf("Button %d pressed\n", buttonNumber);
buttonEvent->setButtonStatus(Spaceball::BUTTON_PRESSED);
}
else
{
//printf("Button %d released\n", buttonNumber);
buttonEvent->setButtonStatus(Spaceball::BUTTON_RELEASED);
}
this->postEvent(currentWidget, buttonEvent);
}

View File

@@ -25,24 +25,13 @@ namespace Gui
class GuiNativeEvent : public QObject
{
public:
GuiNativeEvent(GUIApplicationNativeEventAware *app);
~GuiNativeEvent();
void initSpaceball(QMainWindow *window);
#include "GuiNativeEventCommon.h"
private:
GuiNativeEvent();
GuiNativeEvent(GuiNativeEvent*);
bool spaceballPresent;
GUIApplicationNativeEventAware *mainApp;
static UInt16 tdxClientID; /* ID assigned by the driver */
static uint32_t lastButtons;
static void tdx_drv_handler( io_connect_t connection,
natural_t messageType,
void *messageArgument );
void Move3d();
void Button3d(bool buttonDown, int buttonNumber);
};
}

View File

@@ -18,19 +18,7 @@ class GUIApplicationNativeEventAware;
namespace Gui
{
class GUIApplicationNativeEventAware;
class GuiNativeEvent : public QObject
{
public:
GuiNativeEvent(GUIApplicationNativeEventAware *app);
~GuiNativeEvent();
void initSpaceball(QMainWindow *window);
private:
GuiNativeEvent();
GuiNativeEvent(GuiNativeEvent*);
GUIApplicationNativeEventAware *mainApp;
#if QT_VERSION >= 0x050000
class RawInputEventFilter : public QAbstractNativeEventFilter
{
public:
@@ -47,6 +35,19 @@ namespace Gui
private:
EventFilter eventFilter;
};
#endif // if QT_VERSION >= 0x050000
class GUIApplicationNativeEventAware;
class GuiNativeEvent : public QObject
{
public:
GuiNativeEvent(GUIApplicationNativeEventAware *app);
~GuiNativeEvent();
void initSpaceball(QMainWindow *window);
private:
GuiNativeEvent();
GuiNativeEvent(GuiNativeEvent*);
GUIApplicationNativeEventAware *mainApp;
public:
static bool Is3dmouseAttached();

View File

@@ -0,0 +1,24 @@
#ifndef GUIRAWNATIVEINPUTEVENTFILTER_H
#define GUIRAWNATIVEINPUTEVENTFILTER_H
namespace Gui
{
class RawInputEventFilter : public QAbstractNativeEventFilter
{
public:
typedef bool (*EventFilter)(void *message, long *result);
RawInputEventFilter(EventFilter filter) : eventFilter(filter) {
}
virtual ~RawInputEventFilter() {
}
virtual bool nativeEventFilter(const QByteArray & /*eventType*/, void *message, long *result) {
return eventFilter(message, result);
}
private:
EventFilter eventFilter;
};
} //namespace Gui
#endif //GUIRAWNATIVEINPUTEVENTFILTER_H

View File

@@ -106,6 +106,29 @@ else()
endif()
IF(SPNAV_FOUND)
if(SPNAV_USE_X11)
add_definitions(-DSPNAV_USE_X11)
if (BUILD_QT5 AND UNIX AND NOT APPLE)
find_package(Qt5X11Extras REQUIRED)
include_directories(${Qt5X11Extras_INCLUDE_DIRS})
list(APPEND FreeCADGui_LIBS ${Qt5X11Extras_LIBRARIES})
endif()
find_package(X11 QUIET)
if (X11_FOUND)
list(APPEND FreeCADGui_LIBS
${X11_X11_LIB}
)
endif(X11_FOUND)
SET(FreeCADGui_SDK_SRCS
3Dconnexion/GuiNativeEventLinuxX11.cpp
)
else(SPNAV_USE_X11)
SET(FreeCADGui_SDK_SRCS
3Dconnexion/GuiNativeEventLinux.cpp
)
endif(SPNAV_USE_X11)
SOURCE_GROUP("3D connexion SDK" FILES ${FreeCADGui_SDK_SRCS})
add_definitions(-DSPNAV_FOUND)
include_directories(
${SPNAV_INCLUDE_DIR}
@@ -196,13 +219,6 @@ SET(FreeCADGui_SDK_SRCS
SOURCE_GROUP("3D connexion SDK" FILES ${FreeCADGui_SDK_SRCS})
endif(FREECAD_USE_3DCONNEXION AND APPLE)
if(UNIX AND NOT APPLE)
SET(FreeCADGui_SDK_SRCS
3Dconnexion/GuiNativeEventLinux.cpp
)
SOURCE_GROUP("3D connexion SDK" FILES ${FreeCADGui_SDK_SRCS})
endif(UNIX AND NOT APPLE)
set(Gui_MOC_HDRS
Action.h
ActionFunction.h

View File

@@ -30,32 +30,13 @@
#include "GuiApplicationNativeEventAware.h"
#include "SpaceballEvent.h"
#include "Application.h"
#if defined(Q_OS_LINUX)
#if QT_VERSION >= 0x050000
#undef Bool
#undef CursorShape
#undef Expose
#undef KeyPress
#undef KeyRelease
#undef FocusIn
#undef FocusOut
#undef FontChange
#undef None
#undef Status
#undef Unsorted
#undef False
#undef True
#undef Complex
#endif // #if QT_VERSION >= 0x050000
#endif // if defined(Q_OS_LINUX)
Gui::GUIApplicationNativeEventAware::GUIApplicationNativeEventAware(int &argc, char *argv[]) :
QApplication (argc, argv)
{
#if defined(_USE_3DCONNEXION_SDK) || defined(SPNAV_FOUND)
nativeEvent = new Gui::GuiNativeEvent(this);
#endif
}
Gui::GUIApplicationNativeEventAware::~GUIApplicationNativeEventAware()
@@ -64,7 +45,9 @@ Gui::GUIApplicationNativeEventAware::~GUIApplicationNativeEventAware()
void Gui::GUIApplicationNativeEventAware::initSpaceball(QMainWindow *window)
{
#if defined(_USE_3DCONNEXION_SDK) || defined(SPNAV_FOUND)
nativeEvent->initSpaceball(window);
#endif
Spaceball::MotionEvent::MotionEventType = QEvent::registerEventType();
Spaceball::ButtonEvent::ButtonEventType = QEvent::registerEventType();
}
@@ -105,6 +88,39 @@ bool Gui::GUIApplicationNativeEventAware::processSpaceballEvent(QObject *object,
return true;
}
void Gui::GUIApplicationNativeEventAware::postMotionEvent(int *const motionDataArray)
{
auto currentWidget(focusWidget());
if (!currentWidget) {
return;
}
importSettings(motionDataArray);
Spaceball::MotionEvent *motionEvent = new Spaceball::MotionEvent();
motionEvent->setTranslations(motionDataArray[0], motionDataArray[1], motionDataArray[2]);
motionEvent->setRotations(motionDataArray[3], motionDataArray[4], motionDataArray[5]);
this->postEvent(currentWidget, motionEvent);
}
void Gui::GUIApplicationNativeEventAware::postButtonEvent(int buttonNumber, int buttonPress)
{
auto currentWidget(focusWidget());
if (!currentWidget) {
return;
}
Spaceball::ButtonEvent *buttonEvent = new Spaceball::ButtonEvent();
buttonEvent->setButtonNumber(buttonNumber);
if (buttonPress)
{
buttonEvent->setButtonStatus(Spaceball::BUTTON_PRESSED);
}
else
{
buttonEvent->setButtonStatus(Spaceball::BUTTON_RELEASED);
}
this->postEvent(currentWidget, buttonEvent);
}
float Gui::GUIApplicationNativeEventAware::convertPrefToSensitivity(int value)
{
@@ -129,7 +145,7 @@ float Gui::GUIApplicationNativeEventAware::convertPrefToSensitivity(int value)
// motionDataArray[5] - Spin mouse - rotate around "Zoom" axis on screen
bool Gui::GUIApplicationNativeEventAware::setOSIndependentMotionData()
/*bool Gui::GUIApplicationNativeEventAware::setOSIndependentMotionData()
{
#ifdef SPNAV_FOUND
int temp;
@@ -150,9 +166,9 @@ bool Gui::GUIApplicationNativeEventAware::setOSIndependentMotionData()
return false;
#endif
return true;
}
}*/
void Gui::GUIApplicationNativeEventAware::importSettings()
void Gui::GUIApplicationNativeEventAware::importSettings(int *const motionDataArray)
{
ParameterGrp::handle group = App::GetApplication().GetUserParameter().GetGroup("BaseApp")->GetGroup("Spaceball")->GetGroup("Motion");

View File

@@ -29,13 +29,19 @@
class QMainWindow;
#if defined(_USE_3DCONNEXION_SDK) || defined(SPNAV_FOUND)
#if defined(Q_OS_LINUX)
#include "3Dconnexion/GuiNativeEventLinux.h"
#if defined(SPNAV_USE_X11)
#include "3Dconnexion/GuiNativeEventLinuxX11.h"
#else
#include "3Dconnexion/GuiNativeEventLinux.h"
#endif
#elif defined(Q_OS_WIN)
#include "3Dconnexion/GuiNativeEventWin32.h"
#include "3Dconnexion/GuiNativeEventWin32.h"
#elif defined(Q_OS_MACX)
#include "3Dconnexion/GuiNativeEventMac.h"
#include "3Dconnexion/GuiNativeEventMac.h"
#endif // Platform switch
#endif // Spacemice
namespace Gui
{
@@ -49,13 +55,16 @@ namespace Gui
bool isSpaceballPresent() const {return spaceballPresent;}
void setSpaceballPresent(bool present) {spaceballPresent = present;}
bool processSpaceballEvent(QObject *object, QEvent *event);
void postMotionEvent(int *const motionDataArray);
void postButtonEvent(int buttonNumber, int buttonPress);
private:
bool spaceballPresent;
int motionDataArray[6];
bool setOSIndependentMotionData();
void importSettings();
void importSettings(int *const motionDataArray);
float convertPrefToSensitivity(int value);
#if defined(_USE_3DCONNEXION_SDK) || defined(SPNAV_FOUND)
GuiNativeEvent *nativeEvent;
friend void GuiNativeEvent::initSpaceball(QMainWindow *window);
#endif
}; // end class GUIApplicationNativeEventAware
} // end namespace Gui