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