Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Erwin <significant.bit@gmail.com>2015-10-24 20:58:06 +0300
committerMike Erwin <significant.bit@gmail.com>2015-10-25 23:19:26 +0300
commitc3cec828e82de70fe92eeb7c52869d24466d4109 (patch)
tree4364ccf75853e1c2418e9417715d3239787d791a /intern/ghost/intern/GHOST_NDOFManagerCocoa.mm
parent4f767e37e8452bdc675e362b566fe9aeedb783e4 (diff)
ndof: rework Mac driver glue
Load driver dynamically at runtime instead of weak-linking the 3Dconnexion framework. Driver no longer needed at build time! Works with really old drivers (as in PowerMac old), more recent versions, and the latest which allows us to process events on a separate thread.
Diffstat (limited to 'intern/ghost/intern/GHOST_NDOFManagerCocoa.mm')
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerCocoa.mm240
1 files changed, 174 insertions, 66 deletions
diff --git a/intern/ghost/intern/GHOST_NDOFManagerCocoa.mm b/intern/ghost/intern/GHOST_NDOFManagerCocoa.mm
index 6eedaafb2d1..6fee39dcb82 100644
--- a/intern/ghost/intern/GHOST_NDOFManagerCocoa.mm
+++ b/intern/ghost/intern/GHOST_NDOFManagerCocoa.mm
@@ -23,59 +23,178 @@
#ifdef WITH_INPUT_NDOF
+#define DEBUG_NDOF_DRIVER false
+
#include "GHOST_NDOFManagerCocoa.h"
-#include "GHOST_NDOFManager3Dconnexion.h"
#include "GHOST_SystemCocoa.h"
-extern "C" {
- #include <ConnexionClientAPI.h>
- #include <stdio.h>
-}
+#include <stdint.h>
+#include <dlfcn.h>
+#if DEBUG_NDOF_DRIVER
+ #include <cstdio>
+#endif
-// static functions need to talk to these objects:
+// static callback functions need to talk to these objects:
static GHOST_SystemCocoa* ghost_system = NULL;
static GHOST_NDOFManager* ndof_manager = NULL;
-// 3Dconnexion drivers before 10.x are "old"
-// not all buttons will work
-static bool has_old_driver = true;
+static uint16_t clientID = 0;
+
+static bool driver_loaded = false;
+static bool has_old_driver = false; // 3Dconnexion drivers before 10 beta 4 are "old", not all buttons will work
+static bool has_new_driver = false; // drivers >= 10.2.2 are "new", and can process events on a separate thread
+
+// replicate just enough of the 3Dx API for our uses, not everything the driver provides
+
+#define kConnexionClientModeTakeOver 1
+#define kConnexionMaskAll 0x3fff
+#define kConnexionMaskAllButtons 0xffffffff
+#define kConnexionCmdHandleButtons 2
+#define kConnexionCmdHandleAxis 3
+#define kConnexionCmdAppSpecific 10
+#define kConnexionMsgDeviceState '3dSR'
+#define kConnexionCtlGetDeviceID '3did'
+
+#pragma pack(push,2) // just this struct
+struct ConnexionDeviceState {
+ uint16_t version;
+ uint16_t client;
+ uint16_t command;
+ int16_t param;
+ int32_t value;
+ uint64_t time;
+ uint8_t report[8];
+ uint16_t buttons8; // obsolete! (pre-10.x drivers)
+ int16_t axis[6]; // tx, ty, tz, rx, ry, rz
+ uint16_t address;
+ uint32_t buttons;
+};
+#pragma pack(pop)
+
+// callback functions:
+typedef void (*AddedHandler)(uint32_t);
+typedef void (*RemovedHandler)(uint32_t);
+typedef void (*MessageHandler)(uint32_t, uint32_t msg_type, void* msg_arg);
-static void NDOF_DeviceAdded(io_connect_t connection)
+// driver functions:
+typedef int16_t (*SetConnexionHandlers_ptr)(MessageHandler, AddedHandler, RemovedHandler, bool);
+typedef int16_t (*InstallConnexionHandlers_ptr)(MessageHandler, AddedHandler, RemovedHandler);
+typedef void (*CleanupConnexionHandlers_ptr)();
+typedef uint16_t (*RegisterConnexionClient_ptr)(uint32_t signature, const char* name, uint16_t mode, uint32_t mask);
+typedef void (*SetConnexionClientButtonMask_ptr)(uint16_t clientID, uint32_t buttonMask);
+typedef void (*UnregisterConnexionClient_ptr)(uint16_t clientID);
+typedef int16_t (*ConnexionClientControl_ptr)(uint16_t clientID, uint32_t message, int32_t param, int32_t* result);
+
+#define DECLARE_FUNC(name) name##_ptr name = NULL
+
+DECLARE_FUNC(SetConnexionHandlers);
+DECLARE_FUNC(InstallConnexionHandlers);
+DECLARE_FUNC(CleanupConnexionHandlers);
+DECLARE_FUNC(RegisterConnexionClient);
+DECLARE_FUNC(SetConnexionClientButtonMask);
+DECLARE_FUNC(UnregisterConnexionClient);
+DECLARE_FUNC(ConnexionClientControl);
+
+
+static void* load_func(void* module, const char* func_name)
{
- printf("ndof: device added\n"); // change these: printf --> informational reports
+ void* func = dlsym(module, func_name);
-#if 0 // device preferences will be useful some day
- ConnexionDevicePrefs p;
- ConnexionGetCurrentDevicePrefs(kDevID_AnyDevice, &p);
+#if DEBUG_NDOF_DRIVER
+ if (func) {
+ printf("'%s' loaded :D\n", func_name);
+ }
+ else {
+ printf("<!> %s\n", dlerror());
+ }
+#endif
+
+ return func;
+}
+
+#define LOAD_FUNC(name) name = (name##_ptr) load_func(module, #name)
+
+static bool load_driver_functions()
+{
+ if (driver_loaded) {
+ return true;
+ }
+
+ void* module = dlopen("3DconnexionClient.framework/3DconnexionClient", RTLD_LAZY | RTLD_LOCAL);
+
+ if (module) {
+ LOAD_FUNC(SetConnexionHandlers);
+
+ if (SetConnexionHandlers != NULL) {
+ driver_loaded = true;
+ has_new_driver = true;
+ }
+ else {
+ LOAD_FUNC(InstallConnexionHandlers);
+
+ driver_loaded = (InstallConnexionHandlers != NULL);
+ }
+
+ if (driver_loaded) {
+ LOAD_FUNC(CleanupConnexionHandlers);
+ LOAD_FUNC(RegisterConnexionClient);
+ LOAD_FUNC(SetConnexionClientButtonMask);
+ LOAD_FUNC(UnregisterConnexionClient);
+ LOAD_FUNC(ConnexionClientControl);
+
+ has_old_driver = (SetConnexionClientButtonMask == NULL);
+ }
+
+ dlclose(module); // functions will remain loaded
+ }
+#if DEBUG_NDOF_DRIVER
+ else {
+ printf("<!> %s\n", dlerror());
+ }
+
+ printf("loaded: %s\n", driver_loaded ? "YES" : "NO");
+ printf("old: %s\n", has_old_driver ? "YES" : "NO");
+ printf("new: %s\n", has_new_driver ? "YES" : "NO");
+#endif
+
+ return driver_loaded;
+ }
+
+
+static void DeviceAdded(uint32_t unused)
+{
+#if DEBUG_NDOF_DRIVER
+ printf("ndof: device added\n");
#endif
// determine exactly which device is plugged in
- SInt32 result = 0;
- GHOST_NDOFManager3Dconnexion_ConnexionControl(kConnexionCtlGetDeviceID, 0, &result);
- unsigned short vendorID = result >> 16;
- unsigned short productID = result & 0xffff;
+ int32_t result;
+ ConnexionClientControl(clientID, kConnexionCtlGetDeviceID, 0, &result);
+ int16_t vendorID = result >> 16;
+ int16_t productID = result & 0xffff;
ndof_manager->setDevice(vendorID, productID);
}
-static void NDOF_DeviceRemoved(io_connect_t connection)
+static void DeviceRemoved(uint32_t unused)
{
+#if DEBUG_NDOF_DRIVER
printf("ndof: device removed\n");
+#endif
}
-static void NDOF_DeviceEvent(io_connect_t connection, natural_t messageType, void* messageArgument)
+static void DeviceEvent(uint32_t unused, uint32_t msg_type, void* msg_arg)
{
- switch (messageType)
- {
- case kConnexionMsgDeviceState:
- {
- ConnexionDeviceState* s = (ConnexionDeviceState*)messageArgument;
+ if (msg_type == kConnexionMsgDeviceState) {
+ ConnexionDeviceState* s = (ConnexionDeviceState*)msg_arg;
+ // device state is broadcast to all clients; only react if sent to us
+ if (s->client == clientID) {
+ // TODO: is s->time compatible with GHOST timestamps? if so use that instead.
GHOST_TUns64 now = ghost_system->getMilliSeconds();
- switch (s->command)
- {
+ switch (s->command) {
case kConnexionCmdHandleAxis:
{
// convert to blender view coordinates
@@ -91,82 +210,71 @@ static void NDOF_DeviceEvent(io_connect_t connection, natural_t messageType, voi
case kConnexionCmdHandleButtons:
{
int button_bits = has_old_driver ? s->buttons8 : s->buttons;
+ printf("button bits: 0x%08x\n", button_bits);
ndof_manager->updateButtons(button_bits, now);
ghost_system->notifyExternalEventProcessed();
break;
}
+#if DEBUG_NDOF_DRIVER
case kConnexionCmdAppSpecific:
printf("ndof: app-specific command, param = %hd, value = %d\n", s->param, s->value);
break;
default:
printf("ndof: mystery device command %d\n", s->command);
+#endif
}
- break;
}
- case kConnexionMsgPrefsChanged:
- // printf("ndof: prefs changed\n"); // this includes app switches
- // TODO: look through updated prefs for things blender cares about
- break;
- case kConnexionMsgCalibrateDevice:
- printf("ndof: calibrate\n"); // but what should blender do?
- break;
- case kConnexionMsgDoMapping:
- // printf("ndof: driver did something\n");
- // sent when the driver itself consumes an NDOF event
- // and performs whatever action is set in user prefs
- // 3Dx header file says to ignore these
- break;
- default:
- printf("ndof: mystery event %d\n", messageType);
}
}
GHOST_NDOFManagerCocoa::GHOST_NDOFManagerCocoa(GHOST_System& sys)
: GHOST_NDOFManager(sys)
{
- if (GHOST_NDOFManager3Dconnexion_available())
- {
+ if (load_driver_functions()) {
// give static functions something to talk to:
ghost_system = dynamic_cast<GHOST_SystemCocoa*>(&sys);
ndof_manager = this;
- OSErr error = GHOST_NDOFManager3Dconnexion_InstallConnexionHandlers(NDOF_DeviceEvent, NDOF_DeviceAdded, NDOF_DeviceRemoved);
+ uint16_t error;
+ if (has_new_driver) {
+ const bool separate_thread = false; // TODO: rework Mac event handler to allow this
+ error = SetConnexionHandlers(DeviceEvent, DeviceAdded, DeviceRemoved, separate_thread);
+ }
+ else {
+ error = InstallConnexionHandlers(DeviceEvent, DeviceAdded, DeviceRemoved);
+ }
+
if (error) {
- printf("ndof: error %d while installing handlers\n", error);
+#if DEBUG_NDOF_DRIVER
+ printf("ndof: error %d while setting up handlers\n", error);
+#endif
return;
}
// Pascal string *and* a four-letter constant. How old-skool.
- m_clientID = GHOST_NDOFManager3Dconnexion_RegisterConnexionClient('blnd', (UInt8*) "\007blender",
- kConnexionClientModeTakeOver, kConnexionMaskAll);
-
- // printf("ndof: client id = %d\n", m_clientID);
+ clientID = RegisterConnexionClient('blnd', "\007blender", kConnexionClientModeTakeOver, kConnexionMaskAll);
- if (GHOST_NDOFManager3Dconnexion_oldDRV()) {
- has_old_driver = false;
- GHOST_NDOFManager3Dconnexion_SetConnexionClientButtonMask(m_clientID, kConnexionMaskAllButtons);
- }
- else {
- printf("ndof: old 3Dx driver installed, some buttons may not work\n");
+ if (!has_old_driver) {
+ SetConnexionClientButtonMask(clientID, kConnexionMaskAllButtons);
}
}
- else {
- printf("ndof: 3Dx driver not found\n");
- // This isn't a hard error, just means the user doesn't have a 3D mouse.
- }
}
GHOST_NDOFManagerCocoa::~GHOST_NDOFManagerCocoa()
{
- if (GHOST_NDOFManager3Dconnexion_available())
- {
- GHOST_NDOFManager3Dconnexion_UnregisterConnexionClient(m_clientID);
- GHOST_NDOFManager3Dconnexion_UnregisterConnexionClient(m_clientID);
+ if (driver_loaded) {
+ UnregisterConnexionClient(clientID);
+ CleanupConnexionHandlers();
- GHOST_NDOFManager3Dconnexion_CleanupConnexionHandlers();
ghost_system = NULL;
ndof_manager = NULL;
}
}
+
+bool GHOST_NDOFManagerCocoa::available()
+{
+ return driver_loaded;
+}
+
#endif // WITH_INPUT_NDOF