X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/2a32f1733dd39882d58627d5cb22dbdeb54eb693..bc9e85a3190319006186cd097f9d5b6584f513fa:/src/mac/corefoundation/hidjoystick.cpp diff --git a/src/mac/corefoundation/hidjoystick.cpp b/src/mac/corefoundation/hidjoystick.cpp index 780c1b5ca6..a0e63d71db 100644 --- a/src/mac/corefoundation/hidjoystick.cpp +++ b/src/mac/corefoundation/hidjoystick.cpp @@ -1,262 +1,109 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: joystick.cpp +// Name: src/mac/corefoundation/joystick.cpp // Purpose: wxJoystick class // Author: Ryan Norton // Modified by: // Created: 2/13/2005 // RCS-ID: $Id$ // Copyright: (c) Ryan Norton -// Licence: wxWindows licence +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) -#pragma implementation "joystick.h" -#endif +//=========================================================================== +// DECLARATIONS +//=========================================================================== + +//--------------------------------------------------------------------------- +// Pre-compiled header stuff +//--------------------------------------------------------------------------- +// For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" -#ifdef __DARWIN__ +//--------------------------------------------------------------------------- +// Guard +//--------------------------------------------------------------------------- + +//we only support HID on OSX (DARWIN), since it requires DARWIN... +#if wxUSE_JOYSTICK && defined(__DARWIN__) + +//--------------------------------------------------------------------------- +// Includes +//--------------------------------------------------------------------------- -#if wxUSE_JOYSTICK +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/event.h" //joystick wxEvents + #include "wx/window.h" //for wxWindow to "capture" joystick +#endif -#include "wx/event.h" -#include "wx/log.h" -#include "wx/joystick.h" -#include "wx/thread.h" -#include "wx/window.h" +#include "wx/joystick.h" //... +#include "wx/thread.h" //wxThread for polling thread/ wxCriticalSection -#include "wx/mac/corefoundation/hid.h" +//private headers +#include "wx/mac/corefoundation/hid.h" //private mac hid stuff +//mac headers #include #include #include #include -enum { +//--------------------------------------------------------------------------- +// Definitions/Enumerations +//--------------------------------------------------------------------------- + +#define wxJS_MAX_AXES 10 /*max number of axes*/ +#define wxJS_MAX_BUTTONS 40 /*max number of buttons*/ + +enum +{ + //These are positions within the cookie array + //in wxHIDJoystick that the cookies that store the axis' are wxJS_AXIS_X = 40, wxJS_AXIS_Y, wxJS_AXIS_Z, wxJS_AXIS_RUDDER, wxJS_AXIS_U, wxJS_AXIS_V, - - wxJS_AXIS_MAX = 255, //32767, - wxJS_AXIS_MIN = 0, //-32767 }; +//--------------------------------------------------------------------------- +// wxHIDJoystick +//--------------------------------------------------------------------------- class wxHIDJoystick : public wxHIDDevice { public: - bool Create(int nWhich); - virtual void BuildCookies(wxCFArray& Array); - void MakeCookies(wxCFArray& Array); - IOHIDElementCookie* GetCookies() {return m_pCookies;} - IOHIDQueueInterface** GetQueue() {return m_ppQueue;} - - friend class wxJoystick; -}; + wxHIDJoystick(); + virtual ~wxHIDJoystick(); + bool Create(int nWhich); + virtual void BuildCookies(CFArrayRef Array); + void MakeCookies(CFArrayRef Array); + IOHIDElementCookie* GetCookies(); + IOHIDQueueInterface** GetQueue(); -bool wxHIDJoystick::Create(int nWhich) -{ - int nJoysticks = GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick); - - if (nWhich <= nJoysticks) - return wxHIDDevice::Create(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick); - else - nWhich -= nJoysticks; - - int nGamePads = GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad); - - if (nWhich <= nGamePads) - return wxHIDDevice::Create(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad); - else - return false; -} - -void wxHIDJoystick::BuildCookies(wxCFArray& Array) -{ - Array = CFDictionaryGetValue((CFDictionaryRef)Array[0], CFSTR(kIOHIDElementKey)); - InitCookies(50, true); + int m_nXMax, m_nYMax, m_nZMax, m_nRudderMax, m_nUMax, m_nVMax, + m_nXMin, m_nYMin, m_nZMin, m_nRudderMin, m_nUMin, m_nVMin; - memset(m_pCookies, 0, sizeof(*m_pCookies) * 50); - MakeCookies(Array); - -// for(int i = 0; i < 50; ++i) -// wxPrintf(wxT("\nVAL #%i:[%i]"), i, m_pCookies[i]); -}//end buildcookies - -void wxHIDJoystick::MakeCookies(wxCFArray& Array) -{ - int i, - nUsage, - nPage; - for (i = 0; i < Array.Count(); ++i) - { - const void* ref = CFDictionaryGetValue((CFDictionaryRef)Array[i], CFSTR(kIOHIDElementKey)); - -// wxPrintf(wxT("ELM\n")); - if (ref != NULL) - { - wxCFArray newarray(ref); - MakeCookies(newarray); - } - else - { - CFNumberGetValue( - (CFNumberRef) CFDictionaryGetValue((CFDictionaryRef) Array[i], CFSTR(kIOHIDElementUsageKey)), - kCFNumberLongType, &nUsage); - - CFNumberGetValue( - (CFNumberRef) CFDictionaryGetValue((CFDictionaryRef) Array[i], CFSTR(kIOHIDElementUsagePageKey)), - kCFNumberLongType, &nPage); - - if (nPage == kHIDPage_Button && nUsage <= 40) - AddCookieInQueue(Array[i], nUsage-1 ); - else if (nPage == kHIDPage_GenericDesktop) - { - switch(nUsage) - { - case kHIDUsage_GD_X: - AddCookieInQueue(Array[i], wxJS_AXIS_X); - break; - case kHIDUsage_GD_Y: - AddCookieInQueue(Array[i], wxJS_AXIS_Y); - break; - case kHIDUsage_GD_Z: - AddCookieInQueue(Array[i], wxJS_AXIS_Z); - break; - default: - break; - } - } - else if (nPage == kHIDPage_Simulation && nUsage == kHIDUsage_Sim_Rudder) - AddCookieInQueue(Array[i], wxJS_AXIS_RUDDER ); - } - } -} - - - -IMPLEMENT_DYNAMIC_CLASS(wxJoystick, wxObject) - - -//////////////////////////////////////////////////////////////////////////// -// Background thread for reading the joystick device -//////////////////////////////////////////////////////////////////////////// + friend class wxJoystick; +}; +//--------------------------------------------------------------------------- +// wxJoystickThread +//--------------------------------------------------------------------------- class wxJoystickThread : public wxThread { public: wxJoystickThread(wxHIDJoystick* hid, int joystick); void* Entry(); + static void HIDCallback(void* target, IOReturn res, void* context, void* sender); - static void HIDCallback(void* target, IOReturn res, void* context, void* sender) - { - IOHIDEventStruct hidevent; - AbsoluteTime bogustime = {0,0}; - IOReturn ret; - wxJoystickThread* pThis = (wxJoystickThread*) context; - wxHIDJoystick* m_hid = pThis->m_hid; - -// wxMutexGuiEnter(); - ret = (*m_hid->GetQueue())->getNextEvent(m_hid->GetQueue(), - &hidevent, bogustime, 0); - // wxMutexGuiLeave(); - while ( ret != kIOReturnUnderrun ) - { - if (pThis->TestDestroy()) - break; - -// wxPrintf(wxT("ENTER\n")); - if(ret != kIOReturnSuccess) - { - wxLogSysError(wxString::Format(wxT("wxJoystick Error:[%i]"), ret)); - return; - } - - wxJoystickEvent wxevent; - - int nIndex = 0; - IOHIDElementCookie* pCookies = m_hid->GetCookies(); - while(nIndex < 50) - { - if(hidevent.elementCookie == pCookies[nIndex]) - break; - - ++nIndex; - } - if(nIndex == 50) - { - wxLogSysError(wxString::Format(wxT("wxJoystick Out Of Bounds Error"))); - break; - } - - if (nIndex < 40) - { - if (hidevent.value) - { - pThis->m_buttons |= (1 << nIndex); - wxevent.SetEventType(wxEVT_JOY_BUTTON_DOWN); - } - else - { - pThis->m_buttons &= ~(1 << nIndex); - wxevent.SetEventType(wxEVT_JOY_BUTTON_UP); - } - - wxevent.SetButtonChange(nIndex+1); - } - else if (nIndex == wxJS_AXIS_X) - { - pThis->m_lastposition.x = hidevent.value; - wxevent.SetEventType(wxEVT_JOY_MOVE); - pThis->m_axe[0] = hidevent.value; - } - else if (nIndex == wxJS_AXIS_Y) - { - pThis->m_lastposition.y = hidevent.value; - wxevent.SetEventType(wxEVT_JOY_MOVE); - pThis->m_axe[1] = hidevent.value; - } - else if (nIndex == wxJS_AXIS_Z) - { - wxevent.SetEventType(wxEVT_JOY_ZMOVE); - pThis->m_axe[2] = hidevent.value; - } - else - wxevent.SetEventType(wxEVT_JOY_MOVE); - - Nanoseconds timestamp = AbsoluteToNanoseconds(hidevent.timestamp); - - wxULongLong llTime(timestamp.hi, timestamp.lo); - - llTime /= 1000000; - - wxevent.SetTimestamp(llTime.GetValue()); - wxevent.SetJoystick(pThis->m_joystick); - wxevent.SetButtonState(pThis->m_buttons); - wxevent.SetPosition(pThis->m_lastposition); - wxevent.SetZPosition(pThis->m_axe[2]); - wxevent.SetEventObject(pThis->m_catchwin); - -// wxPrintf(wxT("SEND\n")); - - if (pThis->m_catchwin) - pThis->m_catchwin->AddPendingEvent(wxevent); - - // wxMutexGuiEnter(); - ret = (*m_hid->GetQueue())->getNextEvent(m_hid->GetQueue(), - &hidevent, bogustime, 0); - // wxMutexGuiLeave(); - } - } - private: wxHIDJoystick* m_hid; int m_joystick; wxPoint m_lastposition; - int m_axe[15]; + int m_axe[wxJS_MAX_AXES]; int m_buttons; wxWindow* m_catchwin; int m_polling; @@ -264,70 +111,45 @@ private: friend class wxJoystick; }; +//=========================================================================== +// IMPLEMENTATION +//=========================================================================== -wxJoystickThread::wxJoystickThread(wxHIDJoystick* hid, int joystick) - : m_hid(hid), - m_joystick(joystick), - m_lastposition(127,127), - m_buttons(0), - m_catchwin(NULL), - m_polling(0) -{ - for (int i=0; i<15; i++) - m_axe[i] = 0; -} - - -# define wxJSVERIFY(arg) if(!(arg)) {wxLogSysError(wxT(#arg)); return NULL;} -# define wxJSASSERT(arg) wxJSVERIFY(arg) - -void* wxJoystickThread::Entry() +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +// wxGetIntFromCFDictionary +// +// Helper function that gets a integer from a dictionary key +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +void wxGetIntFromCFDictionary(CFTypeRef cfDict, CFStringRef key, int* pOut) { - CFRunLoopSourceRef pRLSource = NULL; - - wxJSVERIFY( (*m_hid->GetQueue())->createAsyncEventSource(m_hid->GetQueue(), &pRLSource) - == kIOReturnSuccess ); - wxJSASSERT(pRLSource != NULL); - - //attach runloop source to main run loop in thread - CFRunLoopRef pRL = CFRunLoopGetCurrent(); - CFRunLoopAddSource(pRL, pRLSource, kCFRunLoopDefaultMode); - - wxJSVERIFY( (*m_hid->GetQueue())->start(m_hid->GetQueue()) == kIOReturnSuccess ); - wxJSVERIFY( (*m_hid->GetQueue())->setEventCallout(m_hid->GetQueue(), &wxJoystickThread::HIDCallback, this, this) == kIOReturnSuccess ); - - double dTime; - - while(true) - { - if (TestDestroy()) - break; - - if (m_polling) - dTime = 0.0001 * m_polling; - else - dTime = 0.0001 * 10; // check at least every 10 msec in blocking case - - CFRunLoopRunInMode(kCFRunLoopDefaultMode, dTime, true); - } - - wxJSASSERT( CFRunLoopContainsSource(pRL, pRLSource, kCFRunLoopDefaultMode) ); - CFRunLoopRemoveSource(pRL, pRLSource, kCFRunLoopDefaultMode); - CFRelease(pRLSource); - - return NULL; + CFNumberGetValue( + (CFNumberRef) CFDictionaryGetValue((CFDictionaryRef) cfDict, + key), + kCFNumberIntType, pOut); } +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// wxJoystick +// +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -//////////////////////////////////////////////////////////////////////////// +IMPLEMENT_DYNAMIC_CLASS(wxJoystick, wxObject) +//--------------------------------------------------------------------------- +// wxJoystick Constructor +// +// 1) Initializes member variables +// 2) Attempts to create the native HID joystick implementation - if none +// could be found (no joysticks, etc.) then it sets it to NULL +//--------------------------------------------------------------------------- wxJoystick::wxJoystick(int joystick) : m_joystick(joystick), m_thread(NULL) { m_hid = new wxHIDJoystick(); - if (m_hid->Create(m_joystick)) + if (m_hid->Create(m_joystick+1)) //wxHIDDevice is 1-based while this is 0 { m_thread = new wxJoystickThread(m_hid, m_joystick); m_thread->Create(); @@ -340,63 +162,52 @@ wxJoystick::wxJoystick(int joystick) } } - +//--------------------------------------------------------------------------- +// wxJoystick Destructor +// +// Releases the capture of the thread, deletes it, and deletes +// the native implementation. +//--------------------------------------------------------------------------- wxJoystick::~wxJoystick() { ReleaseCapture(); if (m_thread) m_thread->Delete(); // It's detached so it will delete itself - + if (m_hid) delete m_hid; } - -//////////////////////////////////////////////////////////////////////////// -// State -//////////////////////////////////////////////////////////////////////////// - +//--------------------------------------------------------------------------- +// wxJoystick::Get[XXX]Position +// +// Returns the value of an axis that was polled from the thread. In the +// case of GetPosition returns the X and Y values in a wxPoint +//--------------------------------------------------------------------------- wxPoint wxJoystick::GetPosition() const { wxPoint pos(wxDefaultPosition); if (m_thread) pos = m_thread->m_lastposition; return pos; } - int wxJoystick::GetZPosition() const { if (m_thread) return m_thread->m_axe[wxJS_AXIS_Z]; return 0; } - -int wxJoystick::GetButtonState() const -{ - if (m_thread) - return m_thread->m_buttons; - return 0; -} - -int wxJoystick::GetPOVPosition() const -{ return -1; } - -int wxJoystick::GetPOVCTSPosition() const -{ return -1; } - int wxJoystick::GetRudderPosition() const -{ +{ if (m_thread) return m_thread->m_axe[wxJS_AXIS_RUDDER]; return 0; } - int wxJoystick::GetUPosition() const { if (m_thread) return m_thread->m_axe[wxJS_AXIS_U]; return 0; } - int wxJoystick::GetVPosition() const { if (m_thread) @@ -404,158 +215,689 @@ int wxJoystick::GetVPosition() const return 0; } -int wxJoystick::GetMovementThreshold() const -{ return 0; } - -void wxJoystick::SetMovementThreshold(int threshold) -{ } - -//////////////////////////////////////////////////////////////////////////// -// Capabilities -//////////////////////////////////////////////////////////////////////////// +//--------------------------------------------------------------------------- +// wxJoystick::GetButtonState +// +// Returns the state of the buttons in a bitmask as dictated by the +// wx manual (the real work takes place in the thread, as always) +//--------------------------------------------------------------------------- +int wxJoystick::GetButtonState() const +{ + if (m_thread) + return m_thread->m_buttons; + return 0; +} +//--------------------------------------------------------------------------- +// wxJoystick::IsOk +// +// Returns whether the joystick initialized successfully - in this case +// if the native implementation doesn't exist (in constructor) +//--------------------------------------------------------------------------- bool wxJoystick::IsOk() const -{ return m_hid != NULL; } +{ + return m_hid != NULL; +} -int wxJoystick::GetNumberJoysticks() const -{ return wxHIDDevice::GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick) + - wxHIDDevice::GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad); } - +//--------------------------------------------------------------------------- +// wxJoystick::Get[XXX](Id/Name) +// +// Simple accessors to the native HID implementation +//--------------------------------------------------------------------------- int wxJoystick::GetManufacturerId() const -{ return m_hid->m_nManufacturerId; } +{ + return m_hid->m_nManufacturerId; +} int wxJoystick::GetProductId() const -{ return m_hid->m_nProductId; } +{ + return m_hid->m_nProductId; +} wxString wxJoystick::GetProductName() const -{ return m_hid->m_szProductName; } - -int wxJoystick::GetXMin() const -{ return wxJS_AXIS_MIN; } - -int wxJoystick::GetYMin() const -{ return wxJS_AXIS_MIN; } - -int wxJoystick::GetZMin() const -{ return wxJS_AXIS_MIN; } - -int wxJoystick::GetXMax() const -{ return wxJS_AXIS_MAX; } - -int wxJoystick::GetYMax() const -{ return wxJS_AXIS_MAX; } - -int wxJoystick::GetZMax() const -{ return wxJS_AXIS_MAX; } +{ + return m_hid->m_szProductName; +} +//--------------------------------------------------------------------------- +// wxJoystick::GetNumberButtons +// wxJoystick::GetNumberAxes +// +// Queries the joystick for an active number of buttons/axes. +// +// In the native HID implementation, the cookies: +// 0-40 are the buttons of the joystick +// 40-50 are the axes of the joystick +// +// These just query the native HID implementation as above. +//--------------------------------------------------------------------------- int wxJoystick::GetNumberButtons() const { int nCount = 0; - + for(int nIndex = 0; nIndex < 40; ++nIndex) { if(m_hid->HasElement(nIndex)) ++nCount; } - + return nCount; } - int wxJoystick::GetNumberAxes() const { int nCount = 0; - + for(int nIndex = 40; nIndex < 50; ++nIndex) { if(m_hid->HasElement(nIndex)) ++nCount; } - + return nCount; } +//--------------------------------------------------------------------------- +// wxJoystick::GetNumberJoysticks // -// internal +// Gets the number of joysticks on the system. In HID that +// is all devices with the kHIDUsage_GD_Joystick or kHIDUsage_GD_GamePad +// identifiers. +//--------------------------------------------------------------------------- +int wxJoystick::GetNumberJoysticks() +{ + return + wxHIDDevice::GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick) + + wxHIDDevice::GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad); +} + +//--------------------------------------------------------------------------- +// wxJoystick::SetCapture // -int wxJoystick::GetMaxButtons() const -{ return 15; } +// Stops sending events from the thread to the window set in +// SetCapture and stops polling the joystick +//--------------------------------------------------------------------------- +bool wxJoystick::SetCapture(wxWindow* win, int pollingFreq) +{ + if (m_thread) + { + m_thread->m_catchwin = win; + m_thread->m_polling = pollingFreq; + return true; + } + return false; +} -int wxJoystick::GetMaxAxes() const -{ return 10; } +//--------------------------------------------------------------------------- +// wxJoystick::ReleaseCapture +// +// Stops sending events from the thread to the window set in +// SetCapture and stops polling the joystick +//--------------------------------------------------------------------------- +bool wxJoystick::ReleaseCapture() +{ + if (m_thread) + { + m_thread->m_catchwin = NULL; + m_thread->m_polling = 0; + return true; + } + return false; +} -int wxJoystick::GetPollingMin() const -{ return 10; } +//--------------------------------------------------------------------------- +// wxJoystick::Get[XXX] +// +// Gets the minimum and maximum values for each axis, returning 0 if the +// axis doesn't exist. +//--------------------------------------------------------------------------- +int wxJoystick::GetXMin() const +{ + return m_hid->m_nXMin; +} -int wxJoystick::GetPollingMax() const -{ return 1000; } +int wxJoystick::GetYMin() const +{ + return m_hid->m_nYMin; +} -int wxJoystick::GetRudderMin() const -{ return wxJS_AXIS_MIN; } +int wxJoystick::GetZMin() const +{ + return m_hid->m_nZMin; +} -int wxJoystick::GetRudderMax() const -{ return wxJS_AXIS_MAX; } +int wxJoystick::GetRudderMin() const +{ + return m_hid->m_nRudderMin; +} int wxJoystick::GetUMin() const -{ return wxJS_AXIS_MIN; } - -int wxJoystick::GetUMax() const -{ return wxJS_AXIS_MAX; } +{ + return m_hid->m_nUMin; +} int wxJoystick::GetVMin() const -{ return wxJS_AXIS_MIN; } +{ + return m_hid->m_nVMin; +} + +int wxJoystick::GetXMax() const +{ + return m_hid->m_nXMax; +} + +int wxJoystick::GetYMax() const +{ + return m_hid->m_nYMax; +} + +int wxJoystick::GetZMax() const +{ + return m_hid->m_nZMax; +} + +int wxJoystick::GetRudderMax() const +{ + return m_hid->m_nRudderMax; +} + +int wxJoystick::GetUMax() const +{ + return m_hid->m_nUMax; +} int wxJoystick::GetVMax() const -{ return wxJS_AXIS_MAX; } +{ + return m_hid->m_nVMax; +} -bool wxJoystick::HasRudder() const -{ return m_hid->HasElement(wxJS_AXIS_RUDDER); } +//--------------------------------------------------------------------------- +// wxJoystick::Get[XXX] +// +// Min/Max values for buttons, axes, etc.. Polling in this case is just +// what the linux port has. +//--------------------------------------------------------------------------- +int wxJoystick::GetMaxButtons() const +{ + return wxJS_MAX_BUTTONS; +} + +int wxJoystick::GetMaxAxes() const +{ + return wxJS_MAX_AXES; +} + +int wxJoystick::GetPollingMin() const +{ + return 10; +} + +int wxJoystick::GetPollingMax() const +{ + return 1000; +} +//--------------------------------------------------------------------------- +// wxJoystick::Has[XXX] +// +// Just queries the native hid implementation if the cookie was found +// when enumerating the cookies of the joystick device +//--------------------------------------------------------------------------- bool wxJoystick::HasZ() const -{ return m_hid->HasElement(wxJS_AXIS_Z); } +{ + return m_hid->HasElement(wxJS_AXIS_Z); +} + +bool wxJoystick::HasRudder() const +{ + return m_hid->HasElement(wxJS_AXIS_RUDDER); +} bool wxJoystick::HasU() const -{ return m_hid->HasElement(wxJS_AXIS_U); } +{ + return m_hid->HasElement(wxJS_AXIS_U); +} bool wxJoystick::HasV() const -{ return m_hid->HasElement(wxJS_AXIS_V); } +{ + return m_hid->HasElement(wxJS_AXIS_V); +} + +//--------------------------------------------------------------------------- +// UNSUPPORTED +//--------------------------------------------------------------------------- +int wxJoystick::GetPOVPosition() const +{ + return -1; +} + +int wxJoystick::GetPOVCTSPosition() const +{ + return -1; +} + +int wxJoystick::GetMovementThreshold() const +{ + return 0; +} + +void wxJoystick::SetMovementThreshold(int threshold) +{ +} bool wxJoystick::HasPOV() const -{ return false; } +{ + return false; +} bool wxJoystick::HasPOV4Dir() const -{ return false; } +{ + return false; +} bool wxJoystick::HasPOVCTS() const -{ return false; } +{ + return false; +} -//////////////////////////////////////////////////////////////////////////// -// Operations -//////////////////////////////////////////////////////////////////////////// +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// wxHIDJoystick +// +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -bool wxJoystick::SetCapture(wxWindow* win, int pollingFreq) +//--------------------------------------------------------------------------- +// wxHIDJoystick ctor +// +// Initializes the min/max members +//--------------------------------------------------------------------------- +wxHIDJoystick::wxHIDJoystick() : + m_nXMax(0), m_nYMax(0), m_nZMax(0), m_nRudderMax(0), m_nUMax(0), m_nVMax(0), + m_nXMin(0), m_nYMin(0), m_nZMin(0), m_nRudderMin(0), m_nUMin(0), m_nVMin(0) { - if (m_thread) - { - m_thread->m_catchwin = win; - m_thread->m_polling = pollingFreq; - return true; - } +} + +//--------------------------------------------------------------------------- +// wxHIDJoystick dtor +// +// Nothing... +//--------------------------------------------------------------------------- +wxHIDJoystick::~wxHIDJoystick() +{ +} + +//--------------------------------------------------------------------------- +// wxHIDJoystick::Create +// +// Creates the native HID device (joysticks are of either +// kHIDUsage_GD_Joystick or kHIDUsage_GD_GamePad) +//--------------------------------------------------------------------------- +bool wxHIDJoystick::Create(int nWhich) +{ + int nJoysticks = GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick); + + if (nWhich <= nJoysticks) + return wxHIDDevice::Create(kHIDPage_GenericDesktop, + kHIDUsage_GD_Joystick, + nWhich); + else + nWhich -= nJoysticks; + + int nGamePads = GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad); + + if (nWhich <= nGamePads) + return wxHIDDevice::Create(kHIDPage_GenericDesktop, + kHIDUsage_GD_GamePad, + nWhich); + else return false; } -bool wxJoystick::ReleaseCapture() +//--------------------------------------------------------------------------- +// wxHIDJoystick::BuildCookies +// wxHIDJoystick::MakeCookies +// +// Sets up the cookies for the HID device (called from Create) - as +// mentioned 0-40 are the buttons and 40-50 are the axes. +// +// MakeCookies is just a recursive function for each array within +// BuildCookies. +//--------------------------------------------------------------------------- +void wxHIDJoystick::BuildCookies(CFArrayRef Array) { - if (m_thread) + InitCookies(50, true); + + // + // I wasted two hours of my life on this line :( + // accidently removed it during some source cleaning... + // + MakeCookies(Array); + + //paranoid debugging stuff +#if 0 + for(int i = 0; i < 50; ++i) + wxPrintf(wxT("\nVAL #%i:[%i]"), i, m_pCookies[i]); +#endif +}//end buildcookies + +void wxHIDJoystick::MakeCookies(CFArrayRef Array) +{ + int i, nUsage, nPage; + + for (i = 0; i < CFArrayGetCount(Array); ++i) { - m_thread->m_catchwin = NULL; - m_thread->m_polling = 0; - return true; + const void* ref = CFDictionaryGetValue( + (CFDictionaryRef)CFArrayGetValueAtIndex(Array, i), + CFSTR(kIOHIDElementKey) + ); + + if (ref != NULL) + { + MakeCookies((CFArrayRef) ref); } - return false; + else + { + CFNumberGetValue( + (CFNumberRef) + CFDictionaryGetValue( + (CFDictionaryRef) CFArrayGetValueAtIndex(Array, i), + CFSTR(kIOHIDElementUsageKey) + ), + kCFNumberIntType, + &nUsage ); + + CFNumberGetValue( + (CFNumberRef) + CFDictionaryGetValue( + (CFDictionaryRef) CFArrayGetValueAtIndex(Array, i), + CFSTR(kIOHIDElementUsagePageKey) + ), + kCFNumberIntType, + &nPage ); + +#if 0 + wxLogSysError(wxT("[%i][%i]"), nUsage, nPage); +#endif + if (nPage == kHIDPage_Button && nUsage <= 40) + AddCookieInQueue(CFArrayGetValueAtIndex(Array, i), nUsage-1 ); + else if (nPage == kHIDPage_GenericDesktop) + { + //axis... + switch(nUsage) + { + case kHIDUsage_GD_X: + AddCookieInQueue(CFArrayGetValueAtIndex(Array, i), wxJS_AXIS_X); + wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i), + CFSTR(kIOHIDElementMaxKey), + &m_nXMax); + wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i), + CFSTR(kIOHIDElementMinKey), + &m_nXMin); + break; + case kHIDUsage_GD_Y: + AddCookieInQueue(CFArrayGetValueAtIndex(Array, i), wxJS_AXIS_Y); + wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i), + CFSTR(kIOHIDElementMaxKey), + &m_nYMax); + wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i), + CFSTR(kIOHIDElementMinKey), + &m_nYMin); + break; + case kHIDUsage_GD_Z: + AddCookieInQueue(CFArrayGetValueAtIndex(Array, i), wxJS_AXIS_Z); + wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i), + CFSTR(kIOHIDElementMaxKey), + &m_nZMax); + wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i), + CFSTR(kIOHIDElementMinKey), + &m_nZMin); + break; + default: + break; + } + } + else if (nPage == kHIDPage_Simulation && nUsage == kHIDUsage_Sim_Rudder) + { + //rudder... + AddCookieInQueue(CFArrayGetValueAtIndex(Array, i), wxJS_AXIS_RUDDER ); + wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i), + CFSTR(kIOHIDElementMaxKey), + &m_nRudderMax); + wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i), + CFSTR(kIOHIDElementMinKey), + &m_nRudderMin); + } + } + } +} + +//--------------------------------------------------------------------------- +// wxHIDJoystick::Get[XXX] +// +// Simple accessors so that the HID callback and the thread procedure +// can access members from wxHIDDevice (our parent here). +//--------------------------------------------------------------------------- +IOHIDElementCookie* wxHIDJoystick::GetCookies() +{ return m_pCookies; } +IOHIDQueueInterface** wxHIDJoystick::GetQueue() +{ return m_ppQueue; } + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// wxJoystickThread +// +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +//--------------------------------------------------------------------------- +// wxJoystickThread Constructor +// +// Just initializes members +//--------------------------------------------------------------------------- +wxJoystickThread::wxJoystickThread(wxHIDJoystick* hid, int joystick) + : m_hid(hid), + m_joystick(joystick), + m_lastposition(127,127), + m_buttons(0), + m_catchwin(NULL), + m_polling(0) +{ + memset(m_axe, 0, sizeof(int) * wxJS_MAX_AXES); } + +//--------------------------------------------------------------------------- +// wxJoystickThread::Entry +// +// Thread procedure +// +// Runs a CFRunLoop for polling. Basically, it sets the HID queue to +// call wxJoystickThread::HIDCallback in the context of this thread +// when something changes on the device. It polls as long as the user +// wants, or a certain amount if the user wants to "block". Note that +// we don't actually block here since this is in a secondary thread. +//--------------------------------------------------------------------------- +void* wxJoystickThread::Entry() +{ + CFRunLoopSourceRef pRLSource = NULL; + + if ((*m_hid->GetQueue())->createAsyncEventSource( + m_hid->GetQueue(), &pRLSource) != kIOReturnSuccess ) + { + wxLogSysError(wxT("Couldn't create async event source")); + return NULL; + } + + wxASSERT(pRLSource != NULL); + + //attach runloop source to main run loop in thread + CFRunLoopRef pRL = CFRunLoopGetCurrent(); + CFRunLoopAddSource(pRL, pRLSource, kCFRunLoopDefaultMode); + wxASSERT( CFRunLoopContainsSource(pRL, pRLSource, kCFRunLoopDefaultMode) ); + + + if( (*m_hid->GetQueue())->setEventCallout(m_hid->GetQueue(), + wxJoystickThread::HIDCallback, this, this) != kIOReturnSuccess ) + { + wxLogSysError(wxT("Could not set event callout for queue")); + return NULL; + } + + if( (*m_hid->GetQueue())->start(m_hid->GetQueue()) != kIOReturnSuccess ) + { + wxLogSysError(wxT("Could not start queue")); + return NULL; + } + + double dTime; + + while(true) + { + if (TestDestroy()) + break; + + if (m_polling) + dTime = 0.0001 * m_polling; + else + dTime = 0.0001 * 10; // check at least every 10 msec in "blocking" case + + //true just "handles and returns" - false forces it to stay the time + //amount +#if 1 + CFRunLoopRunInMode(kCFRunLoopDefaultMode, dTime, true); +#else + IOReturn ret = NULL; + HIDCallback(this, ret, this, this); + Sleep(3000); #endif - //OSX - + } + + wxASSERT( CFRunLoopContainsSource(pRL, pRLSource, kCFRunLoopDefaultMode) ); + + CFRunLoopRemoveSource(pRL, pRLSource, kCFRunLoopDefaultMode); + CFRelease(pRLSource); + + return NULL; +} + +//--------------------------------------------------------------------------- +// wxJoystickThread::HIDCallback (static) +// +// Callback for the native HID device when it recieves input. +// +// This is where the REAL dirty work gets done. +// +// 1) Loops through each event the queue has recieved +// 2) First, checks if the thread that is running the loop for +// the polling has ended - if so it breaks out +// 3) Next, it checks if there was an error getting this event from +// the HID queue, if there was, it logs an error and returns +// 4) Now it does the real dirty work by getting the button states +// from cookies 0-40 and axes positions/states from cookies 40-50 +// in the native HID device by quering cookie values. +// 5) Sends the event to the polling window (if any) +// 6) Gets the next event and goes back to (1) +//--------------------------------------------------------------------------- +/*static*/ void wxJoystickThread::HIDCallback(void* target, IOReturn res, + void* context, void* sender) +{ + IOHIDEventStruct hidevent; + AbsoluteTime bogustime = {0,0}; + IOReturn ret; + wxJoystickThread* pThis = (wxJoystickThread*) context; + wxHIDJoystick* m_hid = pThis->m_hid; + + //Get the "first" event from the queue + //bogustime tells it we don't care at what time to start + //where it gets the next from + ret = (*m_hid->GetQueue())->getNextEvent(m_hid->GetQueue(), + &hidevent, bogustime, 0); + + while (ret != kIOReturnUnderrun) + { + if (pThis->TestDestroy()) + break; + + if(ret != kIOReturnSuccess) + { + wxLogSysError(wxString::Format(wxT("wxJoystick Error:[%i]"), ret)); + return; + } + + wxJoystickEvent wxevent; + + //Find the cookie that changed + int nIndex = 0; + IOHIDElementCookie* pCookies = m_hid->GetCookies(); + while(nIndex < 50) + { + if(hidevent.elementCookie == pCookies[nIndex]) + break; + + ++nIndex; + } + + //debugging stuff +#if 0 + if(nIndex == 50) + { + wxLogSysError(wxString::Format(wxT("wxJoystick Out Of Bounds Error"))); + break; + } #endif - // wxUSE_JOYSTICK + //is the cookie a button? + if (nIndex < 40) + { + if (hidevent.value) + { + pThis->m_buttons |= (1 << nIndex); + wxevent.SetEventType(wxEVT_JOY_BUTTON_DOWN); + } + else + { + pThis->m_buttons &= ~(1 << nIndex); + wxevent.SetEventType(wxEVT_JOY_BUTTON_UP); + } + + wxevent.SetButtonChange(nIndex+1); + } + else if (nIndex == wxJS_AXIS_X) + { + pThis->m_lastposition.x = hidevent.value; + wxevent.SetEventType(wxEVT_JOY_MOVE); + pThis->m_axe[0] = hidevent.value; + } + else if (nIndex == wxJS_AXIS_Y) + { + pThis->m_lastposition.y = hidevent.value; + wxevent.SetEventType(wxEVT_JOY_MOVE); + pThis->m_axe[1] = hidevent.value; + } + else if (nIndex == wxJS_AXIS_Z) + { + wxevent.SetEventType(wxEVT_JOY_ZMOVE); + pThis->m_axe[2] = hidevent.value; + } + else + wxevent.SetEventType(wxEVT_JOY_MOVE); + + Nanoseconds timestamp = AbsoluteToNanoseconds(hidevent.timestamp); + + wxULongLong llTime(timestamp.hi, timestamp.lo); + + llTime /= 1000000; + + wxevent.SetTimestamp(llTime.GetValue()); + wxevent.SetJoystick(pThis->m_joystick); + wxevent.SetButtonState(pThis->m_buttons); + wxevent.SetPosition(pThis->m_lastposition); + wxevent.SetZPosition(pThis->m_axe[2]); + wxevent.SetEventObject(pThis->m_catchwin); + + if (pThis->m_catchwin) + pThis->m_catchwin->AddPendingEvent(wxevent); + + ret = (*m_hid->GetQueue())->getNextEvent(m_hid->GetQueue(), + &hidevent, bogustime, 0); + } +} + +#endif // wxUSE_JOYSTICK && defined(__DARWIN__)