📄 hidjoystick.cpp
字号:
}
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;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// wxHIDJoystick
//
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//---------------------------------------------------------------------------
// 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)
{
}
//---------------------------------------------------------------------------
// 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;
}
//---------------------------------------------------------------------------
// 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)
{
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)
{
const void* ref = CFDictionaryGetValue(
(CFDictionaryRef)CFArrayGetValueAtIndex(Array, i),
CFSTR(kIOHIDElementKey)
);
if (ref != NULL)
{
MakeCookies((CFArrayRef) ref);
}
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
}
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
//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__)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -