mirror of https://github.com/encounter/SDL.git
WGI: Fix SDL_IsXInputDevice() for Xbox One controllers
The Xbox One driver stack doesn't propagate the VID/PID down to the HID devices that end up in the GetRawInputDeviceList() output. This means we end up matching against the wrong VID/PID and can't properly exclude Xbox One controllers from WGI. Fortunately, it is possible to walk back up the device tree to find the parent with the matching VID/PID.
This commit is contained in:
parent
dd85cc0195
commit
b3e909dc41
|
@ -31,6 +31,7 @@
|
||||||
#include "../../core/windows/SDL_windows.h"
|
#include "../../core/windows/SDL_windows.h"
|
||||||
#define COBJMACROS
|
#define COBJMACROS
|
||||||
#include "windows.gaming.input.h"
|
#include "windows.gaming.input.h"
|
||||||
|
#include <cfgmgr32.h>
|
||||||
|
|
||||||
|
|
||||||
struct joystick_hwdata
|
struct joystick_hwdata
|
||||||
|
@ -123,17 +124,68 @@ SDL_IsXInputDevice(Uint16 vendor, Uint16 product)
|
||||||
char devName[MAX_PATH];
|
char devName[MAX_PATH];
|
||||||
UINT rdiSize = sizeof(rdi);
|
UINT rdiSize = sizeof(rdi);
|
||||||
UINT nameSize = SDL_arraysize(devName);
|
UINT nameSize = SDL_arraysize(devName);
|
||||||
|
DEVINST devNode;
|
||||||
|
char devVidPidString[32];
|
||||||
|
int j;
|
||||||
|
|
||||||
rdi.cbSize = sizeof(rdi);
|
rdi.cbSize = sizeof(rdi);
|
||||||
if ((raw_devices[i].dwType == RIM_TYPEHID) &&
|
|
||||||
(GetRawInputDeviceInfoA(raw_devices[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != ((UINT)-1)) &&
|
if ((raw_devices[i].dwType != RIM_TYPEHID) ||
|
||||||
(MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) == vidpid) &&
|
(GetRawInputDeviceInfoA(raw_devices[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) == ((UINT)-1)) ||
|
||||||
(GetRawInputDeviceInfoA(raw_devices[i].hDevice, RIDI_DEVICENAME, devName, &nameSize) != ((UINT)-1)) &&
|
(GetRawInputDeviceInfoA(raw_devices[i].hDevice, RIDI_DEVICENAME, devName, &nameSize) == ((UINT)-1)) ||
|
||||||
(SDL_strstr(devName, "IG_") != NULL)) {
|
(SDL_strstr(devName, "IG_") == NULL)) {
|
||||||
|
/* Skip non-XInput devices */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* First check for a simple VID/PID match. This will work for Xbox 360 controllers. */
|
||||||
|
if (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) == vidpid) {
|
||||||
|
SDL_free(raw_devices);
|
||||||
return SDL_TRUE;
|
return SDL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* For Xbox One controllers, Microsoft doesn't propagate the VID/PID down to the HID stack.
|
||||||
|
* We'll have to walk the device tree upwards searching for a match for our VID/PID. */
|
||||||
|
|
||||||
|
/* Make sure the device interface string is something we know how to parse */
|
||||||
|
/* Example: \\?\HID#VID_045E&PID_02FF&IG_00#9&2c203035&2&0000#{4d1e55b2-f16f-11cf-88cb-001111000030} */
|
||||||
|
if ((SDL_strstr(devName, "\\\\?\\") != devName) || (SDL_strstr(devName, "#{") == NULL)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unescape the backslashes in the string and terminate before the GUID portion */
|
||||||
|
for (j = 0; devName[j] != '\0'; j++) {
|
||||||
|
if (devName[j] == '#') {
|
||||||
|
if (devName[j + 1] == '{') {
|
||||||
|
devName[j] = '\0';
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
devName[j] = '\\';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We'll be left with a string like this: \\?\HID\VID_045E&PID_02FF&IG_00\9&2c203035&2&0000
|
||||||
|
* Simply skip the \\?\ prefix and we'll have a properly formed device instance ID */
|
||||||
|
if (CM_Locate_DevNodeA(&devNode, &devName[4], CM_LOCATE_DEVNODE_NORMAL) != CR_SUCCESS) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_snprintf(devVidPidString, sizeof(devVidPidString), "VID_%04X&PID_%04X", vendor, product);
|
||||||
|
|
||||||
|
while (CM_Get_Parent(&devNode, devNode, 0) == CR_SUCCESS) {
|
||||||
|
char deviceId[MAX_DEVICE_ID_LEN];
|
||||||
|
|
||||||
|
if ((CM_Get_Device_IDA(devNode, deviceId, SDL_arraysize(deviceId), 0) == CR_SUCCESS) &&
|
||||||
|
(SDL_strstr(deviceId, devVidPidString) != NULL)) {
|
||||||
|
/* The VID/PID matched a parent device */
|
||||||
|
SDL_free(raw_devices);
|
||||||
|
return SDL_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDL_free(raw_devices);
|
||||||
return SDL_FALSE;
|
return SDL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue