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