Remember XInput controllers that we've already seen, so when the raw device list changes we don't assign the old device to the new XInput userid.

This isn't perfect, but at least we won't report the same device twice.
This commit is contained in:
Sam Lantinga 2017-02-02 17:33:40 -08:00
parent da30992d47
commit 710ae62a79

View file

@ -33,6 +33,7 @@
* Internal stuff.
*/
static SDL_bool s_bXInputEnabled = SDL_TRUE;
static char *s_arrXInputDevicePath[XUSER_MAX_COUNT];
static SDL_bool
@ -113,12 +114,12 @@ GetXInputName(const Uint8 userid, BYTE SubType)
and we'll be correct for the case where only one device is connected.
*/
static void
GuessXInputDevice(UINT device_index, Uint16 *pVID, Uint16 *pPID, Uint16 *pVersion)
GuessXInputDevice(Uint8 userid, Uint16 *pVID, Uint16 *pPID, Uint16 *pVersion)
{
#ifndef __WINRT__ /* TODO: remove this ifndef __WINRT__ block, but only after integrating with UWP/WinRT's HID API */
PRAWINPUTDEVICELIST devices = NULL;
UINT i, found_count = 0, device_count = 0;
UINT i, j, found_count = 0, device_count = 0;
if ((GetRawInputDeviceList(NULL, &device_count, sizeof(RAWINPUTDEVICELIST)) == -1) || (!device_count)) {
return; /* oh well. */
@ -145,16 +146,36 @@ GuessXInputDevice(UINT device_index, Uint16 *pVID, Uint16 *pPID, Uint16 *pVersio
(GetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != ((UINT)-1)) &&
(GetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICENAME, devName, &nameSize) != ((UINT)-1)) &&
(SDL_strstr(devName, "IG_") != NULL)) {
SDL_bool found = SDL_FALSE;
for (j = 0; j < SDL_arraysize(s_arrXInputDevicePath); ++j) {
if (j == userid) {
continue;
}
if (!s_arrXInputDevicePath[j]) {
continue;
}
if (SDL_strcmp(devName, s_arrXInputDevicePath[j]) == 0) {
found = SDL_TRUE;
break;
}
}
if (found) {
/* We already have this device in our XInput device list */
continue;
}
/* We don't actually know if this is the right device for this
* userid, but we'll record it so we'll at least be consistent
* when the raw device list changes.
*/
*pVID = (Uint16)rdi.hid.dwVendorId;
*pPID = (Uint16)rdi.hid.dwProductId;
*pVersion = (Uint16)rdi.hid.dwVersionNumber;
if (found_count++ == device_index) {
/* We don't really know the order of the devices relative to XInput,
but we'll guess that this is the correct one
*/
break;
if (s_arrXInputDevicePath[userid]) {
SDL_free(s_arrXInputDevicePath[userid]);
}
s_arrXInputDevicePath[userid] = SDL_strdup(devName);
break;
}
}
SDL_free(devices);
@ -290,14 +311,12 @@ SDL_XINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickde
static void
UpdateXInputJoystickBatteryInformation(SDL_Joystick * joystick, XINPUT_BATTERY_INFORMATION_EX *pBatteryInformation)
{
if ( pBatteryInformation->BatteryType != BATTERY_TYPE_UNKNOWN )
{
if (pBatteryInformation->BatteryType != BATTERY_TYPE_UNKNOWN) {
SDL_JoystickPowerLevel ePowerLevel = SDL_JOYSTICK_POWER_UNKNOWN;
if (pBatteryInformation->BatteryType == BATTERY_TYPE_WIRED) {
ePowerLevel = SDL_JOYSTICK_POWER_WIRED;
} else {
switch ( pBatteryInformation->BatteryLevel )
{
switch (pBatteryInformation->BatteryLevel) {
case BATTERY_LEVEL_EMPTY:
ePowerLevel = SDL_JOYSTICK_POWER_EMPTY;
break;
@ -314,7 +333,7 @@ UpdateXInputJoystickBatteryInformation(SDL_Joystick * joystick, XINPUT_BATTERY_I
}
}
SDL_PrivateJoystickBatteryLevel( joystick, ePowerLevel );
SDL_PrivateJoystickBatteryLevel(joystick, ePowerLevel);
}
}
@ -342,7 +361,7 @@ UpdateXInputJoystickState_OLD(SDL_Joystick * joystick, XINPUT_STATE_EX *pXInputS
SDL_PrivateJoystickButton(joystick, button, (wButtons & s_XInputButtons[button]) ? SDL_PRESSED : SDL_RELEASED);
}
UpdateXInputJoystickBatteryInformation( joystick, pBatteryInformation );
UpdateXInputJoystickBatteryInformation(joystick, pBatteryInformation);
}
static void
@ -383,7 +402,7 @@ UpdateXInputJoystickState(SDL_Joystick * joystick, XINPUT_STATE_EX *pXInputState
}
SDL_PrivateJoystickHat(joystick, 0, hat);
UpdateXInputJoystickBatteryInformation( joystick, pBatteryInformation );
UpdateXInputJoystickBatteryInformation(joystick, pBatteryInformation);
}
void
@ -398,15 +417,20 @@ SDL_XINPUT_JoystickUpdate(SDL_Joystick * joystick)
result = XINPUTGETSTATE(joystick->hwdata->userid, &XInputState);
if (result == ERROR_DEVICE_NOT_CONNECTED) {
Uint8 userid = joystick->hwdata->userid;
joystick->hwdata->send_remove_event = SDL_TRUE;
joystick->hwdata->removed = SDL_TRUE;
if (s_arrXInputDevicePath[userid]) {
SDL_free(s_arrXInputDevicePath[userid]);
s_arrXInputDevicePath[userid] = NULL;
}
return;
}
SDL_zero( XBatteryInformation );
if ( XINPUTGETBATTERYINFORMATION )
{
result = XINPUTGETBATTERYINFORMATION( joystick->hwdata->userid, BATTERY_DEVTYPE_GAMEPAD, &XBatteryInformation );
SDL_zero(XBatteryInformation);
if (XINPUTGETBATTERYINFORMATION) {
result = XINPUTGETBATTERYINFORMATION(joystick->hwdata->userid, BATTERY_DEVTYPE_GAMEPAD, &XBatteryInformation);
}
/* only fire events if the data changed from last time */