1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/mac/corefoundation/joystick.cpp 
   3 // Purpose:     wxJoystick class 
   8 // Copyright:   (c) Ryan Norton 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 //=========================================================================== 
  14 //=========================================================================== 
  16 //--------------------------------------------------------------------------- 
  17 // Pre-compiled header stuff 
  18 //--------------------------------------------------------------------------- 
  20 // For compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  23 //--------------------------------------------------------------------------- 
  25 //--------------------------------------------------------------------------- 
  27 //we only support HID on OSX (DARWIN), since it requires DARWIN... 
  28 #if wxUSE_JOYSTICK && defined(__DARWIN__) && wxUSE_THREADS 
  30 //--------------------------------------------------------------------------- 
  32 //--------------------------------------------------------------------------- 
  36     #include "wx/event.h"   //joystick wxEvents 
  37     #include "wx/window.h"  //for wxWindow to "capture" joystick 
  40 #include "wx/joystick.h"    //... 
  41 #include "wx/thread.h"      //wxThread for polling thread/ wxCriticalSection 
  44 #include "wx/mac/corefoundation/hid.h" //private mac hid stuff 
  47 #include <CoreServices/CoreServices.h> 
  48 #include <mach/mach.h> 
  49 #include <mach/mach_time.h> 
  52 //--------------------------------------------------------------------------- 
  53 // Definitions/Enumerations 
  54 //--------------------------------------------------------------------------- 
  56 #define wxJS_MAX_AXES       10 /*max number of axes*/ 
  57 #define wxJS_MAX_BUTTONS    40 /*max number of buttons*/ 
  61     //These are positions within the cookie array 
  62     //in wxHIDJoystick that the cookies that store the axis' are 
  71 //--------------------------------------------------------------------------- 
  73 //--------------------------------------------------------------------------- 
  74 class wxHIDJoystick 
: public wxHIDDevice
 
  78     virtual ~wxHIDJoystick(); 
  80     bool Create(int nWhich
); 
  81     virtual void BuildCookies(CFArrayRef Array
); 
  82     void MakeCookies(CFArrayRef Array
); 
  83     IOHIDElementCookie
* GetCookies(); 
  84     IOHIDQueueInterface
** GetQueue(); 
  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
; 
  89     friend class wxJoystick
; 
  92 //--------------------------------------------------------------------------- 
  94 //--------------------------------------------------------------------------- 
  95 class wxJoystickThread 
: public wxThread
 
  98     wxJoystickThread(wxHIDJoystick
* hid
, int joystick
); 
 100     static void HIDCallback(void* target
, IOReturn res
, void* context
, void* sender
); 
 103     wxHIDJoystick
*       m_hid
; 
 105     wxPoint   m_lastposition
; 
 106     int       m_axe
[wxJS_MAX_AXES
]; 
 108     wxWindow
* m_catchwin
; 
 111     friend class wxJoystick
; 
 114 //=========================================================================== 
 116 //=========================================================================== 
 118 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
 119 // wxGetIntFromCFDictionary 
 121 // Helper function that gets a integer from a dictionary key 
 122 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
 123 void wxGetIntFromCFDictionary(CFTypeRef cfDict
, CFStringRef key
, int* pOut
) 
 126           (CFNumberRef
) CFDictionaryGetValue((CFDictionaryRef
) cfDict
, 
 128                         kCFNumberIntType
, pOut
); 
 131 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
 135 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
 137 IMPLEMENT_DYNAMIC_CLASS(wxJoystick
, wxObject
) 
 139 //--------------------------------------------------------------------------- 
 140 // wxJoystick Constructor 
 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
), 
 150     m_hid 
= new wxHIDJoystick(); 
 152     if (m_hid
->Create(m_joystick
+1)) //wxHIDDevice is 1-based while this is 0 
 154         m_thread 
= new wxJoystickThread(m_hid
, m_joystick
); 
 165 //--------------------------------------------------------------------------- 
 166 // wxJoystick Destructor 
 168 // Releases the capture of the thread, deletes it, and deletes 
 169 // the native implementation. 
 170 //--------------------------------------------------------------------------- 
 171 wxJoystick::~wxJoystick() 
 175         m_thread
