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