1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/osx/core/joystick.cpp 
   3 // Purpose:     wxJoystick class 
   7 // Copyright:   (c) Ryan Norton 
   8 // Licence:     wxWindows licence 
   9 ///////////////////////////////////////////////////////////////////////////// 
  11 //=========================================================================== 
  13 //=========================================================================== 
  15 //--------------------------------------------------------------------------- 
  16 // Pre-compiled header stuff 
  17 //--------------------------------------------------------------------------- 
  19 // For compilers that support precompilation, includes "wx.h". 
  20 #include "wx/wxprec.h" 
  22 //--------------------------------------------------------------------------- 
  24 //--------------------------------------------------------------------------- 
  26 //we only support HID on OSX (DARWIN), since it requires DARWIN... 
  27 #if wxUSE_JOYSTICK && wxUSE_THREADS 
  29 //--------------------------------------------------------------------------- 
  31 //--------------------------------------------------------------------------- 
  35     #include "wx/event.h"   //joystick wxEvents 
  36     #include "wx/window.h"  //for wxWindow to "capture" joystick 
  39 #include "wx/joystick.h"    //... 
  40 #include "wx/thread.h"      //wxThread for polling thread/ wxCriticalSection 
  43 #include "wx/osx/core/hid.h" //private mac hid stuff 
  46 #include <CoreServices/CoreServices.h> 
  47 #include <mach/mach.h> 
  48 #include <mach/mach_time.h> 
  51 //--------------------------------------------------------------------------- 
  52 // Definitions/Enumerations 
  53 //--------------------------------------------------------------------------- 
  55 #define wxJS_MAX_AXES       10 /*max number of axes*/ 
  56 #define wxJS_MAX_BUTTONS    40 /*max number of buttons*/ 
  60     //These are positions within the cookie array 
  61     //in wxHIDJoystick that the cookies that store the axis' are 
  70 //--------------------------------------------------------------------------- 
  72 //--------------------------------------------------------------------------- 
  73 class wxHIDJoystick 
: public wxHIDDevice
 
  77     virtual ~wxHIDJoystick(); 
  79     bool Create(int nWhich
); 
  80     virtual void BuildCookies(CFArrayRef Array
); 
  81     void MakeCookies(CFArrayRef Array
); 
  82     IOHIDElementCookie
* GetCookies(); 
  83     IOHIDQueueInterface
** GetQueue(); 
  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
; 
  88     friend class wxJoystick
; 
  91 //--------------------------------------------------------------------------- 
  93 //--------------------------------------------------------------------------- 
  94 class wxJoystickThread 
: public wxThread
 
  97     wxJoystickThread(wxHIDJoystick
* hid
, int joystick
); 
  99     static void HIDCallback(void* target
, IOReturn res
, void* context
, void* sender
); 
 102     wxHIDJoystick
*       m_hid
; 
 104     wxPoint   m_lastposition
; 
 105     int       m_axe
[wxJS_MAX_AXES
]; 
 107     wxWindow
* m_catchwin
; 
 110     friend class wxJoystick
; 
 113 //=========================================================================== 
 115 //=========================================================================== 
 117 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
 118 // wxGetIntFromCFDictionary 
 120 // Helper function that gets a integer from a dictionary key 
 121 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
 122 void wxGetIntFromCFDictionary(CFTypeRef cfDict
, CFStringRef key
, int* pOut
) 
 125           (CFNumberRef
) CFDictionaryGetValue((CFDictionaryRef
) cfDict
, 
 127                         kCFNumberIntType
, pOut
); 
 130 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
 134 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
 136 IMPLEMENT_DYNAMIC_CLASS(wxJoystick
, wxObject
) 
 138 //--------------------------------------------------------------------------- 
 139 // wxJoystick Constructor 
 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 //--------------------------------------------------------------------------- 
 145 wxJoystick::wxJoystick(int joystick
) 
 146     : m_joystick(joystick
), 
 149     m_hid 
