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