]> git.saurik.com Git - wxWidgets.git/blame - src/mac/corefoundation/hidjoystick.cpp
Minor editing.
[wxWidgets.git] / src / mac / corefoundation / hidjoystick.cpp
CommitLineData
4cb1d3da
RN
1/////////////////////////////////////////////////////////////////////////////
2// Name: joystick.cpp
3// Purpose: wxJoystick class
4// Author: Ryan Norton
5// Modified by:
6// Created: 2/13/2005
7// RCS-ID: $Id$
8// Copyright: (c) Ryan Norton
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
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
35enum {
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
47class wxHIDJoystick : public wxHIDDevice
48{
49public:
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
58bool 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
75void 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
119IMPLEMENT_DYNAMIC_CLASS(wxJoystick, wxObject)
120
121
122////////////////////////////////////////////////////////////////////////////
123// Background thread for reading the joystick device
124////////////////////////////////////////////////////////////////////////////
125
126class wxJoystickThread : public wxThread
127{
128public:
129 wxJoystickThread(wxHIDJoystick* hid, int joystick);
130 void* Entry();
131
132private:
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
145wxJoystickThread::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
161void* 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
268wxJoystick::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
288wxJoystick::~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
303wxPoint wxJoystick::GetPosition() const
304{
305 wxPoint pos(wxDefaultPosition);
306 if (m_thread) pos = m_thread->m_lastposition;
307 return pos;
308}
309
310int wxJoystick::GetZPosition() const
311{
312 if (m_thread)
313 return m_thread->m_axe[wxJS_AXIS_Z];
314 return 0;
315}
316
317int wxJoystick::GetButtonState() const
318{
319 if (m_thread)
320 return m_thread->m_buttons;
321 return 0;
322}
323
324int wxJoystick::GetPOVPosition() const
325{ return -1; }
326
327int wxJoystick::GetPOVCTSPosition() const
328{ return -1; }
329
330int wxJoystick::GetRudderPosition() const
331{
332 if (m_thread)
333 return m_thread->m_axe[wxJS_AXIS_RUDDER];
334 return 0;
335}
336
337int wxJoystick::GetUPosition() const
338{
339 if (m_thread)
340 return m_thread->m_axe[wxJS_AXIS_U];
341 return 0;
342}
343
344int wxJoystick::GetVPosition() const
345{
346 if (m_thread)
347 return m_thread->m_axe[wxJS_AXIS_V];
348 return 0;
349}
350
351int wxJoystick::GetMovementThreshold() const
352{ return 0; }
353
354void wxJoystick::SetMovementThreshold(int threshold)
355{ }
356
357////////////////////////////////////////////////////////////////////////////
358// Capabilities
359////////////////////////////////////////////////////////////////////////////
360
361bool wxJoystick::IsOk() const
362{ return m_hid != NULL; }
363
364int wxJoystick::GetNumberJoysticks() const
365{ return wxHIDDevice::GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick) +
366 wxHIDDevice::GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad); }
367
368int wxJoystick::GetManufacturerId() const
369{ return 0; }
370
371int wxJoystick::GetProductId() const
372{ return 0; }
373
374wxString wxJoystick::GetProductName() const
375{ return wxT("unknown"); }
376
377int wxJoystick::GetXMin() const
378{ return wxJS_AXIS_MIN; }
379
380int wxJoystick::GetYMin() const
381{ return wxJS_AXIS_MIN; }
382
383int wxJoystick::GetZMin() const
384{ return wxJS_AXIS_MIN; }
385
386int wxJoystick::GetXMax() const
387{ return wxJS_AXIS_MAX; }
388
389int wxJoystick::GetYMax() const
390{ return wxJS_AXIS_MAX; }
391
392int wxJoystick::GetZMax() const
393{ return wxJS_AXIS_MAX; }
394
395int 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
408int 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//
424int wxJoystick::GetMaxButtons() const
425{ return 15; }
426
427int wxJoystick::GetMaxAxes() const
428{ return 10; }
429
430int wxJoystick::GetPollingMin() const
431{ return 10; }
432
433int wxJoystick::GetPollingMax() const
434{ return 1000; }
435
436int wxJoystick::GetRudderMin() const
437{ return wxJS_AXIS_MIN; }
438
439int wxJoystick::GetRudderMax() const
440{ return wxJS_AXIS_MAX; }
441
442int wxJoystick::GetUMin() const
443{ return wxJS_AXIS_MIN; }
444
445int wxJoystick::GetUMax() const
446{ return wxJS_AXIS_MAX; }
447
448int wxJoystick::GetVMin() const
449{ return wxJS_AXIS_MIN; }
450
451int wxJoystick::GetVMax() const
452{ return wxJS_AXIS_MAX; }
453
454bool wxJoystick::HasRudder() const
455{ return m_hid->HasElement(wxJS_AXIS_RUDDER); }
456
457bool wxJoystick::HasZ() const
458{ return m_hid->HasElement(wxJS_AXIS_Z); }
459
460bool wxJoystick::HasU() const
461{ return m_hid->HasElement(wxJS_AXIS_U); }
462
463bool wxJoystick::HasV() const
464{ return m_hid->HasElement(wxJS_AXIS_V); }
465
466bool wxJoystick::HasPOV() const
467{ return false; }
468
469bool wxJoystick::HasPOV4Dir() const
470{ return false; }
471
472bool wxJoystick::HasPOVCTS() const
473{ return false; }
474
475////////////////////////////////////////////////////////////////////////////
476// Operations
477////////////////////////////////////////////////////////////////////////////
478
479bool 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
490bool 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