Merged changes in the trunk up to revision 53146.
[blender.git] / intern / ghost / intern / GHOST_NDOFManagerCocoa.mm
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s):
19  *   Mike Erwin
20  *
21  * ***** END GPL LICENSE BLOCK *****
22  */
23
24 #ifdef WITH_INPUT_NDOF
25
26 #include "GHOST_NDOFManagerCocoa.h"
27 #include "GHOST_SystemCocoa.h"
28
29 extern "C" {
30         #include <ConnexionClientAPI.h>
31         #include <stdio.h>
32         }
33
34 // static functions need to talk to these objects:
35 static GHOST_SystemCocoa* ghost_system = NULL;
36 static GHOST_NDOFManager* ndof_manager = NULL;
37
38 // 3Dconnexion drivers before 10.x are "old"
39 // not all buttons will work
40 static bool has_old_driver = true;
41
42 static void NDOF_DeviceAdded(io_connect_t connection)
43 {
44         printf("ndof: device added\n"); // change these: printf --> informational reports
45
46 #if 0 // device preferences will be useful some day
47         ConnexionDevicePrefs p;
48         ConnexionGetCurrentDevicePrefs(kDevID_AnyDevice, &p);
49 #endif
50
51         // determine exactly which device is plugged in
52         SInt32 result = 0;
53         ConnexionControl(kConnexionCtlGetDeviceID, 0, &result);
54         unsigned short vendorID = result >> 16;
55         unsigned short productID = result & 0xffff;
56
57         ndof_manager->setDevice(vendorID, productID);
58 }
59
60 static void NDOF_DeviceRemoved(io_connect_t connection)
61 {
62         printf("ndof: device removed\n");
63 }
64
65 static void NDOF_DeviceEvent(io_connect_t connection, natural_t messageType, void* messageArgument)
66 {
67         switch (messageType)
68         {
69                 case kConnexionMsgDeviceState:
70                 {
71                         ConnexionDeviceState* s = (ConnexionDeviceState*)messageArgument;
72
73                         GHOST_TUns64 now = ghost_system->getMilliSeconds();
74
75                         switch (s->command)
76                         {
77                                 case kConnexionCmdHandleAxis:
78                                 {
79                                         // convert to blender view coordinates
80                                         short t[3] = {s->axis[0], -(s->axis[2]), s->axis[1]};
81                                         short r[3] = {-(s->axis[3]), s->axis[5], -(s->axis[4])};
82
83                                         ndof_manager->updateTranslation(t, now);
84                                         ndof_manager->updateRotation(r, now);
85
86                                         ghost_system->notifyExternalEventProcessed();
87                                         break;
88                                 }
89                                 case kConnexionCmdHandleButtons:
90                                 {
91                                         int button_bits = has_old_driver ? s->buttons8 : s->buttons;
92                                         ndof_manager->updateButtons(button_bits, now);
93                                         ghost_system->notifyExternalEventProcessed();
94                                         break;
95                                 }
96                                 case kConnexionCmdAppSpecific:
97                                         printf("ndof: app-specific command, param = %hd, value = %d\n", s->param, s->value);
98                                         break;
99
100                                 default:
101                                         printf("ndof: mystery device command %d\n", s->command);
102                         }
103                         break;
104                 }
105                 case kConnexionMsgPrefsChanged:
106                         // printf("ndof: prefs changed\n"); // this includes app switches
107                         // TODO: look through updated prefs for things blender cares about
108                         break;
109                 case kConnexionMsgCalibrateDevice:
110                         printf("ndof: calibrate\n"); // but what should blender do?
111                         break;
112                 case kConnexionMsgDoMapping:
113                         // printf("ndof: driver did something\n");
114                         // sent when the driver itself consumes an NDOF event
115                         // and performs whatever action is set in user prefs
116                         // 3Dx header file says to ignore these
117                         break;
118                 default:
119                         printf("ndof: mystery event %d\n", messageType);
120         }
121 }
122
123 GHOST_NDOFManagerCocoa::GHOST_NDOFManagerCocoa(GHOST_System& sys)
124     : GHOST_NDOFManager(sys)
125 {
126         if (available())
127         {
128                 // give static functions something to talk to:
129                 ghost_system = dynamic_cast<GHOST_SystemCocoa*>(&sys);
130                 ndof_manager = this;
131
132                 OSErr error = InstallConnexionHandlers(NDOF_DeviceEvent, NDOF_DeviceAdded, NDOF_DeviceRemoved);
133                 if (error) {
134                         printf("ndof: error %d while installing handlers\n", error);
135                         return;
136                 }
137
138                 // Pascal string *and* a four-letter constant. How old-skool.
139                 m_clientID = RegisterConnexionClient('blnd', (UInt8*) "\007blender",
140                                                      kConnexionClientModeTakeOver, kConnexionMaskAll);
141
142                 // printf("ndof: client id = %d\n", m_clientID);
143
144                 if (oldDRV()) {
145                         has_old_driver = false;
146                         SetConnexionClientButtonMask(m_clientID, kConnexionMaskAllButtons);
147                 }
148                 else {
149                         printf("ndof: old 3Dx driver installed, some buttons may not work\n");
150                 }
151         }
152         else {
153                 printf("ndof: 3Dx driver not found\n");
154                 // This isn't a hard error, just means the user doesn't have a 3D mouse.
155         }
156 }
157
158 GHOST_NDOFManagerCocoa::~GHOST_NDOFManagerCocoa()
159 {
160         if (available())
161         {
162                 UnregisterConnexionClient(m_clientID);
163                 CleanupConnexionHandlers();
164                 ghost_system = NULL;
165                 ndof_manager = NULL;
166         }
167 }
168 extern "C" {
169         bool GHOST_NDOFManagerCocoa::available()
170         {
171                 extern OSErr InstallConnexionHandlers() __attribute__((weak_import));
172                 // Make the linker happy for the framework check (see link below for more info)
173                 // http://developer.apple.com/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/WeakLinking.html
174                 return InstallConnexionHandlers != NULL;
175                 // this means that the driver is installed and dynamically linked to blender
176         }
177
178         bool GHOST_NDOFManagerCocoa::oldDRV()
179         {
180                 extern OSErr SetConnexionClientButtonMask() __attribute__((weak_import));
181                 // Make the linker happy for the framework check (see link below for more info)
182                 // http://developer.apple.com/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/WeakLinking.html
183                 return SetConnexionClientButtonMask != NULL;
184                 // this means that the driver has this symbol
185         }
186 }
187 #endif // WITH_INPUT_NDOF