->Delete();  // It's detached so it will delete itself 
 181 //--------------------------------------------------------------------------- 
 182 // wxJoystick::Get[XXX]Position 
 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 
 189     wxPoint 
pos(wxDefaultPosition
); 
 190     if (m_thread
) pos 
= m_thread
->m_lastposition
; 
 193 int wxJoystick::GetZPosition() const 
 196         return m_thread
->m_axe
[wxJS_AXIS_Z
]; 
 199 int wxJoystick::GetRudderPosition() const 
 202         return m_thread
->m_axe
[wxJS_AXIS_RUDDER
]; 
 205 int wxJoystick::GetUPosition() const 
 208         return m_thread
->m_axe
[wxJS_AXIS_U
]; 
 211 int wxJoystick::GetVPosition() const 
 214         return m_thread
->m_axe
[wxJS_AXIS_V
]; 
 218 //--------------------------------------------------------------------------- 
 219 // wxJoystick::GetButtonState 
 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 
 227         return m_thread
->m_buttons
; 
 231 //--------------------------------------------------------------------------- 
 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 
 239     return m_hid 
!= NULL
; 
 242 //--------------------------------------------------------------------------- 
 243 // wxJoystick::Get[XXX](Id/Name) 
 245 // Simple accessors to the native HID implementation 
 246 //--------------------------------------------------------------------------- 
 247 int wxJoystick::GetManufacturerId() const 
 249     return m_hid
->m_nManufacturerId
; 
 252 int wxJoystick::GetProductId() const 
 254     return m_hid
->m_nProductId
; 
 257 wxString 
wxJoystick::GetProductName() const 
 259     return m_hid
->m_szProductName
; 
 262 //--------------------------------------------------------------------------- 
 263 // wxJoystick::GetNumberButtons 
 264 // wxJoystick::GetNumberAxes 
 266 // Queries the joystick for an active number of buttons/axes. 
 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 
 272 // These just query the native HID implementation as above. 
 273 //--------------------------------------------------------------------------- 
 274 int wxJoystick::GetNumberButtons() const 
 278     for(int nIndex 
= 0; nIndex 
< 40; ++nIndex
) 
 280         if(m_hid
->HasElement(nIndex
)) 
 286 int wxJoystick::GetNumberAxes() const 
 290     for(int nIndex 
= 40; nIndex 
< 50; ++nIndex
) 
 292         if(m_hid
->HasElement(nIndex
)) 
 299 //--------------------------------------------------------------------------- 
 300 // wxJoystick::GetNumberJoysticks 
 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 
 305 //--------------------------------------------------------------------------- 
 306 int wxJoystick::GetNumberJoysticks() 
 309         wxHIDDevice::GetCount(kHIDPage_GenericDesktop
, kHIDUsage_GD_Joystick
) + 
 310         wxHIDDevice::GetCount(kHIDPage_GenericDesktop
, kHIDUsage_GD_GamePad
); 
 313 //--------------------------------------------------------------------------- 
 314 // wxJoystick::SetCapture 
 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
) 
 323         m_thread
->m_catchwin 
= win
; 
 324         m_thread
->m_polling 
= pollingFreq
; 
 330 //--------------------------------------------------------------------------- 
 331 // wxJoystick::ReleaseCapture 
 333 // Stops sending events from the thread to the window set in 
 334 // SetCapture and stops polling the joystick 
 335 //--------------------------------------------------------------------------- 
 336 bool wxJoystick::ReleaseCapture() 
 340         m_thread
->m_catchwin 
= NULL
; 
 341         m_thread
->m_polling 
= 0; 
 347 //--------------------------------------------------------------------------- 
 348 // wxJoystick::Get[XXX] 
 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 
 355     return m_hid
->m_nXMin
; 
 358 int wxJoystick::GetYMin() const 
 360     return m_hid
->m_nYMin
; 
 363 int wxJoystick::GetZMin() const 
 365     return m_hid
->m_nZMin
; 
 368 int wxJoystick::GetRudderMin() const 
 370     return m_hid
->m_nRudderMin
; 
 373 int wxJoystick::GetUMin() const 
 375     return m_hid
