|
@@ -235,45 +235,150 @@ SetDIerror(const char *function, HRESULT code)
|
|
|
return SDL_SetError("%s() DirectX error 0x%8.8lx", function, code);
|
|
|
}
|
|
|
|
|
|
+#if 0 /* Microsoft recommended implementation, but slower than checking raw devices */
|
|
|
+#define COBJMACROS
|
|
|
+#include <wbemidl.h>
|
|
|
+#include <oleauto.h>
|
|
|
+
|
|
|
+static const IID CLSID_WbemLocator = { 0x4590f811, 0x1d3a, 0x11d0,{ 0x89, 0x1f, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24 } };
|
|
|
+static const IID IID_IWbemLocator = { 0xdc12a687, 0x737f, 0x11cf,{ 0x88, 0x4d, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24 } };
|
|
|
+
|
|
|
static SDL_bool
|
|
|
-SDL_IsXInputDevice(const GUID* pGuidProductFromDirectInput)
|
|
|
+WIN_IsXInputDevice(const GUID* pGuidProductFromDirectInput)
|
|
|
{
|
|
|
- static GUID IID_ValveStreamingGamepad = { MAKELONG(0x28DE, 0x11FF), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
|
|
|
- static GUID IID_X360WiredGamepad = { MAKELONG(0x045E, 0x02A1), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
|
|
|
- static GUID IID_X360WirelessGamepad = { MAKELONG(0x045E, 0x028E), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
|
|
|
- static GUID IID_XOneWiredGamepad = { MAKELONG(0x045E, 0x02FF), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
|
|
|
- static GUID IID_XOneWirelessGamepad = { MAKELONG(0x045E, 0x02DD), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
|
|
|
- static GUID IID_XOneNewWirelessGamepad = { MAKELONG(0x045E, 0x02D1), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
|
|
|
- static GUID IID_XOneSWirelessGamepad = { MAKELONG(0x045E, 0x02EA), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
|
|
|
- static GUID IID_XOneSBluetoothGamepad = { MAKELONG(0x045E, 0x02E0), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
|
|
|
- static GUID IID_XOneEliteWirelessGamepad = { MAKELONG(0x045E, 0x02E3), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
|
|
|
-
|
|
|
- static const GUID *s_XInputProductGUID[] = {
|
|
|
- &IID_ValveStreamingGamepad,
|
|
|
- &IID_X360WiredGamepad, /* Microsoft's wired X360 controller for Windows. */
|
|
|
- &IID_X360WirelessGamepad, /* Microsoft's wireless X360 controller for Windows. */
|
|
|
- &IID_XOneWiredGamepad, /* Microsoft's wired Xbox One controller for Windows. */
|
|
|
- &IID_XOneWirelessGamepad, /* Microsoft's wireless Xbox One controller for Windows. */
|
|
|
- &IID_XOneNewWirelessGamepad, /* Microsoft's updated wireless Xbox One controller (w/ 3.5 mm jack) for Windows. */
|
|
|
- &IID_XOneSWirelessGamepad, /* Microsoft's wireless Xbox One S controller for Windows. */
|
|
|
- &IID_XOneSBluetoothGamepad, /* Microsoft's Bluetooth Xbox One S controller for Windows. */
|
|
|
- &IID_XOneEliteWirelessGamepad /* Microsoft's wireless Xbox One Elite controller for Windows. */
|
|
|
- };
|
|
|
+ IWbemLocator* pIWbemLocator = NULL;
|
|
|
+ IEnumWbemClassObject* pEnumDevices = NULL;
|
|
|
+ IWbemClassObject* pDevices[20];
|
|
|
+ IWbemServices* pIWbemServices = NULL;
|
|
|
+ BSTR bstrNamespace = NULL;
|
|
|
+ BSTR bstrDeviceID = NULL;
|
|
|
+ BSTR bstrClassName = NULL;
|
|
|
+ DWORD uReturned = 0;
|
|
|
+ SDL_bool bIsXinputDevice = SDL_FALSE;
|
|
|
+ UINT iDevice = 0;
|
|
|
+ VARIANT var;
|
|
|
+ HRESULT hr;
|
|
|
+
|
|
|
+ SDL_zero(pDevices);
|
|
|
+
|
|
|
+ // Create WMI
|
|
|
+ hr = CoCreateInstance(&CLSID_WbemLocator,
|
|
|
+ NULL,
|
|
|
+ CLSCTX_INPROC_SERVER,
|
|
|
+ &IID_IWbemLocator,
|
|
|
+ (LPVOID*)&pIWbemLocator);
|
|
|
+ if (FAILED(hr) || pIWbemLocator == NULL)
|
|
|
+ goto LCleanup;
|
|
|
+
|
|
|
+ bstrNamespace = SysAllocString(L"\\\\.\\root\\cimv2"); if (bstrNamespace == NULL) goto LCleanup;
|
|
|
+ bstrClassName = SysAllocString(L"Win32_PNPEntity"); if (bstrClassName == NULL) goto LCleanup;
|
|
|
+ bstrDeviceID = SysAllocString(L"DeviceID"); if (bstrDeviceID == NULL) goto LCleanup;
|
|
|
+
|
|
|
+ // Connect to WMI
|
|
|
+ hr = IWbemLocator_ConnectServer(pIWbemLocator, bstrNamespace, NULL, NULL, 0L,
|
|
|
+ 0L, NULL, NULL, &pIWbemServices);
|
|
|
+ if (FAILED(hr) || pIWbemServices == NULL) {
|
|
|
+ goto LCleanup;
|
|
|
+ }
|
|
|
|
|
|
- size_t iDevice;
|
|
|
- UINT i;
|
|
|
+ // Switch security level to IMPERSONATE.
|
|
|
+ CoSetProxyBlanket((IUnknown *)pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
|
|
|
+ RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
|
|
|
|
|
|
- if (!SDL_XINPUT_Enabled()) {
|
|
|
- return SDL_FALSE;
|
|
|
- }
|
|
|
+ hr = IWbemServices_CreateInstanceEnum(pIWbemServices, bstrClassName, 0, NULL, &pEnumDevices);
|
|
|
+ if (FAILED(hr) || pEnumDevices == NULL)
|
|
|
+ goto LCleanup;
|
|
|
|
|
|
- /* Check for well known XInput device GUIDs */
|
|
|
- /* This lets us skip RAWINPUT for popular devices. Also, we need to do this for the Valve Streaming Gamepad because it's virtualized and doesn't show up in the device list. */
|
|
|
- for (iDevice = 0; iDevice < SDL_arraysize(s_XInputProductGUID); ++iDevice) {
|
|
|
- if (SDL_memcmp(pGuidProductFromDirectInput, s_XInputProductGUID[iDevice], sizeof(GUID)) == 0) {
|
|
|
- return SDL_TRUE;
|
|
|
+ // Loop over all devices
|
|
|
+ for (;;) {
|
|
|
+ // Get 20 at a time
|
|
|
+ hr = IEnumWbemClassObject_Next(pEnumDevices, 10000, SDL_arraysize(pDevices), pDevices, &uReturned);
|
|
|
+ if (FAILED(hr)) {
|
|
|
+ goto LCleanup;
|
|
|
+ }
|
|
|
+ if (uReturned == 0) {
|
|
|
+ break;
|
|
|
}
|
|
|
+
|
|
|
+ for (iDevice = 0; iDevice < uReturned; iDevice++) {
|
|
|
+ // For each device, get its device ID
|
|
|
+ hr = IWbemClassObject_Get(pDevices[iDevice], bstrDeviceID, 0L, &var, NULL, NULL);
|
|
|
+ if (SUCCEEDED(hr) && var.vt == VT_BSTR && var.bstrVal != NULL) {
|
|
|
+ // Check if the device ID contains "IG_". If it does, then it's an XInput device
|
|
|
+ // This information can not be found from DirectInput
|
|
|
+ if (SDL_wcsstr(var.bstrVal, L"IG_")) {
|
|
|
+ char *bstrVal = WIN_StringToUTF8(var.bstrVal);
|
|
|
+
|
|
|
+ // If it does, then get the VID/PID from var.bstrVal
|
|
|
+ DWORD dwPid = 0, dwVid = 0, dwVidPid;
|
|
|
+ const char *strVid, *strPid;
|
|
|
+ strVid = SDL_strstr(bstrVal, "VID_");
|
|
|
+ if (strVid && SDL_sscanf(strVid, "VID_%4X", &dwVid) != 1)
|
|
|
+ dwVid = 0;
|
|
|
+ strPid = SDL_strstr(bstrVal, "PID_");
|
|
|
+ if (strPid && SDL_sscanf(strPid, "PID_%4X", &dwPid) != 1)
|
|
|
+ dwPid = 0;
|
|
|
+
|
|
|
+ SDL_free(bstrVal);
|
|
|
+
|
|
|
+ // Compare the VID/PID to the DInput device
|
|
|
+ dwVidPid = MAKELONG(dwVid, dwPid);
|
|
|
+ if (dwVidPid == pGuidProductFromDirectInput->Data1) {
|
|
|
+ bIsXinputDevice = SDL_TRUE;
|
|
|
+ goto LCleanup;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ IWbemClassObject_Release(pDevices[iDevice]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+LCleanup:
|
|
|
+ if (bstrNamespace) {
|
|
|
+ SysFreeString(bstrNamespace);
|
|
|
+ }
|
|
|
+ if (bstrDeviceID) {
|
|
|
+ SysFreeString(bstrDeviceID);
|
|
|
}
|
|
|
+ if (bstrClassName) {
|
|
|
+ SysFreeString(bstrClassName);
|
|
|
+ }
|
|
|
+ for (iDevice = 0; iDevice < SDL_arraysize(pDevices); iDevice++) {
|
|
|
+ if (pDevices[iDevice]) {
|
|
|
+ IWbemClassObject_Release(pDevices[iDevice]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (pEnumDevices) {
|
|
|
+ IEnumWbemClassObject_Release(pEnumDevices);
|
|
|
+ }
|
|
|
+ if (pIWbemLocator) {
|
|
|
+ IWbemLocator_Release(pIWbemLocator);
|
|
|
+ }
|
|
|
+ if (pIWbemServices) {
|
|
|
+ IWbemServices_Release(pIWbemServices);
|
|
|
+ }
|
|
|
+
|
|
|
+ return bIsXinputDevice;
|
|
|
+}
|
|
|
+#endif /* 0 */
|
|
|
+
|
|
|
+static SDL_bool
|
|
|
+SDL_IsXInputDevice(const GUID* pGuidProductFromDirectInput)
|
|
|
+{
|
|
|
+ UINT i;
|
|
|
+
|
|
|
+ if (!SDL_XINPUT_Enabled()) {
|
|
|
+ return SDL_FALSE;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (SDL_memcmp(&pGuidProductFromDirectInput->Data4[2], "PIDVID", 6) == 0) {
|
|
|
+ Uint16 vendor_id = (Uint16)LOWORD(pGuidProductFromDirectInput->Data1);
|
|
|
+ Uint16 product_id = (Uint16)HIWORD(pGuidProductFromDirectInput->Data1);
|
|
|
+ if (SDL_IsJoystickXbox360(vendor_id, product_id) || SDL_IsJoystickXboxOne(vendor_id, product_id) ||
|
|
|
+ (vendor_id == 0x28DE && product_id == 0x11FF)) {
|
|
|
+ return SDL_TRUE;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
/* Go through RAWINPUT (WinXP and later) to find HID devices. */
|
|
|
/* Cache this if we end up using it. */
|