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