->m_nUMin
; 
 378 int wxJoystick::GetVMin() const 
 380     return m_hid
->m_nVMin
; 
 383 int wxJoystick::GetXMax() const 
 385     return m_hid
->m_nXMax
; 
 388 int wxJoystick::GetYMax() const 
 390     return m_hid
->m_nYMax
; 
 393 int wxJoystick::GetZMax() const 
 395     return m_hid
->m_nZMax
; 
 398 int wxJoystick::GetRudderMax() const 
 400     return m_hid
->m_nRudderMax
; 
 403 int wxJoystick::GetUMax() const 
 405     return m_hid
->m_nUMax
; 
 408 int wxJoystick::GetVMax() const 
 410     return m_hid
->m_nVMax
; 
 413 //--------------------------------------------------------------------------- 
 414 // wxJoystick::Get[XXX] 
 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 
 421     return wxJS_MAX_BUTTONS
; 
 424 int wxJoystick::GetMaxAxes() const 
 426     return wxJS_MAX_AXES
; 
 429 int wxJoystick::GetPollingMin() const 
 434 int wxJoystick::GetPollingMax() const 
 439 //--------------------------------------------------------------------------- 
 440 // wxJoystick::Has[XXX] 
 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 
 447     return m_hid
->HasElement(wxJS_AXIS_Z
); 
 450 bool wxJoystick::HasRudder() const 
 452     return m_hid
->HasElement(wxJS_AXIS_RUDDER
); 
 455 bool wxJoystick::HasU() const 
 457     return m_hid
->HasElement(wxJS_AXIS_U
); 
 460 bool wxJoystick::HasV() const 
 462     return m_hid
->HasElement(wxJS_AXIS_V
); 
 465 //--------------------------------------------------------------------------- 
 467 //--------------------------------------------------------------------------- 
 468 int wxJoystick::GetPOVPosition() const 
 473 int wxJoystick::GetPOVCTSPosition() const 
 478 int wxJoystick::GetMovementThreshold() const 
 483 void wxJoystick::SetMovementThreshold(int WXUNUSED(threshold
)) 
 487 bool wxJoystick::HasPOV() const 
 492 bool wxJoystick::HasPOV4Dir() const 
 497 bool wxJoystick::HasPOVCTS() const 
 502 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
 506 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
 508 //--------------------------------------------------------------------------- 
 509 // wxHIDJoystick ctor 
 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) 
 519 //--------------------------------------------------------------------------- 
 520 // wxHIDJoystick dtor 
 523 //--------------------------------------------------------------------------- 
 524 wxHIDJoystick::~wxHIDJoystick() 
 528 //--------------------------------------------------------------------------- 
 529 // wxHIDJoystick::Create 
 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
) 
 536     int nJoysticks 
