]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/osx/core/hidjoystick.cpp
wxMessageBox off the main thread lost result code.
[wxWidgets.git] / src / osx / core / hidjoystick.cpp
... / ...
CommitLineData
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
58enum
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//---------------------------------------------------------------------------
73class wxHIDJoystick : public wxHIDDevice
74{
75public:
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//---------------------------------------------------------------------------
94class wxJoystickThread : public wxThread
95{
96public:
97 wxJoystickThread(wxHIDJoystick* hid, int joystick);
98 void* Entry();
99 static void HIDCallback(void* target, IOReturn res, void* context, void* sender);
100
101private:
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//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
122void 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
136IMPLEMENT_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//---------------------------------------------------------------------------
145wxJoystick::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//---------------------------------------------------------------------------
169wxJoystick::~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//---------------------------------------------------------------------------
184wxPoint wxJoystick::GetPosition() const
185{
186 wxPoint pos(wxDefaultPosition);
187 if (m_thread) pos = m_thread->m_lastposition;
188 return pos;
189}
190int wxJoystick::GetZPosition() const
191{
192 if (m_thread)
193 return m_thread->m_axe[wxJS_AXIS_Z-wxJS_AXIS_X];
194 return 0;
195}
196int wxJoystick::GetRudderPosition() const
197{
198 if (m_thread)
199 return m_thread->m_axe[wxJS_AXIS_RUDDER-wxJS_AXIS_X];
200 return 0;
201}
202int wxJoystick::GetUPosition() const
203{
204 if (m_thread)
205 return m_thread->m_axe[wxJS_AXIS_U-wxJS_AXIS_X];
206 return 0;
207}
208int 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//---------------------------------------------------------------------------
221int 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//---------------------------------------------------------------------------
234bool 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//---------------------------------------------------------------------------
244int wxJoystick::GetManufacturerId() const
245{
246 return m_hid->m_nManufacturerId;
247}
248
249int wxJoystick::GetProductId() const
250{
251 return m_hid->m_nProductId;
252}
253
254wxString 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//---------------------------------------------------------------------------
271int 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}
283int 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//---------------------------------------------------------------------------
303int 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//---------------------------------------------------------------------------
316bool 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//---------------------------------------------------------------------------
333bool 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//---------------------------------------------------------------------------
350int wxJoystick::GetXMin() const
351{
352 return m_hid->m_nXMin;
353}
354
355int wxJoystick::GetYMin() const
356{
357 return m_hid->m_nYMin;
358}
359
360int wxJoystick::GetZMin() const
361{
362 return m_hid->m_nZMin;
363}
364
365int wxJoystick::GetRudderMin() const
366{
367 return m_hid->m_nRudderMin;
368}
369
370int wxJoystick::GetUMin() const
371{
372 return m_hid->m_nUMin;
373}
374
375int wxJoystick::GetVMin() const
376{
377 return m_hid->m_nVMin;
378}
379
380int wxJoystick::GetXMax() const
381{
382 return m_hid->m_nXMax;
383}
384
385int wxJoystick::GetYMax() const
386{
387 return m_hid->m_nYMax;
388}
389
390int wxJoystick::GetZMax() const
391{
392 return m_hid->m_nZMax;
393}
394
395int wxJoystick::GetRudderMax() const
396{
397 return m_hid->m_nRudderMax;
398}
399
400int wxJoystick::GetUMax() const
401{
402 return m_hid->m_nUMax;
403}
404
405int 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//---------------------------------------------------------------------------
416int wxJoystick::GetMaxButtons() const
417{
418 return wxJS_MAX_BUTTONS;
419}
420
421int wxJoystick::GetMaxAxes() const
422{
423 return wxJS_MAX_AXES;
424}
425
426int wxJoystick::GetPollingMin() const
427{
428 return 10;
429}
430
431int 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//---------------------------------------------------------------------------
442bool wxJoystick::HasZ() const
443{
444 return m_hid->HasElement(wxJS_AXIS_Z);
445}
446
447bool wxJoystick::HasRudder() const
448{
449 return m_hid->HasElement(wxJS_AXIS_RUDDER);
450}
451
452bool wxJoystick::HasU() const
453{
454 return m_hid->HasElement(wxJS_AXIS_U);
455}
456
457bool wxJoystick::HasV() const
458{
459 return m_hid->HasElement(wxJS_AXIS_V);
460}
461
462//---------------------------------------------------------------------------
463// UNSUPPORTED
464//---------------------------------------------------------------------------
465int wxJoystick::GetPOVPosition() const
466{
467 return -1;
468}
469
470int wxJoystick::GetPOVCTSPosition() const
471{
472 return -1;
473}
474
475int wxJoystick::GetMovementThreshold() const
476{
477 return 0;
478}
479
480void wxJoystick::SetMovementThreshold(int WXUNUSED(threshold))
481{
482}
483
484bool wxJoystick::HasPOV() const
485{
486 return false;
487}
488
489bool wxJoystick::HasPOV4Dir() const
490{
491 return false;
492}
493
494bool 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//---------------------------------------------------------------------------
510wxHIDJoystick::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//---------------------------------------------------------------------------
521wxHIDJoystick::~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//---------------------------------------------------------------------------
531bool 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//---------------------------------------------------------------------------
562void 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
579void 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//---------------------------------------------------------------------------
676IOHIDElementCookie* wxHIDJoystick::GetCookies()
677{ return m_pCookies; }
678IOHIDQueueInterface** wxHIDJoystick::GetQueue()
679{ return m_ppQueue; }
680
681//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
682//
683// wxJoystickThread
684//
685//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
686
687//---------------------------------------------------------------------------
688// wxJoystickThread Constructor
689//
690// Just initializes members
691//---------------------------------------------------------------------------
692wxJoystickThread::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//---------------------------------------------------------------------------
714void* 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