]>
Commit | Line | Data |
---|---|---|
4cb1d3da RN |
1 | ///////////////////////////////////////////////////////////////////////////// |
2 | // Name: joystick.cpp | |
3 | // Purpose: wxJoystick class | |
4 | // Author: Ryan Norton | |
5 | // Modified by: | |
6 | // Created: 2/13/2005 | |
7 | // RCS-ID: $Id$ | |
8 | // Copyright: (c) Ryan Norton | |
9 | // Licence: wxWindows licence | |
10 | ///////////////////////////////////////////////////////////////////////////// | |
11 | ||
ce0d1032 SC |
12 | //=========================================================================== |
13 | // DECLARATIONS | |
14 | //=========================================================================== | |
15 | ||
16 | //--------------------------------------------------------------------------- | |
17 | // Pre-compiled header stuff | |
18 | //--------------------------------------------------------------------------- | |
19 | ||
20 | // For compilers that support precompilation, includes "wx.h". | |
4cb1d3da RN |
21 | #include "wx/wxprec.h" |
22 | ||
ce0d1032 SC |
23 | //--------------------------------------------------------------------------- |
24 | // Guard | |
25 | //--------------------------------------------------------------------------- | |
4cb1d3da | 26 | |
ce0d1032 SC |
27 | //we only support HID on OSX (DARWIN), since it requires DARWIN... |
28 | #if wxUSE_JOYSTICK && defined(__DARWIN__) | |
4cb1d3da | 29 | |
ce0d1032 SC |
30 | //--------------------------------------------------------------------------- |
31 | // Includes | |
32 | //--------------------------------------------------------------------------- | |
33 | #include "wx/event.h" //joystick wxEvents | |
34 | #include "wx/log.h" //logging... | |
35 | #include "wx/joystick.h" //... | |
36 | #include "wx/thread.h" //wxThread for polling thread/ wxCriticalSection | |
37 | #include "wx/window.h" //for wxWindow to "capture" joystick | |
4cb1d3da | 38 | |
ce0d1032 SC |
39 | //private headers |
40 | #include "wx/mac/corefoundation/hid.h" //private mac hid stuff | |
4cb1d3da | 41 | |
ce0d1032 | 42 | //mac headers |
4cb1d3da RN |
43 | #include <CoreServices/CoreServices.h> |
44 | #include <mach/mach.h> | |
45 | #include <mach/mach_time.h> | |
46 | #include <unistd.h> | |
47 | ||
ce0d1032 SC |
48 | //--------------------------------------------------------------------------- |
49 | // Definitions/Enumerations | |
50 | //--------------------------------------------------------------------------- | |
51 | ||
52 | #define wxJS_MAX_AXES 10 /*max number of axes*/ | |
53 | #define wxJS_MAX_BUTTONS 40 /*max number of buttons*/ | |
54 | ||
55 | enum | |
56 | { | |
57 | //These are positions within the cookie array | |
58 | //in wxHIDJoystick that the cookies that store the axis' are | |
65442ab6 | 59 | wxJS_AXIS_X = 40, |
4cb1d3da RN |
60 | wxJS_AXIS_Y, |
61 | wxJS_AXIS_Z, | |
62 | wxJS_AXIS_RUDDER, | |
63 | wxJS_AXIS_U, | |
64 | wxJS_AXIS_V, | |
4cb1d3da RN |
65 | }; |
66 | ||
ce0d1032 SC |
67 | //--------------------------------------------------------------------------- |
68 | // wxHIDJoystick | |
69 | //--------------------------------------------------------------------------- | |
4cb1d3da RN |
70 | class wxHIDJoystick : public wxHIDDevice |
71 | { | |
72 | public: | |
175ec4c8 JS |
73 | wxHIDJoystick(); |
74 | ~wxHIDJoystick(); | |
75 | ||
4cb1d3da | 76 | bool Create(int nWhich); |
32efab35 SC |
77 | virtual void BuildCookies(CFArrayRef Array); |
78 | void MakeCookies(CFArrayRef Array); | |
ce0d1032 SC |
79 | IOHIDElementCookie* GetCookies(); |
80 | IOHIDQueueInterface** GetQueue(); | |
65442ab6 | 81 | |
175ec4c8 JS |
82 | int m_nXMax, m_nYMax, m_nZMax, m_nRudderMax, m_nUMax, m_nVMax, |
83 | m_nXMin, m_nYMin, m_nZMin, m_nRudderMin, m_nUMin, m_nVMin; | |
84 | ||
65442ab6 | 85 | friend class wxJoystick; |
4cb1d3da RN |
86 | }; |
87 | ||
ce0d1032 SC |
88 | //--------------------------------------------------------------------------- |
89 | // wxJoystickThread | |
90 | //--------------------------------------------------------------------------- | |
4cb1d3da RN |
91 | class wxJoystickThread : public wxThread |
92 | { | |
93 | public: | |
94 | wxJoystickThread(wxHIDJoystick* hid, int joystick); | |
95 | void* Entry(); | |
ce0d1032 | 96 | static void HIDCallback(void* target, IOReturn res, void* context, void* sender); |
65442ab6 | 97 | |
4cb1d3da RN |
98 | private: |
99 | wxHIDJoystick* m_hid; | |
100 | int m_joystick; | |
101 | wxPoint m_lastposition; | |
ce0d1032 | 102 | int m_axe[wxJS_MAX_AXES]; |
4cb1d3da RN |
103 | int m_buttons; |
104 | wxWindow* m_catchwin; | |
105 | int m_polling; | |
106 | ||
107 | friend class wxJoystick; | |
108 | }; | |
109 | ||
ce0d1032 SC |
110 | //=========================================================================== |
111 | // IMPLEMENTATION | |
112 | //=========================================================================== | |
4cb1d3da | 113 | |
175ec4c8 JS |
114 | //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
115 | // wxGetIntFromCFDictionary | |
116 | // | |
117 | // Helper function that gets a integer from a dictionary key | |
118 | //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
119 | void wxGetIntFromCFDictionary(CFTypeRef cfDict, CFStringRef key, int* pOut) | |
120 | { | |
121 | CFNumberGetValue( | |
122 | (CFNumberRef) CFDictionaryGetValue((CFDictionaryRef) cfDict, | |
123 | key), | |
124 | kCFNumberIntType, pOut); | |
125 | } | |
126 | ||
ce0d1032 SC |
127 | //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
128 | // | |
129 | // wxJoystick | |
130 | // | |
131 | //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
4cb1d3da | 132 | |
ce0d1032 | 133 | IMPLEMENT_DYNAMIC_CLASS(wxJoystick, wxObject) |
4cb1d3da | 134 | |
ce0d1032 SC |
135 | //--------------------------------------------------------------------------- |
136 | // wxJoystick Constructor | |
137 | // | |
138 | // 1) Initializes member variables | |
139 | // 2) Attempts to create the native HID joystick implementation - if none | |
140 | // could be found (no joysticks, etc.) then it sets it to NULL | |
141 | //--------------------------------------------------------------------------- | |
4cb1d3da RN |
142 | wxJoystick::wxJoystick(int joystick) |
143 | : m_joystick(joystick), | |
144 | m_thread(NULL) | |
145 | { | |
146 | m_hid = new wxHIDJoystick(); | |
147 | ||
32efab35 | 148 | if (m_hid->Create(m_joystick+1)) //wxHIDDevice is 1-based while this is 0 |
4cb1d3da RN |
149 | { |
150 | m_thread = new wxJoystickThread(m_hid, m_joystick); | |
151 | m_thread->Create(); | |
152 | m_thread->Run(); | |
153 | } | |
154 | else | |
155 | { | |
156 | delete m_hid; | |
157 | m_hid = NULL; | |
158 | } | |
159 | } | |
160 | ||
ce0d1032 SC |
161 | //--------------------------------------------------------------------------- |
162 | // wxJoystick Destructor | |
163 | // | |
164 | // Releases the capture of the thread, deletes it, and deletes | |
165 | // the native implementation. | |
166 | //--------------------------------------------------------------------------- | |
4cb1d3da RN |
167 | wxJoystick::~wxJoystick() |
168 | { | |
169 | ReleaseCapture(); | |
170 | if (m_thread) | |
171 | m_thread->Delete(); // It's detached so it will delete itself | |
172 | ||
173 | if (m_hid) | |
174 | delete m_hid; | |
175 | } | |
176 | ||
ce0d1032 SC |
177 | //--------------------------------------------------------------------------- |
178 | // wxJoystick::Get[XXX]Position | |
179 | // | |
180 | // Returns the value of an axis that was polled from the thread. In the | |
181 | // case of GetPosition returns the X and Y values in a wxPoint | |
182 | //--------------------------------------------------------------------------- | |
4cb1d3da RN |
183 | wxPoint wxJoystick::GetPosition() const |
184 | { | |
185 | wxPoint pos(wxDefaultPosition); | |
186 | if (m_thread) pos = m_thread->m_lastposition; | |
187 | return pos; | |
188 | } | |
4cb1d3da RN |
189 | int wxJoystick::GetZPosition() const |
190 | { | |
191 | if (m_thread) | |
192 | return m_thread->m_axe[wxJS_AXIS_Z]; | |
193 | return 0; | |
194 | } | |
4cb1d3da RN |
195 | int wxJoystick::GetRudderPosition() const |
196 | { | |
197 | if (m_thread) | |
198 | return m_thread->m_axe[wxJS_AXIS_RUDDER]; | |
199 | return 0; | |
200 | } | |
4cb1d3da RN |
201 | int wxJoystick::GetUPosition() const |
202 | { | |
203 | if (m_thread) | |
204 | return m_thread->m_axe[wxJS_AXIS_U]; | |
205 | return 0; | |
206 | } | |
4cb1d3da RN |
207 | int wxJoystick::GetVPosition() const |
208 | { | |
209 | if (m_thread) | |
210 | return m_thread->m_axe[wxJS_AXIS_V]; | |
211 | return 0; | |
212 | } | |
213 | ||
ce0d1032 SC |
214 | //--------------------------------------------------------------------------- |
215 | // wxJoystick::GetButtonState | |
216 | // | |
217 | // Returns the state of the buttons in a bitmask as dictated by the | |
218 | // wx manual (the real work takes place in the thread, as always) | |
219 | //--------------------------------------------------------------------------- | |
220 | int wxJoystick::GetButtonState() const | |
221 | { | |
222 | if (m_thread) | |
223 | return m_thread->m_buttons; | |
224 | return 0; | |
225 | } | |
4cb1d3da | 226 | |
ce0d1032 SC |
227 | //--------------------------------------------------------------------------- |
228 | // wxJoystick::IsOk | |
229 | // | |
230 | // Returns whether the joystick initialized successfully - in this case | |
231 | // if the native implementation doesn't exist (in constructor) | |
232 | //--------------------------------------------------------------------------- | |
4cb1d3da | 233 | bool wxJoystick::IsOk() const |
ce0d1032 SC |
234 | { |
235 | return m_hid != NULL; | |
236 | } | |
4cb1d3da | 237 | |
ce0d1032 SC |
238 | //--------------------------------------------------------------------------- |
239 | // wxJoystick::Get[XXX](Id/Name) | |
240 | // | |
241 | // Simple accessors to the native HID implementation | |
242 | //--------------------------------------------------------------------------- | |
4cb1d3da | 243 | int wxJoystick::GetManufacturerId() const |
65442ab6 | 244 | { return m_hid->m_nManufacturerId; } |
4cb1d3da | 245 | int wxJoystick::GetProductId() const |
65442ab6 | 246 | { return m_hid->m_nProductId; } |
4cb1d3da | 247 | wxString wxJoystick::GetProductName() const |
65442ab6 | 248 | { return m_hid->m_szProductName; } |
4cb1d3da | 249 | |
ce0d1032 SC |
250 | //--------------------------------------------------------------------------- |
251 | // wxJoystick::GetNumberButtons | |
252 | // wxJoystick::GetNumberAxes | |
253 | // | |
254 | // Queries the joystick for an active number of buttons/axes. | |
255 | // | |
256 | // In the native HID implementation, the cookies: | |
257 | // 0-40 are the buttons of the joystick | |
258 | // 40-50 are the axes of the joystick | |
259 | // | |
260 | // These just query the native HID implementation as above. | |
261 | //--------------------------------------------------------------------------- | |
4cb1d3da RN |
262 | int wxJoystick::GetNumberButtons() const |
263 | { | |
264 | int nCount = 0; | |
265 | ||
266 | for(int nIndex = 0; nIndex < 40; ++nIndex) | |
267 | { | |
268 | if(m_hid->HasElement(nIndex)) | |
269 | ++nCount; | |
270 | } | |
271 | ||
272 | return nCount; | |
273 | } | |
4cb1d3da RN |
274 | int wxJoystick::GetNumberAxes() const |
275 | { | |
276 | int nCount = 0; | |
277 | ||
278 | for(int nIndex = 40; nIndex < 50; ++nIndex) | |
279 | { | |
280 | if(m_hid->HasElement(nIndex)) | |
281 | ++nCount; | |
282 | } | |
283 | ||
284 | return nCount; | |
285 | } | |
286 | ||
ce0d1032 SC |
287 | //--------------------------------------------------------------------------- |
288 | // wxJoystick::GetNumberJoysticks | |
4cb1d3da | 289 | // |
ce0d1032 SC |
290 | // Gets the number of joysticks on the system. In HID that |
291 | // is all devices with the kHIDUsage_GD_Joystick or kHIDUsage_GD_GamePad | |
292 | // identifiers. | |
293 | //--------------------------------------------------------------------------- | |
da9e9563 | 294 | int wxJoystick::GetNumberJoysticks() |
ce0d1032 SC |
295 | { |
296 | return | |
297 | wxHIDDevice::GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick) + | |
298 | wxHIDDevice::GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad); | |
299 | } | |
4cb1d3da | 300 | |
ce0d1032 SC |
301 | //--------------------------------------------------------------------------- |
302 | // wxJoystick::SetCapture | |
303 | // | |
304 | // Stops sending events from the thread to the window set in | |
305 | // SetCapture and stops polling the joystick | |
306 | //--------------------------------------------------------------------------- | |
307 | bool wxJoystick::SetCapture(wxWindow* win, int pollingFreq) | |
308 | { | |
309 | if (m_thread) | |
310 | { | |
311 | m_thread->m_catchwin = win; | |
312 | m_thread->m_polling = pollingFreq; | |
313 | return true; | |
314 | } | |
315 | return false; | |
316 | } | |
4cb1d3da | 317 | |
ce0d1032 SC |
318 | //--------------------------------------------------------------------------- |
319 | // wxJoystick::ReleaseCapture | |
320 | // | |
321 | // Stops sending events from the thread to the window set in | |
322 | // SetCapture and stops polling the joystick | |
323 | //--------------------------------------------------------------------------- | |
324 | bool wxJoystick::ReleaseCapture() | |
325 | { | |
326 | if (m_thread) | |
327 | { | |
328 | m_thread->m_catchwin = NULL; | |
329 | m_thread->m_polling = 0; | |
330 | return true; | |
331 | } | |
332 | return false; | |
333 | } | |
4cb1d3da | 334 | |
ce0d1032 SC |
335 | //--------------------------------------------------------------------------- |
336 | // wxJoystick::Get[XXX] | |
337 | // | |
175ec4c8 JS |
338 | // Gets the minimum and maximum values for each axis, returning 0 if the |
339 | // axis doesn't exist. | |
ce0d1032 SC |
340 | //--------------------------------------------------------------------------- |
341 | int wxJoystick::GetXMin() const | |
175ec4c8 | 342 | { return m_hid->m_nXMin; } |
ce0d1032 | 343 | int wxJoystick::GetYMin() const |
175ec4c8 | 344 | { return m_hid->m_nYMin; } |
ce0d1032 | 345 | int wxJoystick::GetZMin() const |
175ec4c8 JS |
346 | { return m_hid->m_nZMin; } |
347 | int wxJoystick::GetRudderMin() const | |
348 | { return m_hid->m_nRudderMin; } | |
4cb1d3da | 349 | int wxJoystick::GetUMin() const |
175ec4c8 | 350 | { return m_hid->m_nUMin; } |
4cb1d3da | 351 | int wxJoystick::GetVMin() const |
175ec4c8 | 352 | { return m_hid->m_nVMin; } |
4cb1d3da | 353 | |
ce0d1032 | 354 | int wxJoystick::GetXMax() const |
175ec4c8 | 355 | { return m_hid->m_nXMax; } |
ce0d1032 | 356 | int wxJoystick::GetYMax() const |
175ec4c8 | 357 | { return m_hid->m_nYMax; } |
ce0d1032 | 358 | int wxJoystick::GetZMax() const |
175ec4c8 JS |
359 | { return m_hid->m_nZMax; } |
360 | int wxJoystick::GetRudderMax() const | |
361 | { return m_hid->m_nRudderMax; } | |
ce0d1032 | 362 | int wxJoystick::GetUMax() const |
175ec4c8 | 363 | { return m_hid->m_nUMax; } |
4cb1d3da | 364 | int wxJoystick::GetVMax() const |
175ec4c8 | 365 | { return m_hid->m_nVMax; } |
ce0d1032 SC |
366 | |
367 | //--------------------------------------------------------------------------- | |
368 | // wxJoystick::Get[XXX] | |
369 | // | |
370 | // Min/Max values for buttons, axes, etc.. Polling in this case is just | |
371 | // what the linux port has. | |
372 | //--------------------------------------------------------------------------- | |
373 | int wxJoystick::GetMaxButtons() const | |
374 | { return wxJS_MAX_BUTTONS; } | |
375 | int wxJoystick::GetMaxAxes() const | |
376 | { return wxJS_MAX_AXES; } | |
377 | int wxJoystick::GetPollingMin() const | |
378 | { return 10; } | |
379 | int wxJoystick::GetPollingMax() const | |
380 | { return 1000; } | |
4cb1d3da | 381 | |
ce0d1032 SC |
382 | //--------------------------------------------------------------------------- |
383 | // wxJoystick::Has[XXX] | |
384 | // | |
385 | // Just queries the native hid implementation if the cookie was found | |
386 | // when enumerating the cookies of the joystick device | |
387 | //--------------------------------------------------------------------------- | |
4cb1d3da RN |
388 | bool wxJoystick::HasZ() const |
389 | { return m_hid->HasElement(wxJS_AXIS_Z); } | |
175ec4c8 JS |
390 | bool wxJoystick::HasRudder() const |
391 | { return m_hid->HasElement(wxJS_AXIS_RUDDER); } | |
4cb1d3da RN |
392 | bool wxJoystick::HasU() const |
393 | { return m_hid->HasElement(wxJS_AXIS_U); } | |
4cb1d3da RN |
394 | bool wxJoystick::HasV() const |
395 | { return m_hid->HasElement(wxJS_AXIS_V); } | |
396 | ||
ce0d1032 SC |
397 | //--------------------------------------------------------------------------- |
398 | // UNSUPPORTED | |
399 | //--------------------------------------------------------------------------- | |
400 | int wxJoystick::GetPOVPosition() const | |
401 | { return -1; } | |
402 | int wxJoystick::GetPOVCTSPosition() const | |
403 | { return -1; } | |
404 | int wxJoystick::GetMovementThreshold() const | |
405 | { return 0; } | |
406 | void wxJoystick::SetMovementThreshold(int threshold) | |
407 | { } | |
4cb1d3da RN |
408 | bool wxJoystick::HasPOV() const |
409 | { return false; } | |
4cb1d3da RN |
410 | bool wxJoystick::HasPOV4Dir() const |
411 | { return false; } | |
4cb1d3da RN |
412 | bool wxJoystick::HasPOVCTS() const |
413 | { return false; } | |
414 | ||
ce0d1032 SC |
415 | //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
416 | // | |
417 | // wxHIDJoystick | |
418 | // | |
419 | //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
4cb1d3da | 420 | |
175ec4c8 JS |
421 | //--------------------------------------------------------------------------- |
422 | // wxHIDJoystick ctor | |
423 | // | |
424 | // Initializes the min/max members | |
425 | //--------------------------------------------------------------------------- | |
426 | wxHIDJoystick::wxHIDJoystick() : | |
427 | m_nXMax(0), m_nYMax(0), m_nZMax(0), m_nRudderMax(0), m_nUMax(0), m_nVMax(0), | |
428 | m_nXMin(0), m_nYMin(0), m_nZMin(0), m_nRudderMin(0), m_nUMin(0), m_nVMin(0) | |
429 | { | |
430 | } | |
431 | ||
432 | //--------------------------------------------------------------------------- | |
433 | // wxHIDJoystick dtor | |
434 | // | |
435 | // Nothing... | |
436 | //--------------------------------------------------------------------------- | |
437 | wxHIDJoystick::~wxHIDJoystick() | |
438 | { | |
439 | } | |
440 | ||
ce0d1032 SC |
441 | //--------------------------------------------------------------------------- |
442 | // wxHIDJoystick::Create | |
443 | // | |
444 | // Creates the native HID device (joysticks are of either | |
445 | // kHIDUsage_GD_Joystick or kHIDUsage_GD_GamePad) | |
446 | //--------------------------------------------------------------------------- | |
447 | bool wxHIDJoystick::Create(int nWhich) | |
4cb1d3da | 448 | { |
ce0d1032 SC |
449 | int nJoysticks = GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick); |
450 | ||
451 | if (nWhich <= nJoysticks) | |
32efab35 SC |
452 | return wxHIDDevice::Create(kHIDPage_GenericDesktop, |
453 | kHIDUsage_GD_Joystick, | |
454 | nWhich); | |
ce0d1032 SC |
455 | else |
456 | nWhich -= nJoysticks; | |
457 | ||
458 | int nGamePads = GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad); | |
459 | ||
460 | if (nWhich <= nGamePads) | |
32efab35 SC |
461 | return wxHIDDevice::Create(kHIDPage_GenericDesktop, |
462 | kHIDUsage_GD_GamePad, | |
463 | nWhich); | |
ce0d1032 | 464 | else |
4cb1d3da RN |
465 | return false; |
466 | } | |
467 | ||
ce0d1032 SC |
468 | //--------------------------------------------------------------------------- |
469 | // wxHIDJoystick::BuildCookies | |
470 | // wxHIDJoystick::MakeCookies | |
471 | // | |
472 | // Sets up the cookies for the HID device (called from Create) - as | |
473 | // mentioned 0-40 are the buttons and 40-50 are the axes. | |
474 | // | |
475 | // MakeCookies is just a recursive function for each array within | |
476 | // BuildCookies. | |
477 | //--------------------------------------------------------------------------- | |
32efab35 | 478 | void wxHIDJoystick::BuildCookies(CFArrayRef Array) |
4cb1d3da | 479 | { |
ce0d1032 SC |
480 | InitCookies(50, true); |
481 | ||
ce0d1032 SC |
482 | // |
483 | // I wasted two hours of my life on this line :( | |
484 | // accidently removed it during some source cleaning... | |
485 | // | |
486 | MakeCookies(Array); | |
487 | ||
488 | //paranoid debugging stuff | |
489 | #if 0 | |
490 | for(int i = 0; i < 50; ++i) | |
491 | wxPrintf(wxT("\nVAL #%i:[%i]"), i, m_pCookies[i]); | |
492 | #endif | |
493 | }//end buildcookies | |
494 | ||
32efab35 | 495 | void wxHIDJoystick::MakeCookies(CFArrayRef Array) |
ce0d1032 SC |
496 | { |
497 | int i, nUsage, nPage; | |
498 | ||
32efab35 | 499 | for (i = 0; i < CFArrayGetCount(Array); ++i) |
4cb1d3da | 500 | { |
32efab35 SC |
501 | const void* ref = CFDictionaryGetValue( |
502 | (CFDictionaryRef)CFArrayGetValueAtIndex(Array, i), | |
503 | CFSTR(kIOHIDElementKey) | |
504 | ); | |
ce0d1032 SC |
505 | |
506 | if (ref != NULL) | |
507 | { | |
32efab35 | 508 | MakeCookies((CFArrayRef) ref); |
4cb1d3da | 509 | } |
ce0d1032 SC |
510 | else |
511 | { | |
512 | CFNumberGetValue( | |
32efab35 SC |
513 | (CFNumberRef) |
514 | CFDictionaryGetValue( | |
515 | (CFDictionaryRef) CFArrayGetValueAtIndex(Array, i), | |
516 | CFSTR(kIOHIDElementUsageKey) | |
517 | ), | |
518 | kCFNumberIntType, | |
519 | &nUsage ); | |
ce0d1032 SC |
520 | |
521 | CFNumberGetValue( | |
32efab35 SC |
522 | (CFNumberRef) |
523 | CFDictionaryGetValue( | |
524 | (CFDictionaryRef) CFArrayGetValueAtIndex(Array, i), | |
525 | CFSTR(kIOHIDElementUsagePageKey) | |
526 | ), | |
527 | kCFNumberIntType, | |
528 | &nPage ); | |
ce0d1032 SC |
529 | |
530 | #if 0 | |
531 | wxLogSysError(wxT("[%i][%i]"), nUsage, nPage); | |
532 | #endif | |
533 | if (nPage == kHIDPage_Button && nUsage <= 40) | |
32efab35 | 534 | AddCookieInQueue(CFArrayGetValueAtIndex(Array, i), nUsage-1 ); |
ce0d1032 SC |
535 | else if (nPage == kHIDPage_GenericDesktop) |
536 | { | |
175ec4c8 | 537 | //axis... |
ce0d1032 SC |
538 | switch(nUsage) |
539 | { | |
540 | case kHIDUsage_GD_X: | |
32efab35 SC |
541 | AddCookieInQueue(CFArrayGetValueAtIndex(Array, i), wxJS_AXIS_X); |
542 | wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i), | |
543 | CFSTR(kIOHIDElementMaxKey), | |
175ec4c8 | 544 | &m_nXMax); |
32efab35 SC |
545 | wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i), |
546 | CFSTR(kIOHIDElementMinKey), | |
175ec4c8 | 547 | &m_nXMin); |
ce0d1032 SC |
548 | break; |
549 | case kHIDUsage_GD_Y: | |
32efab35 SC |
550 | AddCookieInQueue(CFArrayGetValueAtIndex(Array, i), wxJS_AXIS_Y); |
551 | wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i), | |
552 | CFSTR(kIOHIDElementMaxKey), | |
175ec4c8 | 553 | &m_nYMax); |
32efab35 SC |
554 | wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i), |
555 | CFSTR(kIOHIDElementMinKey), | |
175ec4c8 | 556 | &m_nYMin); |
ce0d1032 SC |
557 | break; |
558 | case kHIDUsage_GD_Z: | |
32efab35 SC |
559 | AddCookieInQueue(CFArrayGetValueAtIndex(Array, i), wxJS_AXIS_Z); |
560 | wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i), | |
561 | CFSTR(kIOHIDElementMaxKey), | |
175ec4c8 | 562 | &m_nZMax); |
32efab35 SC |
563 | wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i), |
564 | CFSTR(kIOHIDElementMinKey), | |
175ec4c8 | 565 | &m_nZMin); |
ce0d1032 SC |
566 | break; |
567 | default: | |
568 | break; | |
569 | } | |
570 | } | |
571 | else if (nPage == kHIDPage_Simulation && nUsage == kHIDUsage_Sim_Rudder) | |
175ec4c8 JS |
572 | { |
573 | //rudder... | |
32efab35 SC |
574 | AddCookieInQueue(CFArrayGetValueAtIndex(Array, i), wxJS_AXIS_RUDDER ); |
575 | wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i), | |
576 | CFSTR(kIOHIDElementMaxKey), | |
175ec4c8 | 577 | &m_nRudderMax); |
32efab35 SC |
578 | wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i), |
579 | CFSTR(kIOHIDElementMinKey), | |
175ec4c8 JS |
580 | &m_nRudderMin); |
581 | } | |
ce0d1032 SC |
582 | } |
583 | } | |
4cb1d3da | 584 | } |
ce0d1032 SC |
585 | |
586 | //--------------------------------------------------------------------------- | |
587 | // wxHIDJoystick::Get[XXX] | |
588 | // | |
589 | // Simple accessors so that the HID callback and the thread procedure | |
590 | // can access members from wxHIDDevice (our parent here). | |
591 | //--------------------------------------------------------------------------- | |
592 | IOHIDElementCookie* wxHIDJoystick::GetCookies() | |
593 | { return m_pCookies; } | |
594 | IOHIDQueueInterface** wxHIDJoystick::GetQueue() | |
595 | { return m_ppQueue; } | |
596 | ||
597 | //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
598 | // | |
599 | // wxJoystickThread | |
600 | // | |
601 | //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
602 | ||
603 | //--------------------------------------------------------------------------- | |
604 | // wxJoystickThread Constructor | |
605 | // | |
606 | // Just initializes members | |
607 | //--------------------------------------------------------------------------- | |
608 | wxJoystickThread::wxJoystickThread(wxHIDJoystick* hid, int joystick) | |
609 | : m_hid(hid), | |
610 | m_joystick(joystick), | |
611 | m_lastposition(127,127), | |
612 | m_buttons(0), | |
613 | m_catchwin(NULL), | |
614 | m_polling(0) | |
615 | { | |
616 | memset(m_axe, 0, sizeof(int) * wxJS_MAX_AXES); | |
617 | } | |
618 | ||
619 | //--------------------------------------------------------------------------- | |
620 | // wxJoystickThread::Entry | |
621 | // | |
622 | // Thread procedure | |
623 | // | |
624 | // Runs a CFRunLoop for polling. Basically, it sets the HID queue to | |
625 | // call wxJoystickThread::HIDCallback in the context of this thread | |
626 | // when something changes on the device. It polls as long as the user | |
627 | // wants, or a certain amount if the user wants to "block". Note that | |
628 | // we don't actually block here since this is in a secondary thread. | |
629 | //--------------------------------------------------------------------------- | |
630 | void* wxJoystickThread::Entry() | |
631 | { | |
632 | CFRunLoopSourceRef pRLSource = NULL; | |
633 | ||
634 | if ((*m_hid->GetQueue())->createAsyncEventSource( | |
635 | m_hid->GetQueue(), &pRLSource) != kIOReturnSuccess ) | |
636 | { | |
637 | wxLogSysError(wxT("Couldn't create async event source")); | |
638 | return NULL; | |
639 | } | |
640 | ||
641 | wxASSERT(pRLSource != NULL); | |
642 | ||
643 | //attach runloop source to main run loop in thread | |
644 | CFRunLoopRef pRL = CFRunLoopGetCurrent(); | |
645 | CFRunLoopAddSource(pRL, pRLSource, kCFRunLoopDefaultMode); | |
646 | wxASSERT( CFRunLoopContainsSource(pRL, pRLSource, kCFRunLoopDefaultMode) ); | |
647 | ||
648 | ||
649 | if( (*m_hid->GetQueue())->setEventCallout(m_hid->GetQueue(), | |
650 | wxJoystickThread::HIDCallback, this, this) != kIOReturnSuccess ) | |
651 | { | |
652 | wxLogSysError(wxT("Could not set event callout for queue")); | |
653 | return NULL; | |
654 | } | |
655 | ||
656 | if( (*m_hid->GetQueue())->start(m_hid->GetQueue()) != kIOReturnSuccess ) | |
657 | { | |
658 | wxLogSysError(wxT("Could not start queue")); | |
659 | return NULL; | |
660 | } | |
661 | ||
662 | double dTime; | |
663 | ||
664 | while(true) | |
665 | { | |
666 | if (TestDestroy()) | |
667 | break; | |
668 | ||
669 | if (m_polling) | |
670 | dTime = 0.0001 * m_polling; | |
671 | else | |
672 | dTime = 0.0001 * 10; // check at least every 10 msec in "blocking" case | |
673 | ||
674 | //true just "handles and returns" - false forces it to stay the time | |
675 | //amount | |
676 | #if 1 | |
677 | CFRunLoopRunInMode(kCFRunLoopDefaultMode, dTime, true); | |
678 | #else | |
679 | IOReturn ret = NULL; | |
680 | HIDCallback(this, ret, this, this); | |
681 | Sleep(3000); | |
4cb1d3da | 682 | #endif |
ce0d1032 SC |
683 | } |
684 | ||
685 | wxASSERT( CFRunLoopContainsSource(pRL, pRLSource, kCFRunLoopDefaultMode) ); | |
686 | ||
687 | CFRunLoopRemoveSource(pRL, pRLSource, kCFRunLoopDefaultMode); | |
688 | CFRelease(pRLSource); | |
689 | ||
690 | return NULL; | |
691 | } | |
692 | ||
693 | //--------------------------------------------------------------------------- | |
694 | // wxJoystickThread::HIDCallback (static) | |
695 | // | |
696 | // Callback for the native HID device when it recieves input. | |
697 | // | |
698 | // This is where the REAL dirty work gets done. | |
699 | // | |
700 | // 1) Loops through each event the queue has recieved | |
701 | // 2) First, checks if the thread that is running the loop for | |
702 | // the polling has ended - if so it breaks out | |
703 | // 3) Next, it checks if there was an error getting this event from | |
704 | // the HID queue, if there was, it logs an error and returns | |
705 | // 4) Now it does the real dirty work by getting the button states | |
706 | // from cookies 0-40 and axes positions/states from cookies 40-50 | |
707 | // in the native HID device by quering cookie values. | |
708 | // 5) Sends the event to the polling window (if any) | |
709 | // 6) Gets the next event and goes back to (1) | |
710 | //--------------------------------------------------------------------------- | |
711 | /*static*/ void wxJoystickThread::HIDCallback(void* target, IOReturn res, | |
712 | void* context, void* sender) | |
713 | { | |
714 | IOHIDEventStruct hidevent; | |
715 | AbsoluteTime bogustime = {0,0}; | |
716 | IOReturn ret; | |
717 | wxJoystickThread* pThis = (wxJoystickThread*) context; | |
718 | wxHIDJoystick* m_hid = pThis->m_hid; | |
4cb1d3da | 719 | |
ce0d1032 SC |
720 | //Get the "first" event from the queue |
721 | //bogustime tells it we don't care at what time to start | |
722 | //where it gets the next from | |
723 | ret = (*m_hid->GetQueue())->getNextEvent(m_hid->GetQueue(), | |
724 | &hidevent, bogustime, 0); | |
725 | ||
726 | while (ret != kIOReturnUnderrun) | |
727 | { | |
728 | if (pThis->TestDestroy()) | |
729 | break; | |
730 | ||
731 | if(ret != kIOReturnSuccess) | |
732 | { | |
733 | wxLogSysError(wxString::Format(wxT("wxJoystick Error:[%i]"), ret)); | |
734 | return; | |
735 | } | |
736 | ||
737 | wxJoystickEvent wxevent; | |
738 | ||
739 | //Find the cookie that changed | |
740 | int nIndex = 0; | |
741 | IOHIDElementCookie* pCookies = m_hid->GetCookies(); | |
742 | while(nIndex < 50) | |
743 | { | |
744 | if(hidevent.elementCookie == pCookies[nIndex]) | |
745 | break; | |
746 | ||
747 | ++nIndex; | |
748 | } | |
749 | ||
750 | //debugging stuff | |
751 | #if 0 | |
752 | if(nIndex == 50) | |
753 | { | |
754 | wxLogSysError(wxString::Format(wxT("wxJoystick Out Of Bounds Error"))); | |
755 | break; | |
756 | } | |
4cb1d3da | 757 | #endif |
ce0d1032 SC |
758 | |
759 | //is the cookie a button? | |
760 | if (nIndex < 40) | |
761 | { | |
762 | if (hidevent.value) | |
763 | { | |
764 | pThis->m_buttons |= (1 << nIndex); | |
765 | wxevent.SetEventType(wxEVT_JOY_BUTTON_DOWN); | |
766 | } | |
767 | else | |
768 | { | |
769 | pThis->m_buttons &= ~(1 << nIndex); | |
770 | wxevent.SetEventType(wxEVT_JOY_BUTTON_UP); | |
771 | } | |
772 | ||
773 | wxevent.SetButtonChange(nIndex+1); | |
774 | } | |
775 | else if (nIndex == wxJS_AXIS_X) | |
776 | { | |
777 | pThis->m_lastposition.x = hidevent.value; | |
778 | wxevent.SetEventType(wxEVT_JOY_MOVE); | |
779 | pThis->m_axe[0] = hidevent.value; | |
780 | } | |
781 | else if (nIndex == wxJS_AXIS_Y) | |
782 | { | |
783 | pThis->m_lastposition.y = hidevent.value; | |
784 | wxevent.SetEventType(wxEVT_JOY_MOVE); | |
785 | pThis->m_axe[1] = hidevent.value; | |
786 | } | |
787 | else if (nIndex == wxJS_AXIS_Z) | |
788 | { | |
789 | wxevent.SetEventType(wxEVT_JOY_ZMOVE); | |
790 | pThis->m_axe[2] = hidevent.value; | |
791 | } | |
792 | else | |
793 | wxevent.SetEventType(wxEVT_JOY_MOVE); | |
794 | ||
795 | Nanoseconds timestamp = AbsoluteToNanoseconds(hidevent.timestamp); | |
796 | ||
797 | wxULongLong llTime(timestamp.hi, timestamp.lo); | |
798 | ||
799 | llTime /= 1000000; | |
800 | ||
801 | wxevent.SetTimestamp(llTime.GetValue()); | |
802 | wxevent.SetJoystick(pThis->m_joystick); | |
803 | wxevent.SetButtonState(pThis->m_buttons); | |
804 | wxevent.SetPosition(pThis->m_lastposition); | |
805 | wxevent.SetZPosition(pThis->m_axe[2]); | |
806 | wxevent.SetEventObject(pThis->m_catchwin); | |
807 | ||
808 | if (pThis->m_catchwin) | |
809 | pThis->m_catchwin->AddPendingEvent(wxevent); | |
810 | ||
811 | ret = (*m_hid->GetQueue())->getNextEvent(m_hid->GetQueue(), | |
812 | &hidevent, bogustime, 0); | |
813 | } | |
814 | } | |
815 | ||
816 | #endif // wxUSE_JOYSTICK && defined(__DARWIN__) | |
4cb1d3da | 817 |