= new wxHIDJoystick(); 
 151     if (m_hid
->Create(m_joystick
+1)) //wxHIDDevice is 1-based while this is 0 
 153         m_thread 
= new wxJoystickThread(m_hid
, m_joystick
); 
 163 //--------------------------------------------------------------------------- 
 164 // wxJoystick Destructor 
 166 // Releases the capture of the thread, deletes it, and deletes 
 167 // the native implementation. 
 168 //--------------------------------------------------------------------------- 
 169 wxJoystick::~wxJoystick() 
 173         m_thread
->Delete();  // It's detached so it will delete itself 
 178 //--------------------------------------------------------------------------- 
 179 // wxJoystick::Get[XXX]Position 
 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 //--------------------------------------------------------------------------- 
 184 wxPoint 
wxJoystick::GetPosition() const 
 186     wxPoint 
pos(wxDefaultPosition
); 
 187     if (m_thread
) pos 
= m_thread
->m_lastposition
; 
 190 int wxJoystick::GetZPosition() const 
 193         return m_thread
->m_axe
[wxJS_AXIS_Z
-wxJS_AXIS_X
]; 
 196 int wxJoystick::GetRudderPosition() const 
 199         return m_thread
->m_axe
[wxJS_AXIS_RUDDER
-wxJS_AXIS_X
]; 
 202 int wxJoystick::GetUPosition() const 
 205         return m_thread
->m_axe
[wxJS_AXIS_U
-wxJS_AXIS_X
]; 
 208 int wxJoystick::GetVPosition() const 
 211         return m_thread
->m_axe
[wxJS_AXIS_V
-wxJS_AXIS_X
]; 
 215 //--------------------------------------------------------------------------- 
 216 // wxJoystick::GetButtonState 
 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 //--------------------------------------------------------------------------- 
 221 int wxJoystick::GetButtonState() const 
 224         return m_thread
->m_buttons
; 
 228 //--------------------------------------------------------------------------- 
 231 // Returns whether the joystick initialized successfully - in this case 
 232 // if the native implementation doesn't exist (in constructor) 
 233 //--------------------------------------------------------------------------- 
 234 bool wxJoystick::IsOk() const 
 236     return m_hid 
!= NULL
; 
 239 //--------------------------------------------------------------------------- 
 240 // wxJoystick::Get[XXX](Id/Name) 
 242 // Simple accessors to the native HID implementation 
 243 //--------------------------------------------------------------------------- 
 244 int wxJoystick::GetManufacturerId() const 
 246     return m_hid
->m_nManufacturerId
; 
 249 int wxJoystick::GetProductId() const 
 251     return m_hid
->m_nProductId
; 
 254 wxString 
wxJoystick::GetProductName() const 
 256     return m_hid
->m_szProductName
; 
 259 //--------------------------------------------------------------------------- 
 260 // wxJoystick::GetNumberButtons 
 261 // wxJoystick::GetNumberAxes 
 263 // Queries the joystick for an active number of buttons/axes. 
 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 
 269 // These just query the native HID implementation as above. 
 270 //--------------------------------------------------------------------------- 
 271 int wxJoystick::GetNumberButtons() const 
 275     for(int nIndex 
= 0; nIndex 
< 40; ++nIndex
) 
 277         if(m_hid
->HasElement(nIndex
)) 
 283 int wxJoystick::GetNumberAxes() const 
 287     for(int nIndex 
= 40; nIndex 
< 50; ++nIndex
) 
 289         if(m_hid
->HasElement(nIndex
)) 
 296 //--------------------------------------------------------------------------- 
 297 // wxJoystick::GetNumberJoysticks 
 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 
 302 //--------------------------------------------------------------------------- 
 303 int wxJoystick::GetNumberJoysticks() 
 306         wxHIDDevice::GetCount(kHIDPage_GenericDesktop
, kHIDUsage_GD_Joystick
) + 
 307         wxHIDDevice::GetCount(kHIDPage_GenericDesktop
, kHIDUsage_GD_GamePad
); 
 310 //--------------------------------------------------------------------------- 
 311 // wxJoystick::SetCapture 
 313 // Stops sending events from the thread to the window set in 
 314 // SetCapture and stops polling the joystick 
 315 //--------------------------------------------------------------------------- 
 316 bool wxJoystick::SetCapture(wxWindow
* win
, int pollingFreq
) 
 320         m_thread
