]>
Commit | Line | Data |
---|---|---|
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 | ||
55 | enum | |
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 |
70 | class wxHIDJoystick : public wxHIDDevice |
71 | { | |
72 | public: | |
175ec4c8 JS |
73 | wxHIDJoystick(); |
74 | ~wxHIDJoystick(); | |
75 | ||
4cb1d3da RN |
76 | bool Create(int nWhich); |
77 | virtual void BuildCookies(wxCFArray& Array); | |
65442ab6 | 78 | void MakeCookies(wxCFArray& 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 |
91 | class wxJoystickThread : public wxThread |
92 | { | |
93 | public: | |
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 |
98 | private: |
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 | //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
119 | void 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 | 133 | IMPLEMENT_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 |
142 | wxJoystick::wxJoystick(int joystick) |
143 | : m_joystick(joystick), | |
144 | m_thread(NULL) | |
145 | { | |
146 | m_hid = new wxHIDJoystick(); | |
147 | ||
148 | if (m_hid->Create(m_joystick)) | |
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 |
167 | wxJoystick::~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 |
183 | wxPoint wxJoystick::GetPosition() const |
184 | { | |
185 | wxPoint pos(wxDefaultPosition); | |
186 | if (m_thread) pos = m_thread->m_lastposition; | |
187 | return pos; | |
188 | } | |
4cb1d3da RN |
189 | int wxJoystick::GetZPosition() const |
190 | { | |
191 | if (m_thread) | |
192 | return m_thread->m_axe[wxJS_AXIS_Z]; | |
193 | return 0; | |
194 | } | |
4cb1d3da RN |
195 | int wxJoystick::GetRudderPosition() const |
196 | { | |
197 | if (m_thread) | |
198 | return m_thread->m_axe[wxJS_AXIS_RUDDER]; | |
199 | return 0; | |
200 | } | |
4cb1d3da RN |
201 | int wxJoystick::GetUPosition() const |
202 | { | |
203 | if (m_thread) | |
204 | return m_thread->m_axe[wxJS_AXIS_U]; | |
205 | return 0; | |
206 | } | |
4cb1d3da RN |
207 | int 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 | //--------------------------------------------------------------------------- | |
220 | int 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 | 233 | bool 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 | 243 | int wxJoystick::GetManufacturerId() const |
65442ab6 | 244 | { return m_hid->m_nManufacturerId; } |
4cb1d3da | 245 | int wxJoystick::GetProductId() const |
65442ab6 | 246 | { return m_hid->m_nProductId; } |
4cb1d3da | 247 | wxString 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 |
262 | int 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 |
274 | int 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 | 294 | int 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 | //--------------------------------------------------------------------------- | |
307 | bool 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 | //--------------------------------------------------------------------------- | |
324 | bool 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 | //--------------------------------------------------------------------------- |
341 | int wxJoystick::GetXMin() const | |
175ec4c8 | 342 | { return m_hid->m_nXMin; } |
ce0d1032 | 343 | int wxJoystick::GetYMin() const |
175ec4c8 | 344 | { return m_hid->m_nYMin; } |
ce0d1032 | 345 | int wxJoystick::GetZMin() const |
175ec4c8 JS |
346 | { return m_hid->m_nZMin; } |
347 | int wxJoystick::GetRudderMin() const | |
348 | { return m_hid->m_nRudderMin; } | |
4cb1d3da | 349 | int wxJoystick::GetUMin() const |
175ec4c8 | 350 | { return m_hid->m_nUMin; } |
4cb1d3da | 351 | int wxJoystick::GetVMin() const |
175ec4c8 | 352 | { return m_hid->m_nVMin; } |
4cb1d3da | 353 | |
ce0d1032 | 354 | int wxJoystick::GetXMax() const |
175ec4c8 | 355 | { return m_hid->m_nXMax; } |
ce0d1032 | 356 | int wxJoystick::GetYMax() const |
175ec4c8 | 357 | { return m_hid->m_nYMax; } |
ce0d1032 | 358 | int wxJoystick::GetZMax() const |
175ec4c8 JS |
359 | { return m_hid->m_nZMax; } |
360 | int wxJoystick::GetRudderMax() const | |
361 | { return m_hid->m_nRudderMax; } | |
ce0d1032 | 362 | int wxJoystick::GetUMax() const |
175ec4c8 | 363 | { return m_hid->m_nUMax; } |
4cb1d3da | 364 | int 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 | //--------------------------------------------------------------------------- | |
373 | int wxJoystick::GetMaxButtons() const | |
374 | { return wxJS_MAX_BUTTONS; } | |
375 | int wxJoystick::GetMaxAxes() const | |
376 | { return wxJS_MAX_AXES; } | |
377 | int wxJoystick::GetPollingMin() const | |
378 | { return 10; } | |
379 | int 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 |
388 | bool wxJoystick::HasZ() const |
389 | { return m_hid->HasElement(wxJS_AXIS_Z); } | |
175ec4c8 JS |
390 | bool wxJoystick::HasRudder() const |
391 | { return m_hid->HasElement(wxJS_AXIS_RUDDER); } | |
4cb1d3da RN |
392 | bool wxJoystick::HasU() const |
393 | { return m_hid->HasElement(wxJS_AXIS_U); } | |
4cb1d3da RN |
394 | bool wxJoystick::HasV() const |
395 | { return m_hid->HasElement(wxJS_AXIS_V); } | |
396 | ||
ce0d1032 SC |
397 | //--------------------------------------------------------------------------- |
398 | // UNSUPPORTED | |
399 | //--------------------------------------------------------------------------- | |
400 | int wxJoystick::GetPOVPosition() const | |
401 | { return -1; } | |
402 | int wxJoystick::GetPOVCTSPosition() const | |
403 | { return -1; } | |
404 | int wxJoystick::GetMovementThreshold() const | |
405 | { return 0; } | |
406 | void wxJoystick::SetMovementThreshold(int threshold) | |
407 | { } | |
4cb1d3da RN |
408 | bool wxJoystick::HasPOV() const |
409 | { return false; } | |
4cb1d3da RN |
410 | bool wxJoystick::HasPOV4Dir() const |
411 | { return false; } | |
4cb1d3da RN |
412 | bool 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 | //--------------------------------------------------------------------------- | |
426 | wxHIDJoystick::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 | //--------------------------------------------------------------------------- | |
437 | wxHIDJoystick::~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 | //--------------------------------------------------------------------------- | |
447 | bool wxHIDJoystick::Create(int nWhich) | |
4cb1d3da | 448 | { |
ce0d1032 SC |
449 | int nJoysticks = GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick); |
450 | ||
451 | if (nWhich <= nJoysticks) | |
452 | return wxHIDDevice::Create(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick); | |
453 | else | |
454 | nWhich -= nJoysticks; | |
455 | ||
456 | int nGamePads = GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad); | |
457 | ||
458 | if (nWhich <= nGamePads) | |
459 | return wxHIDDevice::Create(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad); | |
460 | else | |
4cb1d3da RN |
461 | return false; |
462 | } | |
463 | ||
ce0d1032 SC |
464 | //--------------------------------------------------------------------------- |
465 | // wxHIDJoystick::BuildCookies | |
466 | // wxHIDJoystick::MakeCookies | |
467 | // | |
468 | // Sets up the cookies for the HID device (called from Create) - as | |
469 | // mentioned 0-40 are the buttons and 40-50 are the axes. | |
470 | // | |
471 | // MakeCookies is just a recursive function for each array within | |
472 | // BuildCookies. | |
473 | //--------------------------------------------------------------------------- | |
474 | void wxHIDJoystick::BuildCookies(wxCFArray& Array) | |
4cb1d3da | 475 | { |
ce0d1032 SC |
476 | Array = CFDictionaryGetValue((CFDictionaryRef)Array[0], CFSTR(kIOHIDElementKey)); |
477 | InitCookies(50, true); | |
478 | ||
479 | memset(m_pCookies, 0, sizeof(*m_pCookies) * 50); | |
480 | ||
481 | // | |
482 | // I wasted two hours of my life on this line :( | |
483 | // accidently removed it during some source cleaning... | |
484 | // | |
485 | MakeCookies(Array); | |
486 | ||
487 | //paranoid debugging stuff | |
488 | #if 0 | |
489 | for(int i = 0; i < 50; ++i) | |
490 | wxPrintf(wxT("\nVAL #%i:[%i]"), i, m_pCookies[i]); | |
491 | #endif | |
492 | }//end buildcookies | |
493 | ||
494 | void wxHIDJoystick::MakeCookies(wxCFArray& Array) | |
495 | { | |
496 | int i, nUsage, nPage; | |
497 | ||
498 | for (i = 0; i < Array.Count(); ++i) | |
4cb1d3da | 499 | { |
ce0d1032 SC |
500 | const void* ref = CFDictionaryGetValue((CFDictionaryRef)Array[i], CFSTR(kIOHIDElementKey)); |
501 | ||
502 | if (ref != NULL) | |
503 | { | |
504 | wxCFArray newarray(ref); | |
505 | MakeCookies(newarray); | |
4cb1d3da | 506 | } |
ce0d1032 SC |
507 | else |
508 | { | |
509 | CFNumberGetValue( | |
510 | (CFNumberRef) CFDictionaryGetValue((CFDictionaryRef) Array[i], CFSTR(kIOHIDElementUsageKey)), | |
175ec4c8 | 511 | kCFNumberIntType, &nUsage); |
ce0d1032 SC |
512 | |
513 | CFNumberGetValue( | |
514 | (CFNumberRef) CFDictionaryGetValue((CFDictionaryRef) Array[i], CFSTR(kIOHIDElementUsagePageKey)), | |
175ec4c8 | 515 | kCFNumberIntType, &nPage); |
ce0d1032 SC |
516 | |
517 | #if 0 | |
518 | wxLogSysError(wxT("[%i][%i]"), nUsage, nPage); | |
519 | #endif | |
520 | if (nPage == kHIDPage_Button && nUsage <= 40) | |
521 | AddCookieInQueue(Array[i], nUsage-1 ); | |
522 | else if (nPage == kHIDPage_GenericDesktop) | |
523 | { | |
175ec4c8 | 524 | //axis... |
ce0d1032 SC |
525 | switch(nUsage) |
526 | { | |
527 | case kHIDUsage_GD_X: | |
528 | AddCookieInQueue(Array[i], wxJS_AXIS_X); | |
175ec4c8 JS |
529 | wxGetIntFromCFDictionary(Array[i], CFSTR(kIOHIDElementMaxKey), |
530 | &m_nXMax); | |
531 | wxGetIntFromCFDictionary(Array[i], CFSTR(kIOHIDElementMinKey), | |
532 | &m_nXMin); | |
ce0d1032 SC |
533 | break; |
534 | case kHIDUsage_GD_Y: | |
535 | AddCookieInQueue(Array[i], wxJS_AXIS_Y); | |
175ec4c8 JS |
536 | wxGetIntFromCFDictionary(Array[i], CFSTR(kIOHIDElementMaxKey), |
537 | &m_nYMax); | |
538 | wxGetIntFromCFDictionary(Array[i], CFSTR(kIOHIDElementMinKey), | |
539 | &m_nYMin); | |
ce0d1032 SC |
540 | break; |
541 | case kHIDUsage_GD_Z: | |
542 | AddCookieInQueue(Array[i], wxJS_AXIS_Z); | |
175ec4c8 JS |
543 | wxGetIntFromCFDictionary(Array[i], CFSTR(kIOHIDElementMaxKey), |
544 | &m_nZMax); | |
545 | wxGetIntFromCFDictionary(Array[i], CFSTR(kIOHIDElementMinKey), | |
546 | &m_nZMin); | |
ce0d1032 SC |
547 | break; |
548 | default: | |
549 | break; | |
550 | } | |
551 | } | |
552 | else if (nPage == kHIDPage_Simulation && nUsage == kHIDUsage_Sim_Rudder) | |
175ec4c8 JS |
553 | { |
554 | //rudder... | |
ce0d1032 | 555 | AddCookieInQueue(Array[i], wxJS_AXIS_RUDDER ); |
175ec4c8 JS |
556 | wxGetIntFromCFDictionary(Array[i], CFSTR(kIOHIDElementMaxKey), |
557 | &m_nRudderMax); | |
558 | wxGetIntFromCFDictionary(Array[i], CFSTR(kIOHIDElementMinKey), | |
559 | &m_nRudderMin); | |
560 | } | |
ce0d1032 SC |
561 | } |
562 | } | |
4cb1d3da | 563 | } |
ce0d1032 SC |
564 | |
565 | //--------------------------------------------------------------------------- | |
566 | // wxHIDJoystick::Get[XXX] | |
567 | // | |
568 | // Simple accessors so that the HID callback and the thread procedure | |
569 | // can access members from wxHIDDevice (our parent here). | |
570 | //--------------------------------------------------------------------------- | |
571 | IOHIDElementCookie* wxHIDJoystick::GetCookies() | |
572 | { return m_pCookies; } | |
573 | IOHIDQueueInterface** wxHIDJoystick::GetQueue() | |
574 | { return m_ppQueue; } | |
575 | ||
576 | //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
577 | // | |
578 | // wxJoystickThread | |
579 | // | |
580 | //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
581 | ||
582 | //--------------------------------------------------------------------------- | |
583 | // wxJoystickThread Constructor | |
584 | // | |
585 | // Just initializes members | |
586 | //--------------------------------------------------------------------------- | |
587 | wxJoystickThread::wxJoystickThread(wxHIDJoystick* hid, int joystick) | |
588 | : m_hid(hid), | |
589 | m_joystick(joystick), | |
590 | m_lastposition(127,127), | |
591 | m_buttons(0), | |
592 | m_catchwin(NULL), | |
593 | m_polling(0) | |
594 | { | |
595 | memset(m_axe, 0, sizeof(int) * wxJS_MAX_AXES); | |
596 | } | |
597 | ||
598 | //--------------------------------------------------------------------------- | |
599 | // wxJoystickThread::Entry | |
600 | // | |
601 | // Thread procedure | |
602 | // | |
603 | // Runs a CFRunLoop for polling. Basically, it sets the HID queue to | |
604 | // call wxJoystickThread::HIDCallback in the context of this thread | |
605 | // when something changes on the device. It polls as long as the user | |
606 | // wants, or a certain amount if the user wants to "block". Note that | |
607 | // we don't actually block here since this is in a secondary thread. | |
608 | //--------------------------------------------------------------------------- | |
609 | void* wxJoystickThread::Entry() | |
610 | { | |
611 | CFRunLoopSourceRef pRLSource = NULL; | |
612 | ||
613 | if ((*m_hid->GetQueue())->createAsyncEventSource( | |
614 | m_hid->GetQueue(), &pRLSource) != kIOReturnSuccess ) | |
615 | { | |
616 | wxLogSysError(wxT("Couldn't create async event source")); | |
617 | return NULL; | |
618 | } | |
619 | ||
620 | wxASSERT(pRLSource != NULL); | |
621 | ||
622 | //attach runloop source to main run loop in thread | |
623 | CFRunLoopRef pRL = CFRunLoopGetCurrent(); | |
624 | CFRunLoopAddSource(pRL, pRLSource, kCFRunLoopDefaultMode); | |
625 | wxASSERT( CFRunLoopContainsSource(pRL, pRLSource, kCFRunLoopDefaultMode) ); | |
626 | ||
627 | ||
628 | if( (*m_hid->GetQueue())->setEventCallout(m_hid->GetQueue(), | |
629 | wxJoystickThread::HIDCallback, this, this) != kIOReturnSuccess ) | |
630 | { | |
631 | wxLogSysError(wxT("Could not set event callout for queue")); | |
632 | return NULL; | |
633 | } | |
634 | ||
635 | if( (*m_hid->GetQueue())->start(m_hid->GetQueue()) != kIOReturnSuccess ) | |
636 | { | |
637 | wxLogSysError(wxT("Could not start queue")); | |
638 | return NULL; | |
639 | } | |
640 | ||
641 | double dTime; | |
642 | ||
643 | while(true) | |
644 | { | |
645 | if (TestDestroy()) | |
646 | break; | |
647 | ||
648 | if (m_polling) | |
649 | dTime = 0.0001 * m_polling; | |
650 | else | |
651 | dTime = 0.0001 * 10; // check at least every 10 msec in "blocking" case | |
652 | ||
653 | //true just "handles and returns" - false forces it to stay the time | |
654 | //amount | |
655 | #if 1 | |
656 | CFRunLoopRunInMode(kCFRunLoopDefaultMode, dTime, true); | |
657 | #else | |
658 | IOReturn ret = NULL; | |
659 | HIDCallback(this, ret, this, this); | |
660 | Sleep(3000); | |
4cb1d3da | 661 | #endif |
ce0d1032 SC |
662 | } |
663 | ||
664 | wxASSERT( CFRunLoopContainsSource(pRL, pRLSource, kCFRunLoopDefaultMode) ); | |
665 | ||
666 | CFRunLoopRemoveSource(pRL, pRLSource, kCFRunLoopDefaultMode); | |
667 | CFRelease(pRLSource); | |
668 | ||
669 | return NULL; | |
670 | } | |
671 | ||
672 | //--------------------------------------------------------------------------- | |
673 | // wxJoystickThread::HIDCallback (static) | |
674 | // | |
675 | // Callback for the native HID device when it recieves input. | |
676 | // | |
677 | // This is where the REAL dirty work gets done. | |
678 | // | |
679 | // 1) Loops through each event the queue has recieved | |
680 | // 2) First, checks if the thread that is running the loop for | |
681 | // the polling has ended - if so it breaks out | |
682 | // 3) Next, it checks if there was an error getting this event from | |
683 | // the HID queue, if there was, it logs an error and returns | |
684 | // 4) Now it does the real dirty work by getting the button states | |
685 | // from cookies 0-40 and axes positions/states from cookies 40-50 | |
686 | // in the native HID device by quering cookie values. | |
687 | // 5) Sends the event to the polling window (if any) | |
688 | // 6) Gets the next event and goes back to (1) | |
689 | //--------------------------------------------------------------------------- | |
690 | /*static*/ void wxJoystickThread::HIDCallback(void* target, IOReturn res, | |
691 | void* context, void* sender) | |
692 | { | |
693 | IOHIDEventStruct hidevent; | |
694 | AbsoluteTime bogustime = {0,0}; | |
695 | IOReturn ret; | |
696 | wxJoystickThread* pThis = (wxJoystickThread*) context; | |
697 | wxHIDJoystick* m_hid = pThis->m_hid; | |
4cb1d3da | 698 | |
ce0d1032 SC |
699 | //Get the "first" event from the queue |
700 | //bogustime tells it we don't care at what time to start | |
701 | //where it gets the next from | |
702 | ret = (*m_hid->GetQueue())->getNextEvent(m_hid->GetQueue(), | |
703 | &hidevent, bogustime, 0); | |
704 | ||
705 | while (ret != kIOReturnUnderrun) | |
706 | { | |
707 | if (pThis->TestDestroy()) | |
708 | break; | |
709 | ||
710 | if(ret != kIOReturnSuccess) | |
711 | { | |
712 | wxLogSysError(wxString::Format(wxT("wxJoystick Error:[%i]"), ret)); | |
713 | return; | |
714 | } | |
715 | ||
716 | wxJoystickEvent wxevent; | |
717 | ||
718 | //Find the cookie that changed | |
719 | int nIndex = 0; | |
720 | IOHIDElementCookie* pCookies = m_hid->GetCookies(); | |
721 | while(nIndex < 50) | |
722 | { | |
723 | if(hidevent.elementCookie == pCookies[nIndex]) | |
724 | break; | |
725 | ||
726 | ++nIndex; | |
727 | } | |
728 | ||
729 | //debugging stuff | |
730 | #if 0 | |
731 | if(nIndex == 50) | |
732 | { | |
733 | wxLogSysError(wxString::Format(wxT("wxJoystick Out Of Bounds Error"))); | |
734 | break; | |
735 | } | |
4cb1d3da | 736 | #endif |
ce0d1032 SC |
737 | |
738 | //is the cookie a button? | |
739 | if (nIndex < 40) | |
740 | { | |
741 | if (hidevent.value) | |
742 | { | |
743 | pThis->m_buttons |= (1 << nIndex); | |
744 | wxevent.SetEventType(wxEVT_JOY_BUTTON_DOWN); | |
745 | } | |
746 | else | |
747 | { | |
748 | pThis->m_buttons &= ~(1 << nIndex); | |
749 | wxevent.SetEventType(wxEVT_JOY_BUTTON_UP); | |
750 | } | |
751 | ||
752 | wxevent.SetButtonChange(nIndex+1); | |
753 | } | |
754 | else if (nIndex == wxJS_AXIS_X) | |
755 | { | |
756 | pThis->m_lastposition.x = hidevent.value; | |
757 | wxevent.SetEventType(wxEVT_JOY_MOVE); | |
758 | pThis->m_axe[0] = hidevent.value; | |
759 | } | |
760 | else if (nIndex == wxJS_AXIS_Y) | |
761 | { | |
762 | pThis->m_lastposition.y = hidevent.value; | |
763 | wxevent.SetEventType(wxEVT_JOY_MOVE); | |
764 | pThis->m_axe[1] = hidevent.value; | |
765 | } | |
766 | else if (nIndex == wxJS_AXIS_Z) | |
767 | { | |
768 | wxevent.SetEventType(wxEVT_JOY_ZMOVE); | |
769 | pThis->m_axe[2] = hidevent.value; | |
770 | } | |
771 | else | |
772 | wxevent.SetEventType(wxEVT_JOY_MOVE); | |
773 | ||
774 | Nanoseconds timestamp = AbsoluteToNanoseconds(hidevent.timestamp); | |
775 | ||
776 | wxULongLong llTime(timestamp.hi, timestamp.lo); | |
777 | ||
778 | llTime /= 1000000; | |
779 | ||
780 | wxevent.SetTimestamp(llTime.GetValue()); | |
781 | wxevent.SetJoystick(pThis->m_joystick); | |
782 | wxevent.SetButtonState(pThis->m_buttons); | |
783 | wxevent.SetPosition(pThis->m_lastposition); | |
784 | wxevent.SetZPosition(pThis->m_axe[2]); | |
785 | wxevent.SetEventObject(pThis->m_catchwin); | |
786 | ||
787 | if (pThis->m_catchwin) | |
788 | pThis->m_catchwin->AddPendingEvent(wxevent); | |
789 | ||
790 | ret = (*m_hid->GetQueue())->getNextEvent(m_hid->GetQueue(), | |
791 | &hidevent, bogustime, 0); | |
792 | } | |
793 | } | |
794 | ||
795 | #endif // wxUSE_JOYSTICK && defined(__DARWIN__) | |
4cb1d3da | 796 |