Changes to DirectInputSystem:

- corrected axis identification code as was not enumerating axes properly in all cases
- added fallback which just adds all axes if there is any hint of an irregularity whilst enumerating axes
This commit is contained in:
Nik Henson 2011-09-21 22:08:36 +00:00
parent 71cef1aad0
commit c0dc0b83b6
2 changed files with 77 additions and 41 deletions

View file

@ -186,7 +186,7 @@ DIKeyMapStruct CDirectInputSystem::s_keyMap[] =
//{ "UNDO", ?? }, //{ "UNDO", ?? },
}; };
bool IsXInputDevice(const GUID &devProdGUID) static bool IsXInputDevice(const GUID &devProdGUID)
{ {
// Following code taken from MSDN // Following code taken from MSDN
IWbemLocator* pIWbemLocator = NULL; IWbemLocator* pIWbemLocator = NULL;
@ -285,42 +285,72 @@ Finish:
return isXInpDev; return isXInpDev;
} }
BOOL CALLBACK DI8EnumDevicesCallback(LPCDIDEVICEINSTANCE instance, LPVOID context) struct DIEnumDevsContext
{
vector<DIJoyInfo> *infos;
bool useXInput;
};
static BOOL CALLBACK DI8EnumDevicesCallback(LPCDIDEVICEINSTANCE instance, LPVOID context)
{ {
// Keep track of all joystick device GUIDs // Keep track of all joystick device GUIDs
DIEnumDevsContext *diContext = (DIEnumDevsContext*)context; DIEnumDevsContext *diDevsContext = (DIEnumDevsContext*)context;
DIJoyInfo info; DIJoyInfo info;
memset(&info, 0, sizeof(DIJoyInfo)); memset(&info, 0, sizeof(DIJoyInfo));
info.guid = instance->guidInstance; info.guid = instance->guidInstance;
// If XInput is enabled, see if device is an XInput device // If XInput is enabled, see if device is an XInput device
info.isXInput = diContext->useXInput && IsXInputDevice(instance->guidProduct); info.isXInput = diDevsContext->useXInput && IsXInputDevice(instance->guidProduct);
diContext->infos->push_back(info); diDevsContext->infos->push_back(info);
return DIENUM_CONTINUE; return DIENUM_CONTINUE;
} }
BOOL CALLBACK DI8EnumAxesCallback(LPCDIDEVICEOBJECTINSTANCE instance, LPVOID context) struct DIEnumAxesContext
{ {
// Workout which axis is currently being enumerated JoyDetails *joyDetails;
int objNum = DIDFT_GETINSTANCE(instance->dwType); bool enumError;
DIOBJECTDATAFORMAT fmt = c_dfDIJoystick2.rgodf[objNum]; };
static BOOL CALLBACK DI8EnumAxesCallback(LPCDIDEVICEOBJECTINSTANCE instance, LPVOID context)
{
// Work out which axis is currently being enumerated from the GUID
DIEnumAxesContext *diAxesContext = (DIEnumAxesContext*)context;
int axisNum; int axisNum;
switch (fmt.dwOfs) if (instance->guidType == GUID_XAxis) axisNum = AXIS_X;
else if (instance->guidType == GUID_YAxis) axisNum = AXIS_Y;
else if (instance->guidType == GUID_ZAxis) axisNum = AXIS_Z;
else if (instance->guidType == GUID_RxAxis) axisNum = AXIS_RX;
else if (instance->guidType == GUID_RyAxis) axisNum = AXIS_RY;
else if (instance->guidType == GUID_RzAxis) axisNum = AXIS_RZ;
else
{ {
case DIJOFS_X: axisNum = AXIS_X; break; // If couldn't match GUID (which, according to MSDN, is an optional attribute), then flag error and try matching using a different method
case DIJOFS_Y: axisNum = AXIS_Y; break; diAxesContext->enumError = true;
case DIJOFS_Z: axisNum = AXIS_Z; break; int objNum = DIDFT_GETINSTANCE(instance->dwType);
case DIJOFS_RX: axisNum = AXIS_RX; break; DIOBJECTDATAFORMAT fmt = c_dfDIJoystick2.rgodf[objNum];
case DIJOFS_RY: axisNum = AXIS_RY; break; switch (fmt.dwOfs)
case DIJOFS_RZ: axisNum = AXIS_RZ; break; {
default: return DIENUM_CONTINUE; case DIJOFS_X: axisNum = AXIS_X; break;
case DIJOFS_Y: axisNum = AXIS_Y; break;
case DIJOFS_Z: axisNum = AXIS_Z; break;
case DIJOFS_RX: axisNum = AXIS_RX; break;
case DIJOFS_RY: axisNum = AXIS_RY; break;
case DIJOFS_RZ: axisNum = AXIS_RZ; break;
default:
// If still couldn't match then it is not an axis
return DIENUM_CONTINUE;
}
} }
// If axis overlaps with a previous ones, flag error
JoyDetails *joyDetails = diAxesContext->joyDetails;
if (joyDetails->hasAxis[axisNum])
diAxesContext->enumError = true;
// Record fact that axis is present and also whether it has force feedback available // Record fact that axis is present and also whether it has force feedback available
JoyDetails *joyDetails = (JoyDetails*)context;
joyDetails->hasAxis[axisNum] = true; joyDetails->hasAxis[axisNum] = true;
joyDetails->axisHasFF[axisNum] = !!(instance->dwFlags & DIDOI_FFACTUATOR); joyDetails->axisHasFF[axisNum] = !!(instance->dwFlags & DIDOI_FFACTUATOR);
// Get axis name from DirectInput // Get axis name from DirectInput and store that too
char *axisName = joyDetails->axisName[axisNum]; char *axisName = joyDetails->axisName[axisNum];
strcpy(axisName, CInputSystem::GetDefaultAxisName(axisNum)); strcpy(axisName, CInputSystem::GetDefaultAxisName(axisNum));
strcat(axisName, "-Axis ("); strcat(axisName, "-Axis (");
@ -330,10 +360,10 @@ BOOL CALLBACK DI8EnumAxesCallback(LPCDIDEVICEOBJECTINSTANCE instance, LPVOID con
return DIENUM_CONTINUE; return DIENUM_CONTINUE;
} }
BOOL CALLBACK DI8EnumEffectsCallback(LPCDIEFFECTINFO effectInfo, LPVOID context) static BOOL CALLBACK DI8EnumEffectsCallback(LPCDIEFFECTINFO effectInfo, LPVOID context)
{ {
JoyDetails *joyDetails = (JoyDetails*)context;
// Check joystick has at least one of required types of effects // Check joystick has at least one of required types of effects
JoyDetails *joyDetails = (JoyDetails*)context;
if (!!(effectInfo->dwEffType & (DIEFT_CONSTANTFORCE | DIEFT_PERIODIC | DIEFT_CONDITION))) if (!!(effectInfo->dwEffType & (DIEFT_CONSTANTFORCE | DIEFT_PERIODIC | DIEFT_CONDITION)))
joyDetails->hasFFeedback = true; joyDetails->hasFFeedback = true;
return DIENUM_CONTINUE; return DIENUM_CONTINUE;
@ -988,11 +1018,11 @@ void CDirectInputSystem::ProcessRawInput(HRAWINPUT hInput)
void CDirectInputSystem::OpenJoysticks() void CDirectInputSystem::OpenJoysticks()
{ {
// Get the info about all attached joystick devices // Get the info about all attached joystick devices
DIEnumDevsContext diContext; DIEnumDevsContext diDevsContext;
diContext.infos = &m_diJoyInfos; diDevsContext.infos = &m_diJoyInfos;
diContext.useXInput = m_useXInput; diDevsContext.useXInput = m_useXInput;
HRESULT hr; HRESULT hr;
if (FAILED(hr = m_di8->EnumDevices(DI8DEVCLASS_GAMECTRL, DI8EnumDevicesCallback, &diContext, DIEDFL_ATTACHEDONLY))) if (FAILED(hr = m_di8->EnumDevices(DI8DEVCLASS_GAMECTRL, DI8EnumDevicesCallback, &diDevsContext, DIEDFL_ATTACHEDONLY)))
return; return;
// Loop through those found // Loop through those found
@ -1079,13 +1109,34 @@ void CDirectInputSystem::OpenJoysticks()
joyDetails.numButtons = devCaps.dwButtons; joyDetails.numButtons = devCaps.dwButtons;
// Enumerate axes // Enumerate axes
if (FAILED(hr = joystick->EnumObjects(DI8EnumAxesCallback, &joyDetails, DIDFT_AXIS))) DIEnumAxesContext diAxesContext;
diAxesContext.joyDetails = &joyDetails;
diAxesContext.enumError = false;
if (FAILED(hr = joystick->EnumObjects(DI8EnumAxesCallback, &diAxesContext, DIDFT_AXIS)))
{ {
ErrorLog("Unable to enumerate axes of DirectInput joystick %d (error %d) - skipping joystick.\n", joyNum, hr); ErrorLog("Unable to enumerate axes of DirectInput joystick %d (error %d) - skipping joystick.\n", joyNum, hr);
joystick->Release(); joystick->Release();
continue; continue;
} }
// If enumeration failed for some reason then include all possible joystick axes so that no axis is left off due to error
if (diAxesContext.enumError)
{
for (int axisNum = 0; axisNum < NUM_JOY_AXES; axisNum++)
{
if (!joyDetails.hasAxis[axisNum])
{
joyDetails.hasAxis[axisNum] = true;
joyDetails.axisHasFF[axisNum] = false;
char *axisName = joyDetails.axisName[axisNum];
strcpy(axisName, CInputSystem::GetDefaultAxisName(axisNum));
strcat(axisName, "-Axis");
}
}
}
// Count number of axes
joyDetails.numAxes = 0; joyDetails.numAxes = 0;
for (int axisNum = 0; axisNum < NUM_JOY_AXES; axisNum++) for (int axisNum = 0; axisNum < NUM_JOY_AXES; axisNum++)
joyDetails.numAxes += joyDetails.hasAxis[axisNum]; joyDetails.numAxes += joyDetails.hasAxis[axisNum];

View file

@ -91,12 +91,6 @@ struct DIJoyInfo
WORD xiVibrateBoth; WORD xiVibrateBoth;
}; };
struct DIEnumDevsContext
{
vector<DIJoyInfo> *infos;
bool useXInput;
};
// RawInput API // RawInput API
typedef /*WINUSERAPI*/ INT (WINAPI *GetRawInputDeviceListPtr)(OUT PRAWINPUTDEVICELIST pRawInputDeviceList, IN OUT PUINT puiNumDevices, IN UINT cbSize); typedef /*WINUSERAPI*/ INT (WINAPI *GetRawInputDeviceListPtr)(OUT PRAWINPUTDEVICELIST pRawInputDeviceList, IN OUT PUINT puiNumDevices, IN UINT cbSize);
typedef /*WINUSERAPI*/ INT (WINAPI *GetRawInputDeviceInfoPtr)(IN HANDLE hDevice, IN UINT uiCommand, OUT LPVOID pData, IN OUT PUINT pcbSize); typedef /*WINUSERAPI*/ INT (WINAPI *GetRawInputDeviceInfoPtr)(IN HANDLE hDevice, IN UINT uiCommand, OUT LPVOID pData, IN OUT PUINT pcbSize);
@ -108,15 +102,6 @@ typedef /*WINUSERAPI*/ DWORD (WINAPI *XInputGetCapabilitiesPtr)(IN DWORD dwUserI
typedef /*WINUSERAPI*/ DWORD (WINAPI *XInputGetStatePtr)(IN DWORD dwUserIndex, OUT PXINPUT_STATE pState); typedef /*WINUSERAPI*/ DWORD (WINAPI *XInputGetStatePtr)(IN DWORD dwUserIndex, OUT PXINPUT_STATE pState);
typedef /*WINUSERAPI*/ DWORD (WINAPI *XInputSetStatePtr)(IN DWORD dwUserIndex, IN PXINPUT_VIBRATION pVibration); typedef /*WINUSERAPI*/ DWORD (WINAPI *XInputSetStatePtr)(IN DWORD dwUserIndex, IN PXINPUT_VIBRATION pVibration);
// DirectInput callbacks
static bool IsXInputDevice(const GUID &devProdGUID);
static BOOL CALLBACK DI8EnumDevicesCallback(LPCDIDEVICEINSTANCE instance, LPVOID context);
static BOOL CALLBACK DI8EnumAxesCallback(LPDIDEVICEOBJECTINSTANCE instance, LPVOID context);
static BOOL CALLBACK DI8EnumEffectsCallback(LPCDIEFFECTINFO effectInfo, LPVOID context);
/* /*
* Input system that uses combination of DirectInput, XInput and RawInput APIs. * Input system that uses combination of DirectInput, XInput and RawInput APIs.
*/ */