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