->m_catchwin 
= win
; 
 321         m_thread
->m_polling 
= pollingFreq
; 
 327 //--------------------------------------------------------------------------- 
 328 // wxJoystick::ReleaseCapture 
 330 // Stops sending events from the thread to the window set in 
 331 // SetCapture and stops polling the joystick 
 332 //--------------------------------------------------------------------------- 
 333 bool wxJoystick::ReleaseCapture() 
 337         m_thread
->m_catchwin 
= NULL
; 
 338         m_thread
->m_polling 
= 0; 
 344 //--------------------------------------------------------------------------- 
 345 // wxJoystick::Get[XXX] 
 347 // Gets the minimum and maximum values for each axis, returning 0 if the 
 348 // axis doesn't exist. 
 349 //--------------------------------------------------------------------------- 
 350 int wxJoystick::GetXMin() const 
 352     return m_hid
->m_nXMin
; 
 355 int wxJoystick::GetYMin() const 
 357     return m_hid
->m_nYMin
; 
 360 int wxJoystick::GetZMin() const 
 362     return m_hid
->m_nZMin
; 
 365 int wxJoystick::GetRudderMin() const 
 367     return m_hid
->m_nRudderMin
; 
 370 int wxJoystick::GetUMin() const 
 372     return m_hid
->m_nUMin
; 
 375 int wxJoystick::GetVMin() const 
 377     return m_hid
->m_nVMin
; 
 380 int wxJoystick::GetXMax() const 
 382     return m_hid
->m_nXMax
; 
 385 int wxJoystick::GetYMax() const 
 387     return m_hid
->m_nYMax
; 
 390 int wxJoystick::GetZMax() const 
 392     return m_hid
->m_nZMax
; 
 395 int wxJoystick::GetRudderMax() const 
 397     return m_hid
->m_nRudderMax
; 
 400 int wxJoystick::GetUMax() const 
 402     return m_hid
->m_nUMax
; 
 405 int wxJoystick::GetVMax() const 
 407     return m_hid
->m_nVMax
; 
 410 //--------------------------------------------------------------------------- 
 411 // wxJoystick::Get[XXX] 
 413 // Min/Max values for buttons, axes, etc.. Polling in this case is just 
 414 // what the linux port has. 
 415 //--------------------------------------------------------------------------- 
 416 int wxJoystick::GetMaxButtons() const 
 418     return wxJS_MAX_BUTTONS
; 
 421 int wxJoystick::GetMaxAxes() const 
 423     return wxJS_MAX_AXES
; 
 426 int wxJoystick::GetPollingMin() const 
 431 int wxJoystick::GetPollingMax() const 
 436 //--------------------------------------------------------------------------- 
 437 // wxJoystick::Has[XXX] 
 439 // Just queries the native hid implementation if the cookie was found 
 440 // when enumerating the cookies of the joystick device 
 441 //--------------------------------------------------------------------------- 
 442 bool wxJoystick::HasZ() const 
 444     return m_hid
->HasElement(wxJS_AXIS_Z
); 
 447 bool wxJoystick::HasRudder() const 
 449     return m_hid
->HasElement(wxJS_AXIS_RUDDER
); 
 452 bool wxJoystick::HasU() const 
 454     return m_hid
->HasElement(wxJS_AXIS_U
); 
 457 bool wxJoystick::HasV() const 
 459     return m_hid
