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