diff --git a/CMakeLists.txt b/CMakeLists.txt index 332cd73db..7cc77a74a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,7 +42,6 @@ else(WIN32) set(PLATFORM_MK mkdir -p) endif(WIN32) - # ================================================================================ if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") @@ -169,16 +168,27 @@ OPTION(BUILD_WEB "Build the FreeCAD web module" ON) OPTION(BUILD_VR "Build the FreeCAD Oculus Rift support (need Oculus SDK 4.x or higher)" OFF) if(MSVC) -OPTION(FREECAD_USE_3DCONNEXION "Use the 3D connexion SDK to support 3d mouse." ON) OPTION(FREECAD_USE_FREETYPE "Builds the features using FreeType libs" OFF) OPTION(BUILD_FEM_NETGEN "Build the FreeCAD FEM module with the NETGEN mesher" ON) +OPTION(FREECAD_USE_3DCONNEXION "Use the 3D connexion SDK to support 3d mouse." ON) +elseif(APPLE) + find_library(3DCONNEXIONCLIENT_FRAMEWORK 3DconnexionClient) + if(IS_DIRECTORY ${3DCONNEXIONCLIENT_FRAMEWORK}) + OPTION(FREECAD_USE_3DCONNEXION "Use the 3D connexion + SDK to support 3d mouse." ON) + else(IS_DIRECTORY ${3DCONNEXIONCLIENT_FRAMEWORK}) + OPTION(FREECAD_USE_3DCONNEXION "Use the 3D connexion + SDK to support 3d mouse." OFF) + endif(IS_DIRECTORY ${3DCONNEXIONCLIENT_FRAMEWORK}) else(MSVC) set(FREECAD_USE_3DCONNEXION OFF) +endif(MSVC) +if(NOT MSVC) OPTION(FREECAD_USE_FREETYPE "Builds the features using FreeType libs" ON) OPTION(BUILD_FEM_NETGEN "Build the FreeCAD FEM module with the NETGEN mesher" OFF) OPTION(FREECAD_USE_PCL "Build the features that use PCL libs" OFF) OPTION(FREECAD_USE_EXTERNAL_PIVY "Use system installed python-pivy instead of the bundled." ON) -endif(MSVC) +endif(NOT MSVC) # if this is set override some options if (FREECAD_BUILD_DEBIAN) diff --git a/src/Gui/3Dconnexion/GuiApplicationNativeEventAwareMac.cpp b/src/Gui/3Dconnexion/GuiApplicationNativeEventAwareMac.cpp new file mode 100644 index 000000000..008a281c1 --- /dev/null +++ b/src/Gui/3Dconnexion/GuiApplicationNativeEventAwareMac.cpp @@ -0,0 +1,156 @@ +/* +Development tools and related technology provided under license from 3Dconnexion. +(c) 1992 - 2012 3Dconnexion. All rights reserved +*/ + + /* +Implementation by Torsten Sadowski 2015 +with special thanks to marcxs for making the first steps + */ + +#include +#include "GUIApplicationNativeEventAware.h" +#include "SpaceballEvent.h" +#include + + + +UInt16 Gui::GUIApplicationNativeEventAware::tdxClientID = 0; +uint32_t Gui::GUIApplicationNativeEventAware::lastButtons = 0; + + /* ---------------------------------------------------------------------------- + Handler for driver events. This function is able to handle the events in + different ways: (1) re-package the events as Carbon events, (2) compute + them directly, (3) write the event info in a shared memory location for + usage by reader threads. + */ + void + Gui::GUIApplicationNativeEventAware::tdx_drv_handler(io_connect_t connection, + natural_t messageType, + void *messageArgument) + { + //printf("tdx_drv_handler\n"); + //printf("connection: %X\n", connection); + //printf("messageType %c%c%c%c\n", messageType/0x1000000, messageType/0x10000, messageType/0x100, messageType); + ConnexionDeviceStatePtr msg = (ConnexionDeviceStatePtr)messageArgument; + + switch(messageType) + { + case kConnexionMsgDeviceState: + /* Device state messages are broadcast to all clients. It is up to + * the client to figure out if the message is meant for them. This + * is done by comparing the "client" id sent in the message to our + * assigned id when the connection to the driver was established. + */ + //printf("msg->client: %d, tdxClientID: %d\n", msg->client, tdxClientID); + if (msg->client == tdxClientID) + { + Gui::GUIApplicationNativeEventAware* qapp = static_cast(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(); + break; + } + + case kConnexionCmdHandleButtons: + { + //printf("value: %d\n", msg->value); + //printf("buttons: %u\n", msg->buttons); + uint32_t changedButtons = msg->buttons ^ lastButtons; + uint32_t pressedButtons = msg->buttons & changedButtons; + uint32_t releasedButtons = lastButtons & changedButtons; + for (uint8_t bt = 0; bt < 32; bt++) + { + if (pressedButtons & 1) + qapp->Button3d(true, bt); + pressedButtons = pressedButtons>>1; + } + for (uint8_t bt = 0; bt < 32; bt++) + { + if (releasedButtons & 1) + qapp->Button3d(false, bt); + releasedButtons = releasedButtons>>1; + } + lastButtons = msg->buttons; + break; + } + + default: + break; + + } /* switch */ + } + + break; + + default: + /* other messageTypes can happen and should be ignored */ + break; + } + } + +/*! + 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); +} + diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index 05f1afaf8..d3f76d775 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -6,7 +6,11 @@ endif(WIN32) if (FREECAD_USE_3DCONNEXION) add_definitions(-D_USE_3DCONNEXION_SDK) -endif(FREECAD_USE_3DCONNEXION) + if(APPLE) + set(3DCONNEXION_LINKFLAGS "-F/Library/Frameworks -weak_framework 3DconnexionClient") + set(3DCONNEXION_INCLUDE_DIR ${3DCONNEXIONCLIENT_FRAMEWORK}/Headers ) + endif(APPLE) + endif(FREECAD_USE_3DCONNEXION) if (BUILD_VR) add_definitions(-DBUILD_VR ) @@ -28,6 +32,7 @@ include_directories( ${XERCESC_INCLUDE_DIR} ${QT_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} + ${3DCONNEXION_INCLUDE_DIR} ) if(MSVC) @@ -49,6 +54,7 @@ else(MSVC) ${QT_LIBRARIES} ${Boost_LIBRARIES} ${OPENGL_gl_LIBRARY} + ${3DCONNEXION_LINKFLAGS} ) endif(MSVC) @@ -121,7 +127,7 @@ SET(FreeCADGui_XML_SRCS SOURCE_GROUP("XML" FILES ${FreeCADApp_XML_SRCS}) # The 3D Connexion SDK files -if(FREECAD_USE_3DCONNEXION) +if(FREECAD_USE_3DCONNEXION AND MSVC) SET(FreeCADGui_SDK_SRCS 3Dconnexion/I3dMouseParams.h 3Dconnexion/MouseParameters.cpp @@ -129,7 +135,13 @@ SET(FreeCADGui_SDK_SRCS 3Dconnexion/GuiApplicationNativeEventAwareWin32.cpp ) SOURCE_GROUP("3D connexion SDK" FILES ${FreeCADGui_SDK_SRCS}) -endif(FREECAD_USE_3DCONNEXION) +endif(FREECAD_USE_3DCONNEXION AND MSVC) + +if(FREECAD_USE_3DCONNEXION AND APPLE) +SET(FreeCADGui_SDK_SRCS + 3Dconnexion/GuiApplicationNativeEventAwareMac.cpp) +SOURCE_GROUP("3D connexion SDK" FILES ${FreeCADGui_SDK_SRCS}) +endif(FREECAD_USE_3DCONNEXION AND APPLE) set(Gui_MOC_HDRS Action.h @@ -927,6 +939,7 @@ SET(FreeCADGui_SRCS SET(FreeCADGui_SRCS ${FreeCADGui_SDK_SRCS} + ${FreeCADGui_SDK_SRCS_Mac} ${FreeCADGui_CPP_SRCS} ${FreeCADGui_XML_SRCS} ${iis_MOC_SRCS} diff --git a/src/Gui/GuiApplicationNativeEventAware.cpp b/src/Gui/GuiApplicationNativeEventAware.cpp index 2ae0d3dd0..dfe39819e 100644 --- a/src/Gui/GuiApplicationNativeEventAware.cpp +++ b/src/Gui/GuiApplicationNativeEventAware.cpp @@ -42,8 +42,11 @@ #endif #ifdef _USE_3DCONNEXION_SDK +//windows +#ifdef Q_WS_WIN Gui::GUIApplicationNativeEventAware* Gui::GUIApplicationNativeEventAware::gMouseInput = 0; #endif +#endif //_USE_3DCONNEXION_SDK Gui::GUIApplicationNativeEventAware::GUIApplicationNativeEventAware(int &argc, char *argv[]) : QApplication (argc, argv), spaceballPresent(false) @@ -53,24 +56,44 @@ Gui::GUIApplicationNativeEventAware::GUIApplicationNativeEventAware(int &argc, c Gui::GUIApplicationNativeEventAware::~GUIApplicationNativeEventAware() { +#ifdef Q_WS_X11 #ifdef SPNAV_FOUND if (spnav_close()) Base::Console().Log("Couldn't disconnect from spacenav daemon\n"); else Base::Console().Log("Disconnected from spacenav daemon\n"); #endif +#endif #ifdef _USE_3DCONNEXION_SDK +#ifdef Q_WS_WIN if (gMouseInput == this) { gMouseInput = 0; } #endif +//mac +#ifdef Q_WS_MACX + /* make sure the framework is installed */ + if (InstallConnexionHandlers == NULL) + { + Base::Console().Log("3Dconnexion framework not found!\n"); + return; + } + /* close the connection with the 3dx driver */ + //std::cerr << "tdxClientID: " << tdxClientID << std::endl; + if (tdxClientID) + UnregisterConnexionClient(tdxClientID); + CleanupConnexionHandlers(); + Base::Console().Log("Disconnected from 3DConnexion driver\n"); +#endif +#endif } void Gui::GUIApplicationNativeEventAware::initSpaceball(QMainWindow *window) { mainWindow = window; +#ifdef Q_WS_X11 #ifdef SPNAV_FOUND if (spnav_x11_open(QX11Info::display(), window->winId()) == -1) Base::Console().Log("Couldn't connect to spacenav daemon\n"); @@ -80,8 +103,10 @@ void Gui::GUIApplicationNativeEventAware::initSpaceball(QMainWindow *window) spaceballPresent = true; } #endif +#endif #ifdef _USE_3DCONNEXION_SDK +#ifdef Q_WS_WIN spaceballPresent = Is3dmouseAttached(); if (spaceballPresent) { @@ -92,6 +117,42 @@ void Gui::GUIApplicationNativeEventAware::initSpaceball(QMainWindow *window) qApp->setEventFilter(Gui::GUIApplicationNativeEventAware::RawInputEventFilter); } } +#endif +//mac +#ifdef Q_WS_MACX + OSStatus err; + /* make sure the framework is installed */ + if (InstallConnexionHandlers == NULL) + { + Base::Console().Log("3Dconnexion framework not found!\n"); + return; + } + /* install 3dx message handler in order to receive driver events */ + err = InstallConnexionHandlers(tdx_drv_handler, 0L, 0L); + assert(err == 0); + if (err) + { + Base::Console().Log("Error installing 3Dconnexion handler\n"); + return; + } + /* register our app with the driver */ + //Pascal string Application name required to register driver for application + UInt8 tdxAppName[] = {7,'F','r','e','e','C','A','D'}; + //32bit appID to register driver for application + UInt32 tdxAppID = 'FCAd'; + //std::cerr << "tdxClientID: " << tdxClientID << std::endl; + tdxClientID = RegisterConnexionClient(tdxAppID, tdxAppName, kConnexionClientModeTakeOver, kConnexionMaskAll); + //std::cerr << "tdxClientID: " << tdxClientID << std::endl; + if (tdxClientID == 0) + { + Base::Console().Log("Couldn't connect to 3Dconnexion driver\n"); + return; + } + + Base::Console().Log("3Dconnexion device initialized. Client ID: %d\n", + tdxClientID); + spaceballPresent = true; +#endif #endif // _USE_3DCONNEXION_SDK Spaceball::MotionEvent::MotionEventType = QEvent::registerEventType(); @@ -106,6 +167,7 @@ bool Gui::GUIApplicationNativeEventAware::processSpaceballEvent(QObject *object, QApplication::notify(object, event); if (event->type() == Spaceball::MotionEvent::MotionEventType) { +Base::Console().Log("process motion event\n"); Spaceball::MotionEvent *motionEvent = dynamic_cast(event); if (!motionEvent) return true; diff --git a/src/Gui/GuiApplicationNativeEventAware.h b/src/Gui/GuiApplicationNativeEventAware.h index 89fef7c7e..0bab3aae1 100644 --- a/src/Gui/GuiApplicationNativeEventAware.h +++ b/src/Gui/GuiApplicationNativeEventAware.h @@ -31,6 +31,7 @@ class QMainWindow; #ifdef _USE_3DCONNEXION_SDK +#ifdef Q_WS_WIN #include "3Dconnexion/MouseParameters.h" #include @@ -39,7 +40,15 @@ class QMainWindow; //#define _WIN32_WINNT 0x0501 //target at least windows XP #include - +#endif // Q_WS_WIN +#ifdef Q_WS_MACX +#include <3DconnexionClient/ConnexionClientAPI.h> +extern OSErr InstallConnexionHandlers(ConnexionMessageHandlerProc messageHandler, ConnexionAddedHandlerProc addedHandler, ConnexionRemovedHandlerProc removedHandler) + __attribute__((weak_import)); +extern UInt16 RegisterConnexionClient(UInt32 signature, UInt8 *name, UInt16 mode, UInt32 mask) __attribute__((weak_import)); +extern void UnregisterConnexionClient(UInt16 clientID) __attribute__((weak_import)); +extern void CleanupConnexionHandlers(void) __attribute__((weak_import)); +#endif // Q_WS_MACX #endif // _USE_3DCONNEXION_SDK namespace Gui @@ -67,8 +76,9 @@ namespace Gui bool x11EventFilter(XEvent *event); #endif // Q_WS_X11 -// For Windows #ifdef _USE_3DCONNEXION_SDK +// For Windows +#ifdef Q_WS_WIN public: static bool Is3dmouseAttached(); @@ -112,6 +122,17 @@ namespace Gui // use to calculate distance traveled since last event DWORD fLast3dmouseInputTime; static Gui::GUIApplicationNativeEventAware* gMouseInput; +#endif // Q_WS_WIN +#ifdef Q_WS_MACX + private: + static UInt16 tdxClientID; /* ID assigned by the driver */ + static uint32_t lastButtons; + public: + static void tdx_drv_handler(io_connect_t connection, natural_t messageType, void *messageArgument); + void Move3d(); + void Button3d(bool buttonDown, int buttonNumber); + +#endif// Q_WS_MACX #endif // _USE_3DCONNEXION_SDK }; }