->HasElement(wxJS_AXIS_V
); 
 462 //--------------------------------------------------------------------------- 
 464 //--------------------------------------------------------------------------- 
 465 int wxJoystick::GetPOVPosition() const 
 470 int wxJoystick::GetPOVCTSPosition() const 
 475 int wxJoystick::GetMovementThreshold() const 
 480 void wxJoystick::SetMovementThreshold(int WXUNUSED(threshold
)) 
 484 bool wxJoystick::HasPOV() const 
 489 bool wxJoystick::HasPOV4Dir() const 
 494 bool wxJoystick::HasPOVCTS() const 
 499 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
 503 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
 505 //--------------------------------------------------------------------------- 
 506 // wxHIDJoystick ctor 
 508 // Initializes the min/max members 
 509 //--------------------------------------------------------------------------- 
 510 wxHIDJoystick::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) 
 516 //--------------------------------------------------------------------------- 
 517 // wxHIDJoystick dtor 
 520 //--------------------------------------------------------------------------- 
 521 wxHIDJoystick::~wxHIDJoystick() 
 525 //--------------------------------------------------------------------------- 
 526 // wxHIDJoystick::Create 
 528 // Creates the native HID device (joysticks are of either 
 529 // kHIDUsage_GD_Joystick or kHIDUsage_GD_GamePad) 
 530 //--------------------------------------------------------------------------- 
 531 bool wxHIDJoystick::Create(int nWhich
) 
 533     int nJoysticks 
= GetCount(kHIDPage_GenericDesktop
, kHIDUsage_GD_Joystick
); 
 535     if (nWhich 
<= nJoysticks
) 
 536         return wxHIDDevice::Create(kHIDPage_GenericDesktop
, 
 537                                    kHIDUsage_GD_Joystick
, 
 540         nWhich 
-= nJoysticks
; 
 542     int nGamePads 
= GetCount(kHIDPage_GenericDesktop
, kHIDUsage_GD_GamePad
); 
 544     if (nWhich 
<= nGamePads
) 
 545         return wxHIDDevice::Create(kHIDPage_GenericDesktop
, 
 546                                    kHIDUsage_GD_GamePad
, 
 552 //--------------------------------------------------------------------------- 
 553 // wxHIDJoystick::BuildCookies 
 554 // wxHIDJoystick::MakeCookies 
 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. 
 559 // MakeCookies is just a recursive function for each array within 
 561 //--------------------------------------------------------------------------- 
 562 void wxHIDJoystick::BuildCookies(CFArrayRef Array
) 
 564     InitCookies(50, true); 
 567     // I wasted two hours of my life on this line :( 
 568     // accidentally removed it during some source cleaning... 
 572     //paranoid debugging stuff 
 574     for(int i 
= 0; i 
< 50; ++i
) 
 575         wxPrintf(wxT("\nVAL #%i:[%i]"), i
, m_pCookies
[i
]); 
 579 void wxHIDJoystick::MakeCookies(CFArrayRef Array
) 
 581     int i
, nUsage
, nPage
; 
 583     for (i 
= 0; i 
< CFArrayGetCount(Array
); ++i
) 
 585         const void* ref 
= CFDictionaryGetValue( 
 586                 (CFDictionaryRef
)CFArrayGetValueAtIndex(Array
, i
), 
 587                 CFSTR(kIOHIDElementKey
) 
 592             MakeCookies((CFArrayRef
) ref
); 
 598                     CFDictionaryGetValue( 
 599                         (CFDictionaryRef
) CFArrayGetValueAtIndex(Array
, i
), 
 600                         CFSTR(kIOHIDElementUsageKey
) 
 607                     CFDictionaryGetValue( 
 608                         (CFDictionaryRef
) CFArrayGetValueAtIndex(Array
, i
), 
 609                         CFSTR(kIOHIDElementUsagePageKey
) 
 615             wxLogSysError(wxT("[%i][%i]"), nUsage
, nPage
); 
 617             if (nPage 
== kHIDPage_Button 
&& nUsage 
<= 40) 
 618                 AddCookieInQueue(CFArrayGetValueAtIndex(Array
, i
), nUsage
-1 ); 
 619             else if (nPage 
== kHIDPage_GenericDesktop
) 
 625                         AddCookieInQueue(CFArrayGetValueAtIndex(Array
, i
), wxJS_AXIS_X
); 
 626                         wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array
, i
), 
 627                                                  CFSTR(kIOHIDElementMaxKey
), 
 629                         wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array
, i
), 
 630                                                  CFSTR(kIOHIDElementMinKey
), 
 634                         AddCookieInQueue(CFArrayGetValueAtIndex(Array
, i
), wxJS_AXIS_Y
); 
 635                         wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array
, i
), 
 636                                                  CFSTR(kIOHIDElementMaxKey
), 
 638                         wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array
, i
), 
 639                                                  CFSTR(kIOHIDElementMinKey
), 
 643                         AddCookieInQueue(CFArrayGetValueAtIndex(Array
, i
), wxJS_AXIS_Z
); 
 644                         wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array
, i
), 
 645                                                  CFSTR(kIOHIDElementMaxKey
), 
 647                         wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array
