From ce0d1032d1c9e63bd034575542c5ee4337ab3510 Mon Sep 17 00:00:00 2001 From: Stefan Csomor Date: Wed, 2 Nov 2005 15:22:39 +0000 Subject: [PATCH] applying patch 1345435 git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@36060 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/mac/corefoundation/hid.h | 9 +- src/mac/corefoundation/hid.cpp | 3 +- src/mac/corefoundation/hidjoystick.cpp | 899 +++++++++++++++---------- 3 files changed, 552 insertions(+), 359 deletions(-) diff --git a/include/wx/mac/corefoundation/hid.h b/include/wx/mac/corefoundation/hid.h index 33b01d54df..9d138c301f 100644 --- a/include/wx/mac/corefoundation/hid.h +++ b/include/wx/mac/corefoundation/hid.h @@ -35,7 +35,14 @@ #include #include -#include +//Darn apple - doesn't properly wrap their headers in extern "C"! +//http://www.macosx.com/forums/archive/index.php/t-68069.html +//Needed for codewarrior link error with mach_port_deallocate() +extern "C" { +#include +} + +#include //this actually includes mach_port.h (see above) //Utility wrapper around CFArray class wxCFArray diff --git a/src/mac/corefoundation/hid.cpp b/src/mac/corefoundation/hid.cpp index 8cd855282a..bc107d9f8b 100644 --- a/src/mac/corefoundation/hid.cpp +++ b/src/mac/corefoundation/hid.cpp @@ -111,7 +111,8 @@ bool wxHIDDevice::Create (int nClass, int nType, int nDev) //Now get the maching services io_iterator_t pIterator; wxIOCHECK(IOServiceGetMatchingServices(m_pPort, pDictionary, &pIterator), "No Matching HID Services"); - wxASSERT_MSG(pIterator != 0, wxT("No devices found!")); + if(pIterator == 0) + return false; // No devices found //Now we iterate through them io_object_t pObject; diff --git a/src/mac/corefoundation/hidjoystick.cpp b/src/mac/corefoundation/hidjoystick.cpp index 0216bf347c..4d104a44f4 100644 --- a/src/mac/corefoundation/hidjoystick.cpp +++ b/src/mac/corefoundation/hidjoystick.cpp @@ -9,26 +9,53 @@ // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// +//=========================================================================== +// DECLARATIONS +//=========================================================================== + +//--------------------------------------------------------------------------- +// Pre-compiled header stuff +//--------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" -#ifdef __DARWIN__ +//--------------------------------------------------------------------------- +// Guard +//--------------------------------------------------------------------------- -#if wxUSE_JOYSTICK +//we only support HID on OSX (DARWIN), since it requires DARWIN... +#if wxUSE_JOYSTICK && defined(__DARWIN__) -#include "wx/event.h" -#include "wx/log.h" -#include "wx/joystick.h" -#include "wx/thread.h" -#include "wx/window.h" +//--------------------------------------------------------------------------- +// Includes +//--------------------------------------------------------------------------- +#include "wx/event.h" //joystick wxEvents +#include "wx/log.h" //logging... +#include "wx/joystick.h" //... +#include "wx/thread.h" //wxThread for polling thread/ wxCriticalSection +#include "wx/window.h" //for wxWindow to "capture" joystick -#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, @@ -36,223 +63,41 @@ enum { wxJS_AXIS_U, wxJS_AXIS_V, + //For the Get[XXX](Min/Max) functions 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;} + IOHIDElementCookie* GetCookies(); + IOHIDQueueInterface** GetQueue(); friend class wxJoystick; }; - -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); - - 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 -//////////////////////////////////////////////////////////////////////////// - +//--------------------------------------------------------------------------- +// wxJoystickThread +//--------------------------------------------------------------------------- class wxJoystickThread : public wxThread { public: wxJoystickThread(wxHIDJoystick* hid, int joystick); void* Entry(); - - 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(); - } - } + static void HIDCallback(void* target, IOReturn res, void* context, void* sender); 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; @@ -260,63 +105,25 @@ 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() -{ - 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; -} - +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// 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) @@ -336,7 +143,12 @@ wxJoystick::wxJoystick(int joystick) } } - +//--------------------------------------------------------------------------- +// wxJoystick Destructor +// +// Releases the capture of the thread, deletes it, and deletes +// the native implementation. +//--------------------------------------------------------------------------- wxJoystick::~wxJoystick() { ReleaseCapture(); @@ -347,52 +159,36 @@ wxJoystick::~wxJoystick() 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) @@ -400,50 +196,54 @@ 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; } - -int wxJoystick::GetNumberJoysticks() const -{ return wxHIDDevice::GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick) + - wxHIDDevice::GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad); } +{ + return m_hid != NULL; +} +//--------------------------------------------------------------------------- +// wxJoystick::Get[XXX](Id/Name) +// +// Simple accessors to the native HID implementation +//--------------------------------------------------------------------------- int wxJoystick::GetManufacturerId() const { return m_hid->m_nManufacturerId; } - int wxJoystick::GetProductId() const { 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; } - +//--------------------------------------------------------------------------- +// 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; @@ -456,7 +256,6 @@ int wxJoystick::GetNumberButtons() const return nCount; } - int wxJoystick::GetNumberAxes() const { int nCount = 0; @@ -470,88 +269,474 @@ int wxJoystick::GetNumberAxes() const return nCount; } +//--------------------------------------------------------------------------- +// wxJoystick::GetNumberJoysticks // -// internal -// -int wxJoystick::GetMaxButtons() const -{ return 15; } - -int wxJoystick::GetMaxAxes() const -{ return 10; } +// 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() const +{ + return + wxHIDDevice::GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick) + + wxHIDDevice::GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad); +} -int wxJoystick::GetPollingMin() const -{ return 10; } +//--------------------------------------------------------------------------- +// wxJoystick::SetCapture +// +// 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::GetPollingMax() const -{ return 1000; } +//--------------------------------------------------------------------------- +// 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::GetRudderMin() const +//--------------------------------------------------------------------------- +// wxJoystick::Get[XXX] +// +// All values in hid range from 0 to 255, making these all kind of +// superflous. These are mainly here due to the msw-centric api +// that wxJoystick has... it should REALLY do its own scaling... oh well :) +//--------------------------------------------------------------------------- +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::GetRudderMax() const -{ return wxJS_AXIS_MAX; } - int wxJoystick::GetUMin() const { return wxJS_AXIS_MIN; } - -int wxJoystick::GetUMax() const -{ return wxJS_AXIS_MAX; } - int wxJoystick::GetVMin() const { return wxJS_AXIS_MIN; } +int wxJoystick::GetRudderMin() 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; } +int wxJoystick::GetUMax() const +{ return wxJS_AXIS_MAX; } int wxJoystick::GetVMax() const { return wxJS_AXIS_MAX; } +int wxJoystick::GetRudderMax() const +{ return wxJS_AXIS_MAX; } + +//--------------------------------------------------------------------------- +// 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::HasRudder() const { return m_hid->HasElement(wxJS_AXIS_RUDDER); } - bool wxJoystick::HasZ() const { return m_hid->HasElement(wxJS_AXIS_Z); } - bool wxJoystick::HasU() const { return m_hid->HasElement(wxJS_AXIS_U); } - bool wxJoystick::HasV() const { 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; } - bool wxJoystick::HasPOV4Dir() const { return false; } - bool wxJoystick::HasPOVCTS() const { return false; } -//////////////////////////////////////////////////////////////////////////// -// Operations -//////////////////////////////////////////////////////////////////////////// +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// wxHIDJoystick +// +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -bool wxJoystick::SetCapture(wxWindow* win, int pollingFreq) +//--------------------------------------------------------------------------- +// wxHIDJoystick::Create +// +// Creates the native HID device (joysticks are of either +// kHIDUsage_GD_Joystick or kHIDUsage_GD_GamePad) +//--------------------------------------------------------------------------- +bool wxHIDJoystick::Create(int nWhich) { - if (m_thread) - { - m_thread->m_catchwin = win; - m_thread->m_polling = pollingFreq; - return true; - } + 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; } -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(wxCFArray& Array) { - if (m_thread) + Array = CFDictionaryGetValue((CFDictionaryRef)Array[0], CFSTR(kIOHIDElementKey)); + InitCookies(50, true); + + memset(m_pCookies, 0, sizeof(*m_pCookies) * 50); + + // + // 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(wxCFArray& Array) +{ + int i, nUsage, nPage; + + for (i = 0; i < Array.Count(); ++i) { - m_thread->m_catchwin = NULL; - m_thread->m_polling = 0; - return true; + const void* ref = CFDictionaryGetValue((CFDictionaryRef)Array[i], CFSTR(kIOHIDElementKey)); + + if (ref != NULL) + { + wxCFArray newarray(ref); + MakeCookies(newarray); } - return false; + else + { + CFNumberGetValue( + (CFNumberRef) CFDictionaryGetValue((CFDictionaryRef) Array[i], CFSTR(kIOHIDElementUsageKey)), + kCFNumberLongType, &nUsage); + + CFNumberGetValue( + (CFNumberRef) CFDictionaryGetValue((CFDictionaryRef) Array[i], CFSTR(kIOHIDElementUsagePageKey)), + kCFNumberLongType, &nPage); + +#if 0 + wxLogSysError(wxT("[%i][%i]"), nUsage, nPage); +#endif + 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 ); + } + } } + +//--------------------------------------------------------------------------- +// 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__) -- 2.45.2