]> git.saurik.com Git - wxWidgets.git/blob - src/mac/corefoundation/hidjoystick.cpp
Minor editing.
[wxWidgets.git] / src / mac / corefoundation / hidjoystick.cpp
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
12 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
13 #pragma implementation "joystick.h"
14 #endif
15
16 #include "wx/wxprec.h"
17
18 #ifdef __DARWIN__
19
20 #if wxUSE_JOYSTICK
21
22 #include "wx/event.h"
23 #include "wx/log.h"
24 #include "wx/joystick.h"
25 #include "wx/thread.h"
26 #include "wx/window.h"
27
28 #include "wx/mac/corefoundation/hid.h"
29
30 #include <CoreServices/CoreServices.h>
31 #include <mach/mach.h>
32 #include <mach/mach_time.h>
33 #include <unistd.h>
34
35 enum {
36 wxJS_AXIS_X = 41,
37 wxJS_AXIS_Y,
38 wxJS_AXIS_Z,
39 wxJS_AXIS_RUDDER,
40 wxJS_AXIS_U,
41 wxJS_AXIS_V,
42
43 wxJS_AXIS_MAX = 32767,
44 wxJS_AXIS_MIN = -32767
45 };
46
47 class wxHIDJoystick : public wxHIDDevice
48 {
49 public:
50 bool Create(int nWhich);
51 virtual void BuildCookies(wxCFArray& Array);
52 IOHIDElementCookie* GetCookies() {return m_pCookies;}
53
54 IOHIDQueueInterface** GetQueue() {return m_ppQueue;}
55 };
56
57
58 bool wxHIDJoystick::Create(int nWhich)
59 {
60 int nJoysticks = GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick);
61
62 if (nWhich <= nJoysticks)
63 return wxHIDDevice::Create(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick);
64 else
65 nWhich -= nJoysticks;
66
67 int nGamePads = GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad);
68
69 if (nWhich <= nGamePads)
70 return wxHIDDevice::Create(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad);
71 else
72 return false;
73 }
74
75 void wxHIDJoystick::BuildCookies(wxCFArray& Array)
76 {
77 Array = CFDictionaryGetValue((CFDictionaryRef)Array[0], CFSTR(kIOHIDElementKey));
78 InitCookies(50, true);
79 int i,
80 nUsage,
81 nPage;
82 for (i = 0; i < Array.Count(); ++i)
83 {
84 CFNumberGetValue(
85 (CFNumberRef) CFDictionaryGetValue((CFDictionaryRef) Array[i], CFSTR(kIOHIDElementUsageKey)),
86 kCFNumberLongType, &nUsage);
87
88 CFNumberGetValue(
89 (CFNumberRef) CFDictionaryGetValue((CFDictionaryRef) Array[i], CFSTR(kIOHIDElementUsagePageKey)),
90 kCFNumberLongType, &nPage);
91
92 if (nPage == kHIDPage_Button && nUsage <= 40)
93 AddCookieInQueue(Array[i], nUsage );
94 else if (nPage == kHIDPage_GenericDesktop)
95 {
96 switch(nUsage)
97 {
98 case kHIDUsage_GD_X:
99 AddCookieInQueue(Array[i], wxJS_AXIS_X);
100 break;
101 case kHIDUsage_GD_Y:
102 AddCookieInQueue(Array[i], wxJS_AXIS_Y);
103 break;
104 case kHIDUsage_GD_Z:
105 AddCookieInQueue(Array[i], wxJS_AXIS_Z);
106 break;
107 default:
108 break;
109 }
110 }
111 else if (nPage == kHIDPage_Simulation && nUsage == kHIDUsage_Sim_Rudder)
112 AddCookieInQueue(Array[i], wxJS_AXIS_RUDDER );
113 }
114 }//end buildcookies
115
116
117
118
119 IMPLEMENT_DYNAMIC_CLASS(wxJoystick, wxObject)
120
121
122 ////////////////////////////////////////////////////////////////////////////
123 // Background thread for reading the joystick device
124 ////////////////////////////////////////////////////////////////////////////
125
126 class wxJoystickThread : public wxThread
127 {
128 public:
129 wxJoystickThread(wxHIDJoystick* hid, int joystick);
130 void* Entry();
131
132 private:
133 wxHIDJoystick* m_hid;
134 int m_joystick;
135 wxPoint m_lastposition;
136 int m_axe[15];
137 int m_buttons;
138 wxWindow* m_catchwin;
139 int m_polling;
140
141 friend class wxJoystick;
142 };
143
144
145 wxJoystickThread::wxJoystickThread(wxHIDJoystick* hid, int joystick)
146 : m_hid(hid),
147 m_joystick(joystick),
148 m_lastposition(wxDefaultPosition),
149 m_buttons(0),
150 m_catchwin(NULL),
151 m_polling(0)
152 {
153 for (int i=0; i<15; i++)
154 m_axe[i] = 0;
155 }
156
157
158 # define wxJSVERIFY(arg) if(!(arg)) {wxLogSysError(wxT(#arg)); return NULL;}
159 # define wxJSASSERT(arg) wxJSVERIFY(arg)
160
161 void* wxJoystickThread::Entry()
162 {
163 CFRunLoopSourceRef pRLSource = NULL;
164
165 wxJSVERIFY( (*m_hid->GetQueue())->createAsyncEventSource(m_hid->GetQueue(), &pRLSource)
166 == kIOReturnSuccess );
167 wxJSASSERT(pRLSource != NULL);
168
169 //attach runloop source to main run loop in thread
170 CFRunLoopRef pRL = CFRunLoopGetCurrent();
171 CFRunLoopAddSource(pRL, pRLSource, kCFRunLoopDefaultMode);
172
173 // wxJSVERIFY( (*m_hid->GetQueue())->start(m_hid->GetQueue()) == kIOReturnSuccess );
174
175 double dTime;
176 IOHIDEventStruct hidevent;
177 AbsoluteTime bogustime = {0,0};
178 IOReturn ret;
179
180 while(true)
181 {
182 if (TestDestroy())
183 break;
184
185 if (m_polling)
186 dTime = 0.0001 * m_polling;
187 else
188 dTime = 0.0001 * 10; // check at least every 10 msec in blocking case
189
190 CFRunLoopRunInMode(kCFRunLoopDefaultMode, dTime, m_polling);
191
192 while ( (ret = (*m_hid->GetQueue())->getNextEvent(m_hid->GetQueue(),
193 &hidevent, bogustime, 0)) != kIOReturnUnderrun )
194 {
195 if (TestDestroy())
196 break;
197
198 wxJSASSERT(ret == kIOReturnSuccess);
199 wxJoystickEvent wxevent;
200
201 int nIndex = 0;
202 IOHIDElementCookie* pCookies = m_hid->GetCookies();
203 while(nIndex < 50)
204 {
205 if(hidevent.elementCookie == pCookies[nIndex])
206 break;
207 }
208 wxASSERT(nIndex != 50);
209
210 if (nIndex < 40)
211 {
212 if (hidevent.value)
213 {
214 m_buttons |= (1 << nIndex);
215 wxevent.SetEventType(wxEVT_JOY_BUTTON_DOWN);
216 }
217 else
218 {
219 m_buttons &= ~(1 << nIndex);
220 wxevent.SetEventType(wxEVT_JOY_BUTTON_UP);
221 }
222
223 wxevent.SetButtonChange(nIndex);
224 }
225 else if (nIndex == wxJS_AXIS_X)
226 {
227 m_lastposition.x = hidevent.value;
228 wxevent.SetEventType(wxEVT_JOY_MOVE);
229 m_axe[nIndex - 39] = hidevent.value;
230 }
231 else if (nIndex == wxJS_AXIS_Y)
232 {
233 m_lastposition.y = hidevent.value;
234 wxevent.SetEventType(wxEVT_JOY_MOVE);
235 m_axe[nIndex - 39] = hidevent.value;
236 }
237 else if (nIndex == wxJS_AXIS_Z)
238 {
239 wxevent.SetEventType(wxEVT_JOY_ZMOVE);
240 m_axe[nIndex - 39] = hidevent.value;
241 }
242 else
243 wxevent.SetEventType(wxEVT_JOY_MOVE);
244
245 Nanoseconds timestamp = AbsoluteToNanoseconds(hidevent.timestamp);
246
247 wxULongLong llTime(timestamp.hi, timestamp.lo);
248
249 llTime /= 1000000;
250
251 wxevent.SetTimestamp(llTime.GetValue());
252 wxevent.SetJoystick(m_joystick);
253 wxevent.SetButtonState(m_buttons);
254 wxevent.SetPosition(m_lastposition);
255 wxevent.SetZPosition(m_axe[3]);
256 wxevent.SetEventObject(m_catchwin);
257
258 if (m_catchwin)
259 m_catchwin->AddPendingEvent(wxevent);
260 }
261 }
262 return NULL;
263 }
264
265
266 ////////////////////////////////////////////////////////////////////////////
267
268 wxJoystick::wxJoystick(int joystick)
269 : m_joystick(joystick),
270 m_thread(NULL)
271 {
272 m_hid = new wxHIDJoystick();
273
274 if (m_hid->Create(m_joystick))
275 {
276 m_thread = new wxJoystickThread(m_hid, m_joystick);
277 m_thread->Create();
278 m_thread->Run();
279 }
280 else
281 {
282 delete m_hid;
283 m_hid = NULL;
284 }
285 }
286
287
288 wxJoystick::~wxJoystick()
289 {
290 ReleaseCapture();
291 if (m_thread)
292 m_thread->Delete(); // It's detached so it will delete itself
293
294 if (m_hid)
295 delete m_hid;
296 }
297
298
299 ////////////////////////////////////////////////////////////////////////////
300 // State
301 ////////////////////////////////////////////////////////////////////////////
302
303 wxPoint wxJoystick::GetPosition() const
304 {
305 wxPoint pos(wxDefaultPosition);
306 if (m_thread) pos = m_thread->m_lastposition;
307 return pos;
308 }
309
310 int wxJoystick::GetZPosition() const
311 {
312 if (m_thread)
313 return m_thread->m_axe[wxJS_AXIS_Z];
314 return 0;
315 }
316
317 int wxJoystick::GetButtonState() const
318 {
319 if (m_thread)
320 return m_thread->m_buttons;
321 return 0;
322 }
323
324 int wxJoystick::GetPOVPosition() const
325 { return -1; }
326
327 int wxJoystick::GetPOVCTSPosition() const
328 { return -1; }
329
330 int wxJoystick::GetRudderPosition() const
331 {
332 if (m_thread)
333 return m_thread->m_axe[wxJS_AXIS_RUDDER];
334 return 0;
335 }
336
337 int wxJoystick::GetUPosition() const
338 {
339 if (m_thread)
340 return m_thread->m_axe[wxJS_AXIS_U];
341 return 0;
342 }
343
344 int wxJoystick::GetVPosition() const
345 {
346 if (m_thread)
347 return m_thread->m_axe[wxJS_AXIS_V];
348 return 0;
349 }
350
351 int wxJoystick::GetMovementThreshold() const
352 { return 0; }
353
354 void wxJoystick::SetMovementThreshold(int threshold)
355 { }
356
357 ////////////////////////////////////////////////////////////////////////////
358 // Capabilities
359 ////////////////////////////////////////////////////////////////////////////
360
361 bool wxJoystick::IsOk() const
362 { return m_hid != NULL; }
363
364 int wxJoystick::GetNumberJoysticks() const
365 { return wxHIDDevice::GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick) +
366 wxHIDDevice::GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad); }
367
368 int wxJoystick::GetManufacturerId() const
369 { return 0; }
370
371 int wxJoystick::GetProductId() const
372 { return 0; }
373
374 wxString wxJoystick::GetProductName() const
375 { return wxT("unknown"); }
376
377 int wxJoystick::GetXMin() const
378 { return wxJS_AXIS_MIN; }
379
380 int wxJoystick::GetYMin() const
381 { return wxJS_AXIS_MIN; }
382
383 int wxJoystick::GetZMin() const
384 { return wxJS_AXIS_MIN; }
385
386 int wxJoystick::GetXMax() const
387 { return wxJS_AXIS_MAX; }
388
389 int wxJoystick::GetYMax() const
390 { return wxJS_AXIS_MAX; }
391
392 int wxJoystick::GetZMax() const
393 { return wxJS_AXIS_MAX; }
394
395 int wxJoystick::GetNumberButtons() const
396 {
397 int nCount = 0;
398
399 for(int nIndex = 0; nIndex < 40; ++nIndex)
400 {
401 if(m_hid->HasElement(nIndex))
402 ++nCount;
403 }
404
405 return nCount;
406 }
407
408 int wxJoystick::GetNumberAxes() const
409 {
410 int nCount = 0;
411
412 for(int nIndex = 40; nIndex < 50; ++nIndex)
413 {
414 if(m_hid->HasElement(nIndex))
415 ++nCount;
416 }
417
418 return nCount;
419 }
420
421 //
422 // internal
423 //
424 int wxJoystick::GetMaxButtons() const
425 { return 15; }
426
427 int wxJoystick::GetMaxAxes() const
428 { return 10; }
429
430 int wxJoystick::GetPollingMin() const
431 { return 10; }
432
433 int wxJoystick::GetPollingMax() const
434 { return 1000; }
435
436 int wxJoystick::GetRudderMin() const
437 { return wxJS_AXIS_MIN; }
438
439 int wxJoystick::GetRudderMax() const
440 { return wxJS_AXIS_MAX; }
441
442 int wxJoystick::GetUMin() const
443 { return wxJS_AXIS_MIN; }
444
445 int wxJoystick::GetUMax() const
446 { return wxJS_AXIS_MAX; }
447
448 int wxJoystick::GetVMin() const
449 { return wxJS_AXIS_MIN; }
450
451 int wxJoystick::GetVMax() const
452 { return wxJS_AXIS_MAX; }
453
454 bool wxJoystick::HasRudder() const
455 { return m_hid->HasElement(wxJS_AXIS_RUDDER); }
456
457 bool wxJoystick::HasZ() const
458 { return m_hid->HasElement(wxJS_AXIS_Z); }
459
460 bool wxJoystick::HasU() const
461 { return m_hid->HasElement(wxJS_AXIS_U); }
462
463 bool wxJoystick::HasV() const
464 { return m_hid->HasElement(wxJS_AXIS_V); }
465
466 bool wxJoystick::HasPOV() const
467 { return false; }
468
469 bool wxJoystick::HasPOV4Dir() const
470 { return false; }
471
472 bool wxJoystick::HasPOVCTS() const
473 { return false; }
474
475 ////////////////////////////////////////////////////////////////////////////
476 // Operations
477 ////////////////////////////////////////////////////////////////////////////
478
479 bool wxJoystick::SetCapture(wxWindow* win, int pollingFreq)
480 {
481 if (m_thread)
482 {
483 m_thread->m_catchwin = win;
484 m_thread->m_polling = pollingFreq;
485 return true;
486 }
487 return false;
488 }
489
490 bool wxJoystick::ReleaseCapture()
491 {
492 if (m_thread)
493 {
494 m_thread->m_catchwin = NULL;
495 m_thread->m_polling = 0;
496 return true;
497 }
498 return false;
499 }
500 #endif
501 //OSX
502
503 #endif
504 // wxUSE_JOYSTICK
505