, i
), 
 648                                                  CFSTR(kIOHIDElementMinKey
), 
 655             else if (nPage 
== kHIDPage_Simulation 
&& nUsage 
== kHIDUsage_Sim_Rudder
) 
 658                 AddCookieInQueue(CFArrayGetValueAtIndex(Array
, i
), wxJS_AXIS_RUDDER 
); 
 659                 wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array
, i
), 
 660                                          CFSTR(kIOHIDElementMaxKey
), 
 662                 wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array
, i
), 
 663                                          CFSTR(kIOHIDElementMinKey
), 
 670 //--------------------------------------------------------------------------- 
 671 // wxHIDJoystick::Get[XXX] 
 673 // Simple accessors so that the HID callback and the thread procedure 
 674 // can access members from wxHIDDevice (our parent here). 
 675 //--------------------------------------------------------------------------- 
 676 IOHIDElementCookie
* wxHIDJoystick::GetCookies() 
 677 {   return m_pCookies
;  } 
 678 IOHIDQueueInterface
** wxHIDJoystick::GetQueue() 
 679 {   return m_ppQueue
;   } 
 681 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
 685 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
 687 //--------------------------------------------------------------------------- 
 688 // wxJoystickThread Constructor 
 690 // Just initializes members 
 691 //--------------------------------------------------------------------------- 
 692 wxJoystickThread::wxJoystickThread(wxHIDJoystick
* hid
, int joystick
) 
 694       m_joystick(joystick
), 
 695       m_lastposition(127,127), 
 700     memset(m_axe
, 0, sizeof(int) * wxJS_MAX_AXES
); 
 703 //--------------------------------------------------------------------------- 
 704 // wxJoystickThread::Entry 
 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 //--------------------------------------------------------------------------- 
 714 void* wxJoystickThread::Entry() 
 716     CFRunLoopSourceRef pRLSource 
= NULL
; 
 718     if ((*m_hid
->GetQueue())->createAsyncEventSource( 
 719                     m_hid
->GetQueue(), &pRLSource
) != kIOReturnSuccess 
) 
 721         wxLogSysError(wxT("Couldn't create async event source")); 
 725     wxASSERT(pRLSource 
!= NULL
); 
 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
) ); 
 733     if( (*m_hid
->GetQueue())->setEventCallout(m_hid
->GetQueue(), 
 734           wxJoystickThread::HIDCallback
, this, this) != kIOReturnSuccess 
) 
 736         wxLogSysError(wxT("Could not set event callout for queue")); 
 740     if( (*m_hid
->GetQueue())->start(m_hid
->GetQueue()) != kIOReturnSuccess 
) 
 742         wxLogSysError(wxT("Could not start queue")); 
 754             dTime 
