PageRenderTime 45ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/ExtLibs/wxWidgets/src/osx/core/hidjoystick.cpp

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