]> git.saurik.com Git - wxWidgets.git/blame - src/mac/corefoundation/hidjoystick.cpp
Applied patch [ 1776951 ] wxSizer::GetContainingWindow fails for nested sizers
[wxWidgets.git] / src / mac / corefoundation / hidjoystick.cpp
CommitLineData
4cb1d3da 1/////////////////////////////////////////////////////////////////////////////
e4db172a 2// Name: src/mac/corefoundation/joystick.cpp
4cb1d3da
RN
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
e4db172a 9// Licence: wxWindows licence
4cb1d3da
RN
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 27//we only support HID on OSX (DARWIN), since it requires DARWIN...
4afa6df3 28#if wxUSE_JOYSTICK && defined(__DARWIN__) && wxUSE_THREADS
4cb1d3da 29
ce0d1032
SC
30//---------------------------------------------------------------------------
31// Includes
32//---------------------------------------------------------------------------
e4db172a
WS
33
34#ifndef WX_PRECOMP
35 #include "wx/log.h"
d5da0ce7 36 #include "wx/event.h" //joystick wxEvents
cdccdfab 37 #include "wx/window.h" //for wxWindow to "capture" joystick
e4db172a
WS
38#endif
39
ce0d1032
SC
40#include "wx/joystick.h" //...
41#include "wx/thread.h" //wxThread for polling thread/ wxCriticalSection
4cb1d3da 42
ce0d1032
SC
43//private headers
44#include "wx/mac/corefoundation/hid.h" //private mac hid stuff
4cb1d3da 45
ce0d1032 46//mac headers
4cb1d3da
RN
47#include <CoreServices/CoreServices.h>
48#include <mach/mach.h>
49#include <mach/mach_time.h>
50#include <unistd.h>
51
ce0d1032
SC
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
e4db172a 59enum
ce0d1032
SC
60{
61 //These are positions within the cookie array
62 //in wxHIDJoystick that the cookies that store the axis' are
65442ab6 63 wxJS_AXIS_X = 40,
4cb1d3da
RN
64 wxJS_AXIS_Y,
65 wxJS_AXIS_Z,
66 wxJS_AXIS_RUDDER,
67 wxJS_AXIS_U,
68 wxJS_AXIS_V,
4cb1d3da
RN
69};
70
ce0d1032
SC
71//---------------------------------------------------------------------------
72// wxHIDJoystick
73//---------------------------------------------------------------------------
4cb1d3da
RN
74class wxHIDJoystick : public wxHIDDevice
75{
76public:
175ec4c8 77 wxHIDJoystick();
d3c7fc99 78 virtual ~wxHIDJoystick();
e4db172a
WS
79
80 bool Create(int nWhich);
81 virtual void BuildCookies(CFArrayRef Array);
82 void MakeCookies(CFArrayRef Array);
ce0d1032
SC
83 IOHIDElementCookie* GetCookies();
84 IOHIDQueueInterface** GetQueue();
e4db172a 85
175ec4c8
JS
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
65442ab6 89 friend class wxJoystick;
4cb1d3da
RN
90};
91
ce0d1032
SC
92//---------------------------------------------------------------------------
93// wxJoystickThread
94//---------------------------------------------------------------------------
4cb1d3da
RN
95class wxJoystickThread : public wxThread
96{
97public:
98 wxJoystickThread(wxHIDJoystick* hid, int joystick);
99 void* Entry();
ce0d1032 100 static void HIDCallback(void* target, IOReturn res, void* context, void* sender);
e4db172a 101
4cb1d3da
RN
102private:
103 wxHIDJoystick* m_hid;
104 int m_joystick;
105 wxPoint m_lastposition;
ce0d1032 106 int m_axe[wxJS_MAX_AXES];
4cb1d3da
RN
107 int m_buttons;
108 wxWindow* m_catchwin;
109 int m_polling;
110
111 friend class wxJoystick;
112};
113
ce0d1032
SC
114//===========================================================================
115// IMPLEMENTATION
116//===========================================================================
4cb1d3da 117
175ec4c8
JS
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(
e4db172a
WS
126 (CFNumberRef) CFDictionaryGetValue((CFDictionaryRef) cfDict,
127 key),
128 kCFNumberIntType, pOut);
175ec4c8
JS
129}
130
ce0d1032
SC
131//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
132//
133// wxJoystick
134//
135//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4cb1d3da 136
ce0d1032 137IMPLEMENT_DYNAMIC_CLASS(wxJoystick, wxObject)
4cb1d3da 138
ce0d1032
SC
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//---------------------------------------------------------------------------
4cb1d3da
RN
146wxJoystick::wxJoystick(int joystick)
147 : m_joystick(joystick),
148 m_thread(NULL)
149{
150 m_hid = new wxHIDJoystick();
151
32efab35 152 if (m_hid->Create(m_joystick+1)) //wxHIDDevice is 1-based while this is 0
4cb1d3da
RN
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
ce0d1032
SC
165//---------------------------------------------------------------------------
166// wxJoystick Destructor
167//
e4db172a 168// Releases the capture of the thread, deletes it, and deletes
ce0d1032
SC
169// the native implementation.
170//---------------------------------------------------------------------------
4cb1d3da
RN
171wxJoystick::~wxJoystick()
172{
173 ReleaseCapture();
174 if (m_thread)
175 m_thread->Delete(); // It's detached so it will delete itself
e4db172a 176
4cb1d3da
RN
177 if (m_hid)
178 delete m_hid;
179}
180
ce0d1032
SC
181//---------------------------------------------------------------------------
182// wxJoystick::Get[XXX]Position
183//
184// Returns the value of an axis that was polled from the thread. In the
e4db172a 185// case of GetPosition returns the X and Y values in a wxPoint
ce0d1032 186//---------------------------------------------------------------------------
4cb1d3da
RN
187wxPoint wxJoystick::GetPosition() const
188{
189 wxPoint pos(wxDefaultPosition);
190 if (m_thread) pos = m_thread->m_lastposition;
191 return pos;
192}
4cb1d3da
RN
193int wxJoystick::GetZPosition() const
194{
195 if (m_thread)
196 return m_thread->m_axe[wxJS_AXIS_Z];
197 return 0;
198}
4cb1d3da 199int wxJoystick::GetRudderPosition() const
e4db172a 200{
4cb1d3da
RN
201 if (m_thread)
202 return m_thread->m_axe[wxJS_AXIS_RUDDER];
203 return 0;
204}
4cb1d3da
RN
205int wxJoystick::GetUPosition() const
206{
207 if (m_thread)
208 return m_thread->m_axe[wxJS_AXIS_U];
209 return 0;
210}
4cb1d3da
RN
211int wxJoystick::GetVPosition() const
212{
213 if (m_thread)
214 return m_thread->m_axe[wxJS_AXIS_V];
215 return 0;
216}
217
ce0d1032
SC
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}
4cb1d3da 230
ce0d1032
SC
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//---------------------------------------------------------------------------
4cb1d3da 237bool wxJoystick::IsOk() const
e4db172a
WS
238{
239 return m_hid != NULL;
ce0d1032 240}
e4db172a 241
ce0d1032
SC
242//---------------------------------------------------------------------------
243// wxJoystick::Get[XXX](Id/Name)
244//
245// Simple accessors to the native HID implementation
246//---------------------------------------------------------------------------
4cb1d3da 247int wxJoystick::GetManufacturerId() const
e4db172a
WS
248{
249 return m_hid->m_nManufacturerId;
250}
251
4cb1d3da 252int wxJoystick::GetProductId() const
e4db172a
WS
253{
254 return m_hid->m_nProductId;
255}
256
4cb1d3da 257wxString wxJoystick::GetProductName() const
e4db172a
WS
258{
259 return m_hid->m_szProductName;
260}
4cb1d3da 261
ce0d1032
SC
262//---------------------------------------------------------------------------
263// wxJoystick::GetNumberButtons
264// wxJoystick::GetNumberAxes
265//
e4db172a 266// Queries the joystick for an active number of buttons/axes.
ce0d1032
SC
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//---------------------------------------------------------------------------
4cb1d3da
RN
274int wxJoystick::GetNumberButtons() const
275{
276 int nCount = 0;
e4db172a 277
4cb1d3da
RN
278 for(int nIndex = 0; nIndex < 40; ++nIndex)
279 {
280 if(m_hid->HasElement(nIndex))
281 ++nCount;
282 }
e4db172a 283
4cb1d3da
RN
284 return nCount;
285}
4cb1d3da
RN
286int wxJoystick::GetNumberAxes() const
287{
288 int nCount = 0;
e4db172a 289
4cb1d3da
RN
290 for(int nIndex = 40; nIndex < 50; ++nIndex)
291 {
292 if(m_hid->HasElement(nIndex))
293 ++nCount;
294 }
e4db172a 295
4cb1d3da
RN
296 return nCount;
297}
298
ce0d1032
SC
299//---------------------------------------------------------------------------
300// wxJoystick::GetNumberJoysticks
4cb1d3da 301//
ce0d1032
SC
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//---------------------------------------------------------------------------
da9e9563 306int wxJoystick::GetNumberJoysticks()
e4db172a
WS
307{
308 return
ce0d1032 309 wxHIDDevice::GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick) +
e4db172a 310 wxHIDDevice::GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad);
ce0d1032 311}
4cb1d3da 312
ce0d1032
SC
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}
4cb1d3da 329
ce0d1032
SC
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}
4cb1d3da 346
ce0d1032
SC
347//---------------------------------------------------------------------------
348// wxJoystick::Get[XXX]
349//
175ec4c8
JS
350// Gets the minimum and maximum values for each axis, returning 0 if the
351// axis doesn't exist.
ce0d1032
SC
352//---------------------------------------------------------------------------
353int wxJoystick::GetXMin() const
e4db172a
WS
354{
355 return m_hid->m_nXMin;
356}
357
ce0d1032 358int wxJoystick::GetYMin() const
e4db172a
WS
359{
360 return m_hid->m_nYMin;
361}
362
ce0d1032 363int wxJoystick::GetZMin() const
e4db172a
WS
364{
365 return m_hid->m_nZMin;
366}
367
175ec4c8 368int wxJoystick::GetRudderMin() const
e4db172a
WS
369{
370 return m_hid->m_nRudderMin;
371}
372
4cb1d3da 373int wxJoystick::GetUMin() const
e4db172a
WS
374{
375 return m_hid->m_nUMin;
376}
377
4cb1d3da 378int wxJoystick::GetVMin() const
e4db172a
WS
379{
380 return m_hid->m_nVMin;
381}
4cb1d3da 382
ce0d1032 383int wxJoystick::GetXMax() const
e4db172a
WS
384{
385 return m_hid->m_nXMax;
386}
387
ce0d1032 388int wxJoystick::GetYMax() const
e4db172a
WS
389{
390 return m_hid->m_nYMax;
391}
392
ce0d1032 393int wxJoystick::GetZMax() const
e4db172a
WS
394{
395 return m_hid->m_nZMax;
396}
397
175ec4c8 398int wxJoystick::GetRudderMax() const
e4db172a
WS
399{
400 return m_hid->m_nRudderMax;
401}
402
ce0d1032 403int wxJoystick::GetUMax() const
e4db172a
WS
404{
405 return m_hid->m_nUMax;
406}
407
4cb1d3da 408int wxJoystick::GetVMax() const
e4db172a
WS
409{
410 return m_hid->m_nVMax;
411}
ce0d1032
SC
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
e4db172a
WS
420{
421 return wxJS_MAX_BUTTONS;
422}
423
ce0d1032 424int wxJoystick::GetMaxAxes() const
e4db172a
WS
425{
426 return wxJS_MAX_AXES;
427}
428
ce0d1032 429int wxJoystick::GetPollingMin() const
e4db172a
WS
430{
431 return 10;
432}
433
ce0d1032 434int wxJoystick::GetPollingMax() const
e4db172a
WS
435{
436 return 1000;
437}
4cb1d3da 438
ce0d1032
SC
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//---------------------------------------------------------------------------
4cb1d3da 445bool wxJoystick::HasZ() const
e4db172a
WS
446{
447 return m_hid->HasElement(wxJS_AXIS_Z);
448}
449
175ec4c8 450bool wxJoystick::HasRudder() const
e4db172a
WS
451{
452 return m_hid->HasElement(wxJS_AXIS_RUDDER);
453}
454
4cb1d3da 455bool wxJoystick::HasU() const
e4db172a
WS
456{
457 return m_hid->HasElement(wxJS_AXIS_U);
458}
459
4cb1d3da 460bool wxJoystick::HasV() const
e4db172a
WS
461{
462 return m_hid->HasElement(wxJS_AXIS_V);
463}
4cb1d3da 464
ce0d1032
SC
465//---------------------------------------------------------------------------
466// UNSUPPORTED
467//---------------------------------------------------------------------------
468int wxJoystick::GetPOVPosition() const
e4db172a
WS
469{
470 return -1;
471}
472
ce0d1032 473int wxJoystick::GetPOVCTSPosition() const
e4db172a
WS
474{
475 return -1;
476}
477
ce0d1032 478int wxJoystick::GetMovementThreshold() const
e4db172a
WS
479{
480 return 0;
481}
482
ce0d1032 483void wxJoystick::SetMovementThreshold(int threshold)
e4db172a
WS
484{
485}
486
4cb1d3da 487bool wxJoystick::HasPOV() const
e4db172a
WS
488{
489 return false;
490}
491
4cb1d3da 492bool wxJoystick::HasPOV4Dir() const
e4db172a
WS
493{
494 return false;
495}
496
4cb1d3da 497bool wxJoystick::HasPOVCTS() const
e4db172a
WS
498{
499 return false;
500}
4cb1d3da 501
ce0d1032
SC
502//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
503//
504// wxHIDJoystick
505//
506//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4cb1d3da 507
175ec4c8
JS
508//---------------------------------------------------------------------------
509// wxHIDJoystick ctor
e4db172a 510//
175ec4c8
JS
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
ce0d1032
SC
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)
4cb1d3da 535{
ce0d1032 536 int nJoysticks = GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick);
e4db172a 537
ce0d1032 538 if (nWhich <= nJoysticks)
e4db172a
WS
539 return wxHIDDevice::Create(kHIDPage_GenericDesktop,
540 kHIDUsage_GD_Joystick,
32efab35 541 nWhich);
ce0d1032
SC
542 else
543 nWhich -= nJoysticks;
e4db172a 544
ce0d1032 545 int nGamePads = GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad);
e4db172a 546
ce0d1032 547 if (nWhich <= nGamePads)
e4db172a
WS
548 return wxHIDDevice::Create(kHIDPage_GenericDesktop,
549 kHIDUsage_GD_GamePad,
32efab35 550 nWhich);
ce0d1032 551 else
4cb1d3da
RN
552 return false;
553}
554
ce0d1032
SC
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//
e4db172a 562// MakeCookies is just a recursive function for each array within
ce0d1032
SC
563// BuildCookies.
564//---------------------------------------------------------------------------
32efab35 565void wxHIDJoystick::BuildCookies(CFArrayRef Array)
4cb1d3da 566{
e4db172a 567 InitCookies(50, true);
ce0d1032 568
ce0d1032
SC
569 //
570 // I wasted two hours of my life on this line :(
571 // accidently removed it during some source cleaning...
572 //
573 MakeCookies(Array);
e4db172a
WS
574
575 //paranoid debugging stuff
ce0d1032
SC
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
32efab35 582void wxHIDJoystick::MakeCookies(CFArrayRef Array)
ce0d1032 583{
e4db172a 584 int i, nUsage, nPage;
ce0d1032 585
e4db172a 586 for (i = 0; i < CFArrayGetCount(Array); ++i)
4cb1d3da 587 {
32efab35 588 const void* ref = CFDictionaryGetValue(
e4db172a 589 (CFDictionaryRef)CFArrayGetValueAtIndex(Array, i),
32efab35
SC
590 CFSTR(kIOHIDElementKey)
591 );
ce0d1032
SC
592
593 if (ref != NULL)
594 {
32efab35 595 MakeCookies((CFArrayRef) ref);
4cb1d3da 596 }
ce0d1032
SC
597 else
598 {
599 CFNumberGetValue(
e4db172a
WS
600 (CFNumberRef)
601 CFDictionaryGetValue(
602 (CFDictionaryRef) CFArrayGetValueAtIndex(Array, i),
603 CFSTR(kIOHIDElementUsageKey)
604 ),
605 kCFNumberIntType,
606 &nUsage );
607
ce0d1032 608 CFNumberGetValue(
e4db172a
WS
609 (CFNumberRef)
610 CFDictionaryGetValue(
611 (CFDictionaryRef) CFArrayGetValueAtIndex(Array, i),
612 CFSTR(kIOHIDElementUsagePageKey)
613 ),
614 kCFNumberIntType,
615 &nPage );
ce0d1032
SC
616
617#if 0
618 wxLogSysError(wxT("[%i][%i]"), nUsage, nPage);
619#endif
620 if (nPage == kHIDPage_Button && nUsage <= 40)
32efab35 621 AddCookieInQueue(CFArrayGetValueAtIndex(Array, i), nUsage-1 );
ce0d1032
SC
622 else if (nPage == kHIDPage_GenericDesktop)
623 {
175ec4c8 624 //axis...
ce0d1032
SC
625 switch(nUsage)
626 {
627 case kHIDUsage_GD_X:
32efab35 628 AddCookieInQueue(CFArrayGetValueAtIndex(Array, i), wxJS_AXIS_X);
e4db172a 629 wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i),
32efab35 630 CFSTR(kIOHIDElementMaxKey),
175ec4c8 631 &m_nXMax);
e4db172a 632 wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i),
32efab35 633 CFSTR(kIOHIDElementMinKey),
175ec4c8 634 &m_nXMin);
e4db172a 635 break;
ce0d1032 636 case kHIDUsage_GD_Y:
32efab35 637 AddCookieInQueue(CFArrayGetValueAtIndex(Array, i), wxJS_AXIS_Y);
e4db172a 638 wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i),
32efab35 639 CFSTR(kIOHIDElementMaxKey),
175ec4c8 640 &m_nYMax);
e4db172a 641 wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i),
32efab35 642 CFSTR(kIOHIDElementMinKey),
175ec4c8 643 &m_nYMin);
ce0d1032
SC
644 break;
645 case kHIDUsage_GD_Z:
32efab35 646 AddCookieInQueue(CFArrayGetValueAtIndex(Array, i), wxJS_AXIS_Z);
e4db172a 647 wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i),
32efab35 648 CFSTR(kIOHIDElementMaxKey),
175ec4c8 649 &m_nZMax);
e4db172a 650 wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i),
32efab35 651 CFSTR(kIOHIDElementMinKey),
175ec4c8 652 &m_nZMin);
ce0d1032
SC
653 break;
654 default:
655 break;
656 }
657 }
658 else if (nPage == kHIDPage_Simulation && nUsage == kHIDUsage_Sim_Rudder)
175ec4c8
JS
659 {
660 //rudder...
32efab35 661 AddCookieInQueue(CFArrayGetValueAtIndex(Array, i), wxJS_AXIS_RUDDER );
e4db172a 662 wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i),
32efab35 663 CFSTR(kIOHIDElementMaxKey),
175ec4c8 664 &m_nRudderMax);
e4db172a 665 wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i),
32efab35 666 CFSTR(kIOHIDElementMinKey),
175ec4c8
JS
667 &m_nRudderMin);
668 }
ce0d1032 669 }
e4db172a 670 }
4cb1d3da 671}
ce0d1032
SC
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//---------------------------------------------------------------------------
e4db172a 679IOHIDElementCookie* wxHIDJoystick::GetCookies()
ce0d1032 680{ return m_pCookies; }
e4db172a 681IOHIDQueueInterface** wxHIDJoystick::GetQueue()
ce0d1032
SC
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 }
e4db172a 727
ce0d1032
SC
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) );
ce0d1032 734
e4db172a
WS
735
736 if( (*m_hid->GetQueue())->setEventCallout(m_hid->GetQueue(),
ce0d1032
SC
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;
e4db172a 750
ce0d1032
SC
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
e4db172a 764 CFRunLoopRunInMode(kCFRunLoopDefaultMode, dTime, true);
ce0d1032
SC
765#else
766 IOReturn ret = NULL;
767 HIDCallback(this, ret, this, this);
768 Sleep(3000);
4cb1d3da 769#endif
ce0d1032 770 }
e4db172a 771
ce0d1032 772 wxASSERT( CFRunLoopContainsSource(pRL, pRLSource, kCFRunLoopDefaultMode) );
e4db172a 773
ce0d1032
SC
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
e4db172a 788// 2) First, checks if the thread that is running the loop for
ce0d1032
SC
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//---------------------------------------------------------------------------
e4db172a 798/*static*/ void wxJoystickThread::HIDCallback(void* target, IOReturn res,
ce0d1032
SC
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;
e4db172a 806
ce0d1032
SC
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
e4db172a 810 ret = (*m_hid->GetQueue())->getNextEvent(m_hid->GetQueue(),
ce0d1032 811 &hidevent, bogustime, 0);
e4db172a 812
ce0d1032
SC
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;
e4db172a
WS
822 }
823
ce0d1032 824 wxJoystickEvent wxevent;
e4db172a 825
ce0d1032
SC
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;
e4db172a 833
ce0d1032 834 ++nIndex;
e4db172a
WS
835 }
836
ce0d1032
SC
837 //debugging stuff
838#if 0
e4db172a 839 if(nIndex == 50)
ce0d1032
SC
840 {
841 wxLogSysError(wxString::Format(wxT("wxJoystick Out Of Bounds Error")));
842 break;
e4db172a 843 }
4cb1d3da 844#endif
ce0d1032 845
e4db172a 846 //is the cookie a button?
ce0d1032
SC
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
e4db172a 880 wxevent.SetEventType(wxEVT_JOY_MOVE);
ce0d1032
SC
881
882 Nanoseconds timestamp = AbsoluteToNanoseconds(hidevent.timestamp);
e4db172a 883
ce0d1032 884 wxULongLong llTime(timestamp.hi, timestamp.lo);
e4db172a 885
ce0d1032 886 llTime /= 1000000;
e4db172a 887
ce0d1032
SC
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)
e4db172a 896 pThis->m_catchwin->AddPendingEvent(wxevent);
ce0d1032 897
e4db172a 898 ret = (*m_hid->GetQueue())->getNextEvent(m_hid->GetQueue(),
ce0d1032
SC
899 &hidevent, bogustime, 0);
900 }
901}
902
903#endif // wxUSE_JOYSTICK && defined(__DARWIN__)