= 0.0001 * m_polling
; 
 756             dTime 
= 0.0001 * 10;  // check at least every 10 msec in "blocking" case 
 758         //true just "handles and returns" - false forces it to stay the time 
 761         CFRunLoopRunInMode(kCFRunLoopDefaultMode
, dTime
, true); 
 764         HIDCallback(this, ret
, this, this); 
 769     wxASSERT( CFRunLoopContainsSource(pRL
, pRLSource
, kCFRunLoopDefaultMode
) ); 
 771     CFRunLoopRemoveSource(pRL
, pRLSource
, kCFRunLoopDefaultMode
); 
 772     CFRelease(pRLSource
); 
 777 //--------------------------------------------------------------------------- 
 778 // wxJoystickThread::HIDCallback (static) 
 780 // Callback for the native HID device when it receives input. 
 782 // This is where the REAL dirty work gets done. 
 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
), 
 798                                               void* WXUNUSED(sender
)) 
 800     IOHIDEventStruct hidevent
; 
 801     AbsoluteTime bogustime 
= {0,0}; 
 803     wxJoystickThread
* pThis 
= (wxJoystickThread
*) context
; 
 804     wxHIDJoystick
* m_hid 
= pThis
->m_hid
; 
 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); 
 812     while (ret 
!= kIOReturnUnderrun
) 
 814         if (pThis
->TestDestroy()) 
 817         if(ret 
!= kIOReturnSuccess
) 
 819             wxLogSysError(wxString::Format(wxT("wxJoystick Error:[%i]"), ret
)); 
 823         wxJoystickEvent wxevent
; 
 825         //Find the cookie that changed 
 827         IOHIDElementCookie
* pCookies 
= m_hid
->GetCookies(); 
 830             if(hidevent
.elementCookie 
== pCookies
[nIndex
]) 
 840             wxLogSysError(wxString::Format(wxT("wxJoystick Out Of Bounds Error"))); 
 845         //is the cookie a button? 
 850                 pThis
->m_buttons 
|= (1 << nIndex
); 
 851                 wxevent
.SetEventType(wxEVT_JOY_BUTTON_DOWN
); 
 855                 pThis
->m_buttons 
&= ~(1 << nIndex
); 
 856                 wxevent
.SetEventType(wxEVT_JOY_BUTTON_UP
); 
 859             wxevent
.SetButtonChange(nIndex
+1); 
 861         else if (nIndex 
== wxJS_AXIS_X
) 
 863             pThis
->m_lastposition
.x 
= hidevent
.value
; 
 864             wxevent
.SetEventType(wxEVT_JOY_MOVE
); 
 865             pThis
->m_axe
[0] = hidevent
.value
; 
 867         else if (nIndex 
== wxJS_AXIS_Y
) 
 869             pThis
->m_lastposition
.y 
= hidevent
.value
; 
 870             wxevent
.SetEventType(wxEVT_JOY_MOVE
); 
 871             pThis
->m_axe
[1] = hidevent
.value
; 
 873         else if (nIndex 
== wxJS_AXIS_Z
) 
 875             wxevent
.SetEventType(wxEVT_JOY_ZMOVE
); 
 876             pThis
->m_axe
[2] = hidevent
.value
; 
 879             wxevent
.SetEventType(wxEVT_JOY_MOVE
); 
 881         Nanoseconds timestamp 
= AbsoluteToNanoseconds(hidevent
.timestamp
); 
 883         wxULongLong 
llTime(timestamp
.hi
, timestamp
.lo
); 
 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
); 
 894         if (pThis
->m_catchwin
) 
 895             pThis
->m_catchwin
->GetEventHandler()->AddPendingEvent(wxevent
); 
 897         ret 
= (*m_hid
->GetQueue())->getNextEvent(m_hid
->GetQueue(), 
 898                     &hidevent
, bogustime
, 0); 
 902 #endif // wxUSE_JOYSTICK