= GetCount(kHIDPage_GenericDesktop
, kHIDUsage_GD_Joystick
); 
 538     if (nWhich 
<= nJoysticks
) 
 539         return wxHIDDevice::Create(kHIDPage_GenericDesktop
, 
 540                                    kHIDUsage_GD_Joystick
, 
 543         nWhich 
-= nJoysticks
; 
 545     int nGamePads 
= GetCount(kHIDPage_GenericDesktop
, kHIDUsage_GD_GamePad
); 
 547     if (nWhich 
<= nGamePads
) 
 548         return wxHIDDevice::Create(kHIDPage_GenericDesktop
, 
 549                                    kHIDUsage_GD_GamePad
, 
 555 //--------------------------------------------------------------------------- 
 556 // wxHIDJoystick::BuildCookies 
 557 // wxHIDJoystick::MakeCookies 
 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. 
 562 // MakeCookies is just a recursive function for each array within 
 564 //--------------------------------------------------------------------------- 
 565 void wxHIDJoystick::BuildCookies(CFArrayRef Array
) 
 567     InitCookies(50, true); 
 570     // I wasted two hours of my life on this line :( 
 571     // accidently removed it during some source cleaning... 
 575     //paranoid debugging stuff 
 577     for(int i 
= 0; i 
< 50; ++i
) 
 578         wxPrintf(wxT("\nVAL #%i:[%i]"), i
, m_pCookies
[i
]); 
 582 void wxHIDJoystick::MakeCookies(CFArrayRef Array
) 
 584     int i
, nUsage
, nPage
; 
 586     for (i 
= 0; i 
< CFArrayGetCount(Array
); ++i
) 
 588         const void* ref 
= CFDictionaryGetValue( 
 589                 (CFDictionaryRef
)CFArrayGetValueAtIndex(Array
, i
), 
 590                 CFSTR(kIOHIDElementKey
) 
 595             MakeCookies((CFArrayRef
) ref
); 
 601                     CFDictionaryGetValue( 
 602                         (CFDictionaryRef
) CFArrayGetValueAtIndex(Array
, i
), 
 603                         CFSTR(kIOHIDElementUsageKey
) 
 610                     CFDictionaryGetValue( 
 611                         (CFDictionaryRef
) CFArrayGetValueAtIndex(Array
, i
), 
 612                         CFSTR(kIOHIDElementUsagePageKey
) 
 618             wxLogSysError(wxT("[%i][%i]"), nUsage
, nPage
); 
 620             if (nPage 
== kHIDPage_Button 
&& nUsage 
<= 40) 
 621                 AddCookieInQueue(CFArrayGetValueAtIndex(Array
, i
), nUsage
-1 ); 
 622             else if (nPage 
== kHIDPage_GenericDesktop
) 
 628                         AddCookieInQueue(CFArrayGetValueAtIndex(Array
, i
), wxJS_AXIS_X
); 
 629                         wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array
, i
), 
 630                                                  CFSTR(kIOHIDElementMaxKey
), 
 632                         wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array
, i
), 
 633                                                  CFSTR(kIOHIDElementMinKey
), 
 637                         AddCookieInQueue(CFArrayGetValueAtIndex(Array
, i
), wxJS_AXIS_Y
); 
 638                         wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array
, i
), 
 639                                                  CFSTR(kIOHIDElementMaxKey
), 
 641                         wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array
, i
), 
 642                                                  CFSTR(kIOHIDElementMinKey
), 
 646                         AddCookieInQueue(CFArrayGetValueAtIndex(Array
, i
), wxJS_AXIS_Z
); 
 647                         wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array
, i
), 
 648                                                  CFSTR(kIOHIDElementMaxKey
), 
 650                         wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array
, i
), 
 651                                                  CFSTR(kIOHIDElementMinKey
), 
 658             else if (nPage 
== kHIDPage_Simulation 
&& nUsage 
== kHIDUsage_Sim_Rudder
) 
 661                 AddCookieInQueue(CFArrayGetValueAtIndex(Array
, i
), wxJS_AXIS_RUDDER 
); 
 662                 wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array
, i
), 
 663                                          CFSTR(kIOHIDElementMaxKey
), 
 665                 wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array
, i
), 
 666                                          CFSTR(kIOHIDElementMinKey
), 
 673 //--------------------------------------------------------------------------- 
 674 // wxHIDJoystick::Get[XXX] 
 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
;   } 
 684 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
 688 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
 690 //--------------------------------------------------------------------------- 
 691 // wxJoystickThread Constructor 
 693 // Just initializes members 
 694 //--------------------------------------------------------------------------- 
 695 wxJoystickThread::wxJoystickThread(wxHIDJoystick
* hid
, int joystick
) 
 697       m_joystick(joystick
), 
 698       m_lastposition(127,127), 
 703     memset(m_axe
, 0, sizeof(int) * wxJS_MAX_AXES
); 
 706 //--------------------------------------------------------------------------- 
 707 // wxJoystickThread::Entry 
 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() 
 719     CFRunLoopSourceRef pRLSource 
= NULL
; 
 721     if ((*m_hid
->GetQueue())->createAsyncEventSource( 
 722                     m_hid
->GetQueue(), &pRLSource
) != kIOReturnSuccess 
) 
 724         wxLogSysError(wxT("Couldn't create async event source")); 
 728     wxASSERT(pRLSource 
!= NULL
); 
 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
) ); 
 736     if( (*m_hid
->GetQueue())->setEventCallout(m_hid
->GetQueue(), 
 737           wxJoystickThread::HIDCallback
, this, this) != kIOReturnSuccess 
) 
 739         wxLogSysError(wxT("Could not set event callout for queue")); 
 743     if( (*m_hid
->GetQueue())->start(m_hid
->GetQueue()) != kIOReturnSuccess 
) 
 745         wxLogSysError(wxT("Could not start queue")); 
 757             dTime 
