]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/mac/corefoundation/hidjoystick.cpp
Applied patch [ 1776951 ] wxSizer::GetContainingWindow fails for nested sizers
[wxWidgets.git] / src / mac / corefoundation / hidjoystick.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/mac/corefoundation/joystick.cpp
3// Purpose: wxJoystick class
4// Author: Ryan Norton
5// Modified by:
6// Created: 2/13/2005
7// RCS-ID: $Id$
8// Copyright: (c) Ryan Norton
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12//===========================================================================
13// DECLARATIONS
14//===========================================================================
15
16//---------------------------------------------------------------------------
17// Pre-compiled header stuff
18//---------------------------------------------------------------------------
19
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23//---------------------------------------------------------------------------
24// Guard
25//---------------------------------------------------------------------------
26
27//we only support HID on OSX (DARWIN), since it requires DARWIN...
28#if wxUSE_JOYSTICK && defined(__DARWIN__) && 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/mac/corefoundation/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
59enum
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//---------------------------------------------------------------------------
74class wxHIDJoystick : public wxHIDDevice
75{
76public:
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//---------------------------------------------------------------------------
95class wxJoystickThread : public wxThread
96{
97public:
98 wxJoystickThread(wxHIDJoystick* hid, int joystick);
99 void* Entry();
100 static void HIDCallback(void* target, IOReturn res, void* context, void* sender);
101
102private:
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//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
123void 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
137IMPLEMENT_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//---------------------------------------------------------------------------
146wxJoystick::wxJoystick(int joystick)
147 : m_joystick(joystick),
148 m_thread(NULL)
149{
150 m_hid = new wxHIDJoystick();
151
152 if (m_hid->Create(m_joystick+1)) //wxHIDDevice is 1-based while this is 0
153 {
154 m_thread = new wxJoystickThread(m_hid, m_joystick);
155 m_thread->Create();
156 m_thread->Run();
157 }
158 else
159 {
160 delete m_hid;
161 m_hid = NULL;
162 }
163}
164
165//---------------------------------------------------------------------------
166// wxJoystick Destructor
167//
168// Releases the capture of the thread, deletes it, and deletes
169// the native implementation.
170//---------------------------------------------------------------------------
171wxJoystick::~wxJoystick()
172{
173 ReleaseCapture();
174 if (m_thread)
175 m_thread->Delete(); // It's detached so it will delete itself
176
177 if (m_hid)
178 delete m_hid;
179}
180
181//---------------------------------------------------------------------------
182// wxJoystick::Get[XXX]Position
183//
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//---------------------------------------------------------------------------
187wxPoint wxJoystick::GetPosition() const
188{
189 wxPoint pos(wxDefaultPosition);
190 if (m_thread) pos = m_thread->m_lastposition;
191 return pos;
192}
193int wxJoystick::GetZPosition() const
194{
195 if (m_thread)
196 return m_thread->m_axe[wxJS_AXIS_Z];
197 return 0;
198}
199int wxJoystick::GetRudderPosition() const
200{
201 if (m_thread)
202 return m_thread->m_axe[wxJS_AXIS_RUDDER];
203 return 0;
204}
205int wxJoystick::GetUPosition() const
206{
207 if (m_thread)
208 return m_thread->m_axe[wxJS_AXIS_U];
209 return 0;
210}
211int wxJoystick::GetVPosition() const
212{
213 if (m_thread)
214 return m_thread->m_axe[wxJS_AXIS_V];
215 return 0;
216}
217
218//---------------------------------------------------------------------------
219// wxJoystick::GetButtonState
220//
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//---------------------------------------------------------------------------
224int wxJoystick::GetButtonState() const
225{
226 if (m_thread)
227 return m_thread->m_buttons;
228 return 0;
229}
230
231//---------------------------------------------------------------------------
232// wxJoystick::IsOk
233//
234// Returns whether the joystick initialized successfully - in this case
235// if the native implementation doesn't exist (in constructor)
236//---------------------------------------------------------------------------
237bool wxJoystick::IsOk() const
238{
239 return m_hid != NULL;
240}
241
242//---------------------------------------------------------------------------
243// wxJoystick::Get[XXX](Id/Name)
244//
245// Simple accessors to the native HID implementation
246//---------------------------------------------------------------------------
247int wxJoystick::GetManufacturerId() const
248{
249 return m_hid->m_nManufacturerId;
250}
251
252int wxJoystick::GetProductId() const
253{
254 return m_hid->m_nProductId;
255}
256
257wxString wxJoystick::GetProductName() const
258{
259 return m_hid->m_szProductName;
260}
261
262//---------------------------------------------------------------------------
263// wxJoystick::GetNumberButtons
264// wxJoystick::GetNumberAxes
265//
266// Queries the joystick for an active number of buttons/axes.
267//
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
271//
272// These just query the native HID implementation as above.
273//---------------------------------------------------------------------------
274int wxJoystick::GetNumberButtons() const
275{
276 int nCount = 0;
277
278 for(int nIndex = 0; nIndex < 40; ++nIndex)
279 {
280 if(m_hid->HasElement(nIndex))
281 ++nCount;
282 }
283
284 return nCount;
285}
286int wxJoystick::GetNumberAxes() const
287{
288 int nCount = 0;
289
290 for(int nIndex = 40; nIndex < 50; ++nIndex)
291 {
292 if(m_hid->HasElement(nIndex))
293 ++nCount;
294 }
295
296 return nCount;
297}
298
299//---------------------------------------------------------------------------
300// wxJoystick::GetNumberJoysticks
301//
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
304// identifiers.
305//---------------------------------------------------------------------------
306int wxJoystick::GetNumberJoysticks()
307{
308 return
309 wxHIDDevice::GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick) +
310 wxHIDDevice::GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad);
311}
312
313//---------------------------------------------------------------------------
314// wxJoystick::SetCapture
315//
316// Stops sending events from the thread to the window set in
317// SetCapture and stops polling the joystick
318//---------------------------------------------------------------------------
319bool wxJoystick::SetCapture(wxWindow* win, int pollingFreq)
320{
321 if (m_thread)
322 {
323 m_thread->m_catchwin = win;
324 m_thread->m_polling = pollingFreq;
325 return true;
326 }
327 return false;
328}
329
330//---------------------------------------------------------------------------
331// wxJoystick::ReleaseCapture
332//
333// Stops sending events from the thread to the window set in
334// SetCapture and stops polling the joystick
335//---------------------------------------------------------------------------
336bool wxJoystick::ReleaseCapture()
337{
338 if (m_thread)
339 {
340 m_thread->m_catchwin = NULL;
341 m_thread->m_polling = 0;
342 return true;
343 }
344 return false;
345}
346
347//---------------------------------------------------------------------------
348// wxJoystick::Get[XXX]
349//
350// Gets the minimum and maximum values for each axis, returning 0 if the
351// axis doesn't exist.
352//---------------------------------------------------------------------------
353int wxJoystick::GetXMin() const
354{
355 return m_hid->m_nXMin;
356}
357
358int wxJoystick::GetYMin() const
359{
360 return m_hid->m_nYMin;
361}
362
363int wxJoystick::GetZMin() const
364{
365 return m_hid->m_nZMin;
366}
367
368int wxJoystick::GetRudderMin() const
369{
370 return m_hid->m_nRudderMin;
371}
372
373int wxJoystick::GetUMin() const
374{
375 return m_hid->m_nUMin;
376}
377
378int wxJoystick::GetVMin() const
379{
380 return m_hid->m_nVMin;
381}
382
383int wxJoystick::GetXMax() const
384{
385 return m_hid->m_nXMax;
386}
387
388int wxJoystick::GetYMax() const
389{
390 return m_hid->m_nYMax;
391}
392
393int wxJoystick::GetZMax() const
394{
395 return m_hid->m_nZMax;
396}
397
398int wxJoystick::GetRudderMax() const
399{
400 return m_hid->m_nRudderMax;
401}
402
403int wxJoystick::GetUMax() const
404{
405 return m_hid->m_nUMax;
406}
407
408int wxJoystick::GetVMax() const
409{
410 return m_hid->m_nVMax;
411}
412
413//---------------------------------------------------------------------------
414// wxJoystick::Get[XXX]
415//
416// Min/Max values for buttons, axes, etc.. Polling in this case is just
417// what the linux port has.
418//---------------------------------------------------------------------------
419int wxJoystick::GetMaxButtons() const
420{
421 return wxJS_MAX_BUTTONS;
422}
423
424int wxJoystick::GetMaxAxes() const
425{
426 return wxJS_MAX_AXES;
427}
428
429int wxJoystick::GetPollingMin() const
430{
431 return 10;
432}
433
434int wxJoystick::GetPollingMax() const
435{
436 return 1000;
437}
438
439//---------------------------------------------------------------------------
440// wxJoystick::Has[XXX]
441//
442// Just queries the native hid implementation if the cookie was found
443// when enumerating the cookies of the joystick device
444//---------------------------------------------------------------------------
445bool wxJoystick::HasZ() const
446{
447 return m_hid->HasElement(wxJS_AXIS_Z);
448}
449
450bool wxJoystick::HasRudder() const
451{
452 return m_hid->HasElement(wxJS_AXIS_RUDDER);
453}
454
455bool wxJoystick::HasU() const
456{
457 return m_hid->HasElement(wxJS_AXIS_U);
458}
459
460bool wxJoystick::HasV() const
461{
462 return m_hid->HasElement(wxJS_AXIS_V);
463}
464
465//---------------------------------------------------------------------------
466// UNSUPPORTED
467//---------------------------------------------------------------------------
468int wxJoystick::GetPOVPosition() const
469{
470 return -1;
471}
472
473int wxJoystick::GetPOVCTSPosition() const
474{
475 return -1;
476}
477
478int wxJoystick::GetMovementThreshold() const
479{
480 return 0;
481}
482
483void wxJoystick::SetMovementThreshold(int threshold)
484{
485}
486
487bool wxJoystick::HasPOV() const
488{
489 return false;
490}
491
492bool wxJoystick::HasPOV4Dir() const
493{
494 return false;
495}
496
497bool wxJoystick::HasPOVCTS() const
498{
499 return false;
500}
501
502//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
503//
504// wxHIDJoystick
505//
506//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
507
508//---------------------------------------------------------------------------
509// wxHIDJoystick ctor
510//
511// Initializes the min/max members
512//---------------------------------------------------------------------------
513wxHIDJoystick::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)
516{
517}
518
519//---------------------------------------------------------------------------
520// wxHIDJoystick dtor
521//
522// Nothing...
523//---------------------------------------------------------------------------
524wxHIDJoystick::~wxHIDJoystick()
525{
526}
527
528//---------------------------------------------------------------------------
529// wxHIDJoystick::Create
530//
531// Creates the native HID device (joysticks are of either
532// kHIDUsage_GD_Joystick or kHIDUsage_GD_GamePad)
533//---------------------------------------------------------------------------
534bool wxHIDJoystick::Create(int nWhich)
535{
536 int nJoysticks = GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick);
537
538 if (nWhich <= nJoysticks)
539 return wxHIDDevice::Create(kHIDPage_GenericDesktop,
540 kHIDUsage_GD_Joystick,
541 nWhich);
542 else
543 nWhich -= nJoysticks;
544
545 int nGamePads = GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad);
546
547 if (nWhich <= nGamePads)
548 return wxHIDDevice::Create(kHIDPage_GenericDesktop,
549 kHIDUsage_GD_GamePad,
550 nWhich);
551 else
552 return false;
553}
554
555//---------------------------------------------------------------------------
556// wxHIDJoystick::BuildCookies
557// wxHIDJoystick::MakeCookies
558//
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.
561//
562// MakeCookies is just a recursive function for each array within
563// BuildCookies.
564//---------------------------------------------------------------------------
565void wxHIDJoystick::BuildCookies(CFArrayRef Array)
566{
567 InitCookies(50, true);
568
569 //
570 // I wasted two hours of my life on this line :(
571 // accidently removed it during some source cleaning...
572 //
573 MakeCookies(Array);
574
575 //paranoid debugging stuff
576#if 0
577 for(int i = 0; i < 50; ++i)
578 wxPrintf(wxT("\nVAL #%i:[%i]"), i, m_pCookies[i]);
579#endif
580}//end buildcookies
581
582void wxHIDJoystick::MakeCookies(CFArrayRef Array)
583{
584 int i, nUsage, nPage;
585
586 for (i = 0; i < CFArrayGetCount(Array); ++i)
587 {
588 const void* ref = CFDictionaryGetValue(
589 (CFDictionaryRef)CFArrayGetValueAtIndex(Array, i),
590 CFSTR(kIOHIDElementKey)
591 );
592
593 if (ref != NULL)
594 {
595 MakeCookies((CFArrayRef) ref);
596 }
597 else
598 {
599 CFNumberGetValue(
600 (CFNumberRef)
601 CFDictionaryGetValue(
602 (CFDictionaryRef) CFArrayGetValueAtIndex(Array, i),
603 CFSTR(kIOHIDElementUsageKey)
604 ),
605 kCFNumberIntType,
606 &nUsage );
607
608 CFNumberGetValue(
609 (CFNumberRef)
610 CFDictionaryGetValue(
611 (CFDictionaryRef) CFArrayGetValueAtIndex(Array, i),
612 CFSTR(kIOHIDElementUsagePageKey)
613 ),
614 kCFNumberIntType,
615 &nPage );
616
617#if 0
618 wxLogSysError(wxT("[%i][%i]"), nUsage, nPage);
619#endif
620 if (nPage == kHIDPage_Button && nUsage <= 40)
621 AddCookieInQueue(CFArrayGetValueAtIndex(Array, i), nUsage-1 );
622 else if (nPage == kHIDPage_GenericDesktop)
623 {
624 //axis...
625 switch(nUsage)
626 {
627 case kHIDUsage_GD_X:
628 AddCookieInQueue(CFArrayGetValueAtIndex(Array, i), wxJS_AXIS_X);
629 wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i),
630 CFSTR(kIOHIDElementMaxKey),
631 &m_nXMax);
632 wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i),
633 CFSTR(kIOHIDElementMinKey),
634 &m_nXMin);
635 break;
636 case kHIDUsage_GD_Y:
637 AddCookieInQueue(CFArrayGetValueAtIndex(Array, i), wxJS_AXIS_Y);
638 wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i),
639 CFSTR(kIOHIDElementMaxKey),
640 &m_nYMax);
641 wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i),
642 CFSTR(kIOHIDElementMinKey),
643 &m_nYMin);
644 break;
645 case kHIDUsage_GD_Z:
646 AddCookieInQueue(CFArrayGetValueAtIndex(Array, i), wxJS_AXIS_Z);
647 wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i),
648 CFSTR(kIOHIDElementMaxKey),
649 &m_nZMax);
650 wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i),
651 CFSTR(kIOHIDElementMinKey),
652 &m_nZMin);
653 break;
654 default:
655 break;
656 }
657 }
658 else if (nPage == kHIDPage_Simulation && nUsage == kHIDUsage_Sim_Rudder)
659 {
660 //rudder...
661 AddCookieInQueue(CFArrayGetValueAtIndex(Array, i), wxJS_AXIS_RUDDER );
662 wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i),
663 CFSTR(kIOHIDElementMaxKey),
664 &m_nRudderMax);
665 wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i),
666 CFSTR(kIOHIDElementMinKey),
667 &m_nRudderMin);
668 }
669 }
670 }
671}
672
673//---------------------------------------------------------------------------
674// wxHIDJoystick::Get[XXX]
675//
676// Simple accessors so that the HID callback and the thread procedure
677// can access members from wxHIDDevice (our parent here).
678//---------------------------------------------------------------------------
679IOHIDElementCookie* wxHIDJoystick::GetCookies()
680{ return m_pCookies; }
681IOHIDQueueInterface** wxHIDJoystick::GetQueue()
682{ return m_ppQueue; }
683
684//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
685//
686// wxJoystickThread
687//
688//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
689
690//---------------------------------------------------------------------------
691// wxJoystickThread Constructor
692//
693// Just initializes members
694//---------------------------------------------------------------------------
695wxJoystickThread::wxJoystickThread(wxHIDJoystick* hid, int joystick)
696 : m_hid(hid),
697 m_joystick(joystick),
698 m_lastposition(127,127),
699 m_buttons(0),
700 m_catchwin(NULL),
701 m_polling(0)
702{
703 memset(m_axe, 0, sizeof(int) * wxJS_MAX_AXES);
704}
705
706//---------------------------------------------------------------------------
707// wxJoystickThread::Entry
708//
709// Thread procedure
710//
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//---------------------------------------------------------------------------
717void* wxJoystickThread::Entry()
718{
719 CFRunLoopSourceRef pRLSource = NULL;
720
721 if ((*m_hid->GetQueue())->createAsyncEventSource(
722 m_hid->GetQueue(), &pRLSource) != kIOReturnSuccess )
723 {
724 wxLogSysError(wxT("Couldn't create async event source"));
725 return NULL;
726 }
727
728 wxASSERT(pRLSource != NULL);
729
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) );
734
735
736 if( (*m_hid->GetQueue())->setEventCallout(m_hid->GetQueue(),
737 wxJoystickThread::HIDCallback, this, this) != kIOReturnSuccess )
738 {
739 wxLogSysError(wxT("Could not set event callout for queue"));
740 return NULL;
741 }
742
743 if( (*m_hid->GetQueue())->start(m_hid->GetQueue()) != kIOReturnSuccess )
744 {
745 wxLogSysError(wxT("Could not start queue"));
746 return NULL;
747 }
748
749 double dTime;
750
751 while(true)
752 {
753 if (TestDestroy())
754 break;
755
756 if (m_polling)
757 dTime = 0.0001 * m_polling;
758 else
759 dTime = 0.0001 * 10; // check at least every 10 msec in "blocking" case
760
761 //true just "handles and returns" - false forces it to stay the time
762 //amount
763#if 1
764 CFRunLoopRunInMode(kCFRunLoopDefaultMode, dTime, true);
765#else
766 IOReturn ret = NULL;
767 HIDCallback(this, ret, this, this);
768 Sleep(3000);
769#endif
770 }
771
772 wxASSERT( CFRunLoopContainsSource(pRL, pRLSource, kCFRunLoopDefaultMode) );
773
774 CFRunLoopRemoveSource(pRL, pRLSource, kCFRunLoopDefaultMode);
775 CFRelease(pRLSource);
776
777 return NULL;
778}
779
780//---------------------------------------------------------------------------
781// wxJoystickThread::HIDCallback (static)
782//
783// Callback for the native HID device when it recieves input.
784//
785// This is where the REAL dirty work gets done.
786//
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* target, IOReturn res,
799 void* context, void* 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->AddPendingEvent(wxevent);
897
898 ret = (*m_hid->GetQueue())->getNextEvent(m_hid->GetQueue(),
899 &hidevent, bogustime, 0);
900 }
901}
902
903#endif // wxUSE_JOYSTICK && defined(__DARWIN__)