= 0.0001 * m_polling
; 
 759             dTime 
= 0.0001 * 10;  // check at least every 10 msec in "blocking" case 
 761         //true just "handles and returns" - false forces it to stay the time 
 764         CFRunLoopRunInMode(kCFRunLoopDefaultMode
, dTime
, true); 
 767         HIDCallback(this, ret
, this, this); 
 772     wxASSERT( CFRunLoopContainsSource(pRL
, pRLSource
, kCFRunLoopDefaultMode
) ); 
 774     CFRunLoopRemoveSource(pRL
, pRLSource
, kCFRunLoopDefaultMode
); 
 775     CFRelease(pRLSource
); 
 780 //--------------------------------------------------------------------------- 
 781 // wxJoystickThread::HIDCallback (static) 
 783 // Callback for the native HID device when it recieves input. 
 785 // This is where the REAL dirty work gets done. 
 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
), 
 801                                               void* WXUNUSED(sender
)) 
 803     IOHIDEventStruct hidevent
; 
 804     AbsoluteTime bogustime 
= {0,0}; 
 806     wxJoystickThread
* pThis 
= (wxJoystickThread
*) context
; 
 807     wxHIDJoystick
* m_hid 
= pThis
->m_hid
; 
 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); 
 815     while (ret 
!= kIOReturnUnderrun
) 
 817         if (pThis
->TestDestroy()) 
 820         if(ret 
!= kIOReturnSuccess
) 
 822             wxLogSysError(wxString::Format(wxT("wxJoystick Error:[%i]"), ret
)); 
 826         wxJoystickEvent wxevent
; 
 828         //Find the cookie that changed 
 830         IOHIDElementCookie
* pCookies 
= m_hid
->GetCookies(); 
 833             if(hidevent
.elementCookie 
== pCookies
[nIndex
]) 
 843             wxLogSysError(wxString::Format(wxT("wxJoystick Out Of Bounds Error"))); 
 848         //is the cookie a button? 
 853                 pThis
->m_buttons 
|= (1 << nIndex
); 
 854                 wxevent
.SetEventType(wxEVT_JOY_BUTTON_DOWN
); 
 858                 pThis
->m_buttons 
&= ~(1 << nIndex
); 
 859                 wxevent
.SetEventType(wxEVT_JOY_BUTTON_UP
); 
 862             wxevent
.SetButtonChange(nIndex
+1); 
 864         else if (nIndex 
== wxJS_AXIS_X
) 
 866             pThis
->m_lastposition
.x 
= hidevent
.value
; 
 867             wxevent
.SetEventType(wxEVT_JOY_MOVE
); 
 868             pThis
->m_axe
[0] = hidevent
.value
; 
 870         else if (nIndex 
== wxJS_AXIS_Y
) 
 872             pThis
->m_lastposition
.y 
= hidevent
.value
; 
 873             wxevent
.SetEventType(wxEVT_JOY_MOVE
); 
 874             pThis
->m_axe
[1] = hidevent
.value
; 
 876         else if (nIndex 
== wxJS_AXIS_Z
) 
 878             wxevent
.SetEventType(wxEVT_JOY_ZMOVE
); 
 879             pThis
->m_axe
[2] = hidevent
.value
; 
 882             wxevent
.SetEventType(wxEVT_JOY_MOVE
); 
 884         Nanoseconds timestamp 
= AbsoluteToNanoseconds(hidevent
.timestamp
); 
 886         wxULongLong 
llTime(timestamp
.hi
, timestamp
.lo
); 
 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
); 
 897         if (pThis
->m_catchwin
) 
 898             pThis
->m_catchwin
->AddPendingEvent(wxevent
); 
 900         ret 
= (*m_hid
->GetQueue())->getNextEvent(m_hid
->GetQueue(), 
 901                     &hidevent
, bogustime
, 0); 
 905 #endif // wxUSE_JOYSTICK && defined(__DARWIN__)