Added SDL_GameControllerTypeForIndex() and SDL_GameControllerGetType() to return the type of controller attached.
authorSam Lantinga <slouken@libsdl.org>
Fri, 22 Nov 2019 13:12:12 -0800
changeset 13275e55cd89033a6
parent 13274 b948d820ae75
child 13276 c95ba765e925
Added SDL_GameControllerTypeForIndex() and SDL_GameControllerGetType() to return the type of controller attached.
include/SDL_gamecontroller.h
src/dynapi/SDL_dynapi_overrides.h
src/dynapi/SDL_dynapi_procs.h
src/joystick/SDL_gamecontroller.c
src/joystick/SDL_joystick.c
src/joystick/SDL_joystick_c.h
src/joystick/hidapi/SDL_hidapi_ps4.c
src/joystick/hidapi/SDL_hidapi_xbox360.c
src/joystick/hidapi/SDL_hidapi_xboxone.c
src/joystick/windows/SDL_dinputjoystick.c
test/testgamecontroller.c
     1.1 --- a/include/SDL_gamecontroller.h	Thu Nov 21 14:04:48 2019 -0800
     1.2 +++ b/include/SDL_gamecontroller.h	Fri Nov 22 13:12:12 2019 -0800
     1.3 @@ -57,6 +57,15 @@
     1.4  struct _SDL_GameController;
     1.5  typedef struct _SDL_GameController SDL_GameController;
     1.6  
     1.7 +typedef enum
     1.8 +{
     1.9 +    SDL_CONTROLLER_TYPE_UNKNOWN = 0,
    1.10 +    SDL_CONTROLLER_TYPE_XBOX360,
    1.11 +    SDL_CONTROLLER_TYPE_XBOXONE,
    1.12 +    SDL_CONTROLLER_TYPE_PS3,
    1.13 +    SDL_CONTROLLER_TYPE_PS4,
    1.14 +    SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO,
    1.15 +} SDL_GameControllerType;
    1.16  
    1.17  typedef enum
    1.18  {
    1.19 @@ -176,6 +185,12 @@
    1.20  extern DECLSPEC const char *SDLCALL SDL_GameControllerNameForIndex(int joystick_index);
    1.21  
    1.22  /**
    1.23 + *  Get the type of a game controller.
    1.24 + *  This can be called before any controllers are opened.
    1.25 + */
    1.26 +extern DECLSPEC SDL_GameControllerType SDLCALL SDL_GameControllerTypeForIndex(int joystick_index);
    1.27 +
    1.28 +/**
    1.29   *  Get the mapping of a game controller.
    1.30   *  This can be called before any controllers are opened.
    1.31   *
    1.32 @@ -205,6 +220,11 @@
    1.33  extern DECLSPEC const char *SDLCALL SDL_GameControllerName(SDL_GameController *gamecontroller);
    1.34  
    1.35  /**
    1.36 + *  Return the type of this currently opened controller
    1.37 + */
    1.38 +extern DECLSPEC SDL_GameControllerType SDLCALL SDL_GameControllerGetType(SDL_GameController *gamecontroller);
    1.39 +
    1.40 +/**
    1.41   *  Get the player index of an opened game controller, or -1 if it's not available
    1.42   *
    1.43   *  For XInput controllers this returns the XInput user index.
     2.1 --- a/src/dynapi/SDL_dynapi_overrides.h	Thu Nov 21 14:04:48 2019 -0800
     2.2 +++ b/src/dynapi/SDL_dynapi_overrides.h	Fri Nov 22 13:12:12 2019 -0800
     2.3 @@ -731,3 +731,5 @@
     2.4  #define SDL_strtokr SDL_strtokr_REAL
     2.5  #define SDL_wcsstr SDL_wcsstr_REAL
     2.6  #define SDL_wcsncmp SDL_wcsncmp_REAL
     2.7 +#define SDL_GameControllerTypeForIndex SDL_GameControllerTypeForIndex_REAL
     2.8 +#define SDL_GameControllerGetType SDL_GameControllerGetType_REAL
     3.1 --- a/src/dynapi/SDL_dynapi_procs.h	Thu Nov 21 14:04:48 2019 -0800
     3.2 +++ b/src/dynapi/SDL_dynapi_procs.h	Fri Nov 22 13:12:12 2019 -0800
     3.3 @@ -787,3 +787,5 @@
     3.4  SDL_DYNAPI_PROC(char*,SDL_strtokr,(char *a, const char *b, char **c),(a,b,c),return)
     3.5  SDL_DYNAPI_PROC(wchar_t*,SDL_wcsstr,(const wchar_t *a, const wchar_t *b),(a,b),return)
     3.6  SDL_DYNAPI_PROC(int,SDL_wcsncmp,(const wchar_t *a, const wchar_t *b, size_t c),(a,b,c),return)
     3.7 +SDL_DYNAPI_PROC(SDL_GameControllerType,SDL_GameControllerTypeForIndex,(int a),(a),return)
     3.8 +SDL_DYNAPI_PROC(SDL_GameControllerType,SDL_GameControllerGetType,(SDL_GameController *a),(a),return)
     4.1 --- a/src/joystick/SDL_gamecontroller.c	Thu Nov 21 14:04:48 2019 -0800
     4.2 +++ b/src/joystick/SDL_gamecontroller.c	Fri Nov 22 13:12:12 2019 -0800
     4.3 @@ -1413,6 +1413,17 @@
     4.4  
     4.5  
     4.6  /**
     4.7 + *  Get the type of a game controller.
     4.8 + */
     4.9 +SDL_GameControllerType
    4.10 +SDL_GameControllerTypeForIndex(int joystick_index)
    4.11 +{
    4.12 +    SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(joystick_index);
    4.13 +    return SDL_GetGameControllerTypeFromGUID(guid);
    4.14 +}
    4.15 +
    4.16 +
    4.17 +/**
    4.18   *  Get the mapping of a game controller.
    4.19   *  This can be called before any controllers are opened.
    4.20   *  If no mapping can be found, this function returns NULL.
    4.21 @@ -1743,6 +1754,15 @@
    4.22      }
    4.23  }
    4.24  
    4.25 +SDL_GameControllerType
    4.26 +SDL_GameControllerGetType(SDL_GameController *gamecontroller)
    4.27 +{
    4.28 +    if (!gamecontroller) {
    4.29 +        return SDL_CONTROLLER_TYPE_UNKNOWN;
    4.30 +    }
    4.31 +    return SDL_GetGameControllerTypeFromGUID(gamecontroller->joystick->guid);
    4.32 +}
    4.33 +
    4.34  int
    4.35  SDL_GameControllerGetPlayerIndex(SDL_GameController *gamecontroller)
    4.36  {
     5.1 --- a/src/joystick/SDL_joystick.c	Thu Nov 21 14:04:48 2019 -0800
     5.2 +++ b/src/joystick/SDL_joystick.c	Fri Nov 22 13:12:12 2019 -0800
     5.3 @@ -1159,12 +1159,6 @@
     5.4  }
     5.5  
     5.6  SDL_bool
     5.7 -SDL_IsJoystickPS4(Uint16 vendor, Uint16 product)
     5.8 -{
     5.9 -    return (GuessControllerType(vendor, product) == k_eControllerType_PS4Controller);
    5.10 -}
    5.11 -
    5.12 -SDL_bool
    5.13  SDL_IsJoystickNintendoSwitchPro(Uint16 vendor, Uint16 product)
    5.14  {
    5.15      EControllerType eType = GuessControllerType(vendor, product);
    5.16 @@ -1172,6 +1166,51 @@
    5.17              eType == k_eControllerType_SwitchInputOnlyController);
    5.18  }
    5.19  
    5.20 +SDL_GameControllerType
    5.21 +SDL_GetGameControllerTypeFromGUID(SDL_JoystickGUID guid)
    5.22 +{
    5.23 +    SDL_GameControllerType type;
    5.24 +    Uint16 vendor, product;
    5.25 +
    5.26 +    SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL);
    5.27 +    type = SDL_GetGameControllerType(vendor, product);
    5.28 +    if (type == SDL_CONTROLLER_TYPE_UNKNOWN) {
    5.29 +        if (SDL_IsJoystickXInput(guid)) {
    5.30 +            /* This is probably an Xbox One controller */
    5.31 +            return SDL_CONTROLLER_TYPE_XBOXONE;
    5.32 +        }
    5.33 +    }
    5.34 +    return type;
    5.35 +}
    5.36 +
    5.37 +SDL_GameControllerType
    5.38 +SDL_GetGameControllerType(Uint16 vendor, Uint16 product)
    5.39 +{
    5.40 +    /* Filter out some bogus values here */
    5.41 +    if (vendor == 0x0000 && product == 0x0000) {
    5.42 +        return SDL_CONTROLLER_TYPE_UNKNOWN;
    5.43 +    }
    5.44 +    if (vendor == 0x0001 && product == 0x0001) {
    5.45 +        return SDL_CONTROLLER_TYPE_UNKNOWN;
    5.46 +    }
    5.47 +
    5.48 +    switch (GuessControllerType(vendor, product)) {
    5.49 +    case k_eControllerType_XBox360Controller:
    5.50 +        return SDL_CONTROLLER_TYPE_XBOX360;
    5.51 +    case k_eControllerType_XBoxOneController:
    5.52 +        return SDL_CONTROLLER_TYPE_XBOXONE;
    5.53 +    case k_eControllerType_PS3Controller:
    5.54 +        return SDL_CONTROLLER_TYPE_PS3;
    5.55 +    case k_eControllerType_PS4Controller:
    5.56 +        return SDL_CONTROLLER_TYPE_PS4;
    5.57 +    case k_eControllerType_SwitchProController:
    5.58 +    case k_eControllerType_SwitchInputOnlyController:
    5.59 +        return SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO;
    5.60 +    default:
    5.61 +        return SDL_CONTROLLER_TYPE_UNKNOWN;
    5.62 +    }
    5.63 +}
    5.64 +
    5.65  SDL_bool
    5.66  SDL_IsJoystickNintendoSwitchProInputOnly(Uint16 vendor, Uint16 product)
    5.67  {
    5.68 @@ -1188,25 +1227,6 @@
    5.69  }
    5.70  
    5.71  SDL_bool
    5.72 -SDL_IsJoystickXbox360(Uint16 vendor, Uint16 product)
    5.73 -{
    5.74 -    /* Filter out some bogus values here */
    5.75 -    if (vendor == 0x0000 && product == 0x0000) {
    5.76 -        return SDL_FALSE;
    5.77 -    }
    5.78 -    if (vendor == 0x0001 && product == 0x0001) {
    5.79 -        return SDL_FALSE;
    5.80 -    }
    5.81 -    return (GuessControllerType(vendor, product) == k_eControllerType_XBox360Controller);
    5.82 -}
    5.83 -
    5.84 -SDL_bool
    5.85 -SDL_IsJoystickXboxOne(Uint16 vendor, Uint16 product)
    5.86 -{
    5.87 -    return (GuessControllerType(vendor, product) == k_eControllerType_XBoxOneController);
    5.88 -}
    5.89 -
    5.90 -SDL_bool
    5.91  SDL_IsJoystickXInput(SDL_JoystickGUID guid)
    5.92  {
    5.93      return (guid.data[14] == 'x') ? SDL_TRUE : SDL_FALSE;
    5.94 @@ -1481,7 +1501,7 @@
    5.95          }
    5.96      }
    5.97  
    5.98 -    if (SDL_IsJoystickPS4(vendor, product) && SDL_IsPS4RemapperRunning()) {
    5.99 +    if (SDL_GetGameControllerType(vendor, product) == SDL_CONTROLLER_TYPE_PS4 && SDL_IsPS4RemapperRunning()) {
   5.100          return SDL_TRUE;
   5.101      }
   5.102  
     6.1 --- a/src/joystick/SDL_joystick_c.h	Thu Nov 21 14:04:48 2019 -0800
     6.2 +++ b/src/joystick/SDL_joystick_c.h	Fri Nov 22 13:12:12 2019 -0800
     6.3 @@ -25,6 +25,7 @@
     6.4  #include "../SDL_internal.h"
     6.5  
     6.6  /* Useful functions and variables from SDL_joystick.c */
     6.7 +#include "SDL_gamecontroller.h"
     6.8  #include "SDL_joystick.h"
     6.9  
    6.10  struct _SDL_JoystickDriver;
    6.11 @@ -51,22 +52,16 @@
    6.12  /* Function to extract information from an SDL joystick GUID */
    6.13  extern void SDL_GetJoystickGUIDInfo(SDL_JoystickGUID guid, Uint16 *vendor, Uint16 *product, Uint16 *version);
    6.14  
    6.15 -/* Function to return whether a joystick is a PS4 controller */
    6.16 -extern SDL_bool SDL_IsJoystickPS4(Uint16 vendor_id, Uint16 product_id);
    6.17 +/* Function to return the type of a controller */
    6.18 +extern SDL_GameControllerType SDL_GetGameControllerTypeFromGUID(SDL_JoystickGUID guid);
    6.19 +extern SDL_GameControllerType SDL_GetGameControllerType(Uint16 vendor, Uint16 product);
    6.20  
    6.21  /* Function to return whether a joystick is a Nintendo Switch Pro controller */
    6.22 -extern SDL_bool SDL_IsJoystickNintendoSwitchPro( Uint16 vendor_id, Uint16 product_id );
    6.23  extern SDL_bool SDL_IsJoystickNintendoSwitchProInputOnly(Uint16 vendor_id, Uint16 product_id);
    6.24  
    6.25  /* Function to return whether a joystick is a Steam Controller */
    6.26  extern SDL_bool SDL_IsJoystickSteamController(Uint16 vendor_id, Uint16 product_id);
    6.27  
    6.28 -/* Function to return whether a joystick is an Xbox 360 controller */
    6.29 -extern SDL_bool SDL_IsJoystickXbox360(Uint16 vendor_id, Uint16 product_id);
    6.30 -
    6.31 -/* Function to return whether a joystick is an Xbox One controller */
    6.32 -extern SDL_bool SDL_IsJoystickXboxOne(Uint16 vendor_id, Uint16 product_id);
    6.33 -
    6.34  /* Function to return whether a joystick guid comes from the XInput driver */
    6.35  extern SDL_bool SDL_IsJoystickXInput(SDL_JoystickGUID guid);
    6.36  
     7.1 --- a/src/joystick/hidapi/SDL_hidapi_ps4.c	Thu Nov 21 14:04:48 2019 -0800
     7.2 +++ b/src/joystick/hidapi/SDL_hidapi_ps4.c	Fri Nov 22 13:12:12 2019 -0800
     7.3 @@ -141,7 +141,7 @@
     7.4  static SDL_bool
     7.5  HIDAPI_DriverPS4_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, const char *name)
     7.6  {
     7.7 -    return SDL_IsJoystickPS4(vendor_id, product_id);
     7.8 +    return (SDL_GetGameControllerType(vendor_id, product_id) == SDL_CONTROLLER_TYPE_PS4);
     7.9  }
    7.10  
    7.11  static const char *
     8.1 --- a/src/joystick/hidapi/SDL_hidapi_xbox360.c	Thu Nov 21 14:04:48 2019 -0800
     8.2 +++ b/src/joystick/hidapi/SDL_hidapi_xbox360.c	Fri Nov 22 13:12:12 2019 -0800
     8.3 @@ -249,6 +249,8 @@
     8.4  static SDL_bool
     8.5  HIDAPI_DriverXbox360_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, const char *name)
     8.6  {
     8.7 +    SDL_GameControllerType type = SDL_GameControllerType(vendor_id, product_id);
     8.8 +
     8.9  #if defined(__MACOSX__) || defined(__WIN32__)
    8.10      if (vendor_id == 0x045e && product_id == 0x028e && version == 1) {
    8.11          /* This is the Steam Virtual Gamepad, which isn't supported by this driver */
    8.12 @@ -258,9 +260,9 @@
    8.13          /* This is the old Bluetooth Xbox One S firmware, which isn't supported by this driver */
    8.14          return SDL_FALSE;
    8.15      }
    8.16 -    return SDL_IsJoystickXbox360(vendor_id, product_id) || SDL_IsJoystickXboxOne(vendor_id, product_id);
    8.17 +    return (type == SDL_CONTROLLER_TYPE_XBOX360 || type == SDL_CONTROLLER_TYPE_XBOXONE);
    8.18  #else
    8.19 -    return SDL_IsJoystickXbox360(vendor_id, product_id);
    8.20 +    return (type == SDL_CONTROLLER_TYPE_XBOX360);
    8.21  #endif
    8.22  }
    8.23  
     9.1 --- a/src/joystick/hidapi/SDL_hidapi_xboxone.c	Thu Nov 21 14:04:48 2019 -0800
     9.2 +++ b/src/joystick/hidapi/SDL_hidapi_xboxone.c	Fri Nov 22 13:12:12 2019 -0800
     9.3 @@ -197,7 +197,7 @@
     9.4          return SDL_FALSE;
     9.5      }
     9.6  #endif
     9.7 -    return SDL_IsJoystickXboxOne(vendor_id, product_id);
     9.8 +    return (SDL_GetGameControllerType(vendor_id, product_id) == SDL_CONTROLLER_TYPE_XBOXONE);
     9.9  }
    9.10  
    9.11  static const char *
    10.1 --- a/src/joystick/windows/SDL_dinputjoystick.c	Thu Nov 21 14:04:48 2019 -0800
    10.2 +++ b/src/joystick/windows/SDL_dinputjoystick.c	Fri Nov 22 13:12:12 2019 -0800
    10.3 @@ -246,139 +246,141 @@
    10.4  static SDL_bool
    10.5  WIN_IsXInputDevice(const GUID* pGuidProductFromDirectInput)
    10.6  {
    10.7 -	IWbemLocator*           pIWbemLocator = NULL;
    10.8 -	IEnumWbemClassObject*   pEnumDevices = NULL;
    10.9 -	IWbemClassObject*       pDevices[20];
   10.10 -	IWbemServices*          pIWbemServices = NULL;
   10.11 -	BSTR                    bstrNamespace = NULL;
   10.12 -	BSTR                    bstrDeviceID = NULL;
   10.13 -	BSTR                    bstrClassName = NULL;
   10.14 -	DWORD                   uReturned = 0;
   10.15 -	SDL_bool                bIsXinputDevice = SDL_FALSE;
   10.16 -	UINT                    iDevice = 0;
   10.17 -	VARIANT                 var;
   10.18 -	HRESULT                 hr;
   10.19 +    IWbemLocator*           pIWbemLocator = NULL;
   10.20 +    IEnumWbemClassObject*   pEnumDevices = NULL;
   10.21 +    IWbemClassObject*       pDevices[20];
   10.22 +    IWbemServices*          pIWbemServices = NULL;
   10.23 +    BSTR                    bstrNamespace = NULL;
   10.24 +    BSTR                    bstrDeviceID = NULL;
   10.25 +    BSTR                    bstrClassName = NULL;
   10.26 +    DWORD                   uReturned = 0;
   10.27 +    SDL_bool                bIsXinputDevice = SDL_FALSE;
   10.28 +    UINT                    iDevice = 0;
   10.29 +    VARIANT                 var;
   10.30 +    HRESULT                 hr;
   10.31  
   10.32 -	SDL_zero(pDevices);
   10.33 +    SDL_zero(pDevices);
   10.34  
   10.35 -	// Create WMI
   10.36 -	hr = CoCreateInstance(&CLSID_WbemLocator,
   10.37 -		NULL,
   10.38 -		CLSCTX_INPROC_SERVER,
   10.39 -		&IID_IWbemLocator,
   10.40 -		(LPVOID*)&pIWbemLocator);
   10.41 -	if (FAILED(hr) || pIWbemLocator == NULL)
   10.42 -		goto LCleanup;
   10.43 +    // Create WMI
   10.44 +    hr = CoCreateInstance(&CLSID_WbemLocator,
   10.45 +        NULL,
   10.46 +        CLSCTX_INPROC_SERVER,
   10.47 +        &IID_IWbemLocator,
   10.48 +        (LPVOID*)&pIWbemLocator);
   10.49 +    if (FAILED(hr) || pIWbemLocator == NULL)
   10.50 +        goto LCleanup;
   10.51  
   10.52 -	bstrNamespace = SysAllocString(L"\\\\.\\root\\cimv2"); if (bstrNamespace == NULL) goto LCleanup;
   10.53 -	bstrClassName = SysAllocString(L"Win32_PNPEntity");   if (bstrClassName == NULL) goto LCleanup;
   10.54 -	bstrDeviceID = SysAllocString(L"DeviceID");          if (bstrDeviceID == NULL)  goto LCleanup;
   10.55 +    bstrNamespace = SysAllocString(L"\\\\.\\root\\cimv2"); if (bstrNamespace == NULL) goto LCleanup;
   10.56 +    bstrClassName = SysAllocString(L"Win32_PNPEntity");   if (bstrClassName == NULL) goto LCleanup;
   10.57 +    bstrDeviceID = SysAllocString(L"DeviceID");          if (bstrDeviceID == NULL)  goto LCleanup;
   10.58  
   10.59 -	// Connect to WMI 
   10.60 -	hr = IWbemLocator_ConnectServer(pIWbemLocator, bstrNamespace, NULL, NULL, 0L,
   10.61 -		0L, NULL, NULL, &pIWbemServices);
   10.62 -	if (FAILED(hr) || pIWbemServices == NULL) {
   10.63 -		goto LCleanup;
   10.64 +    // Connect to WMI 
   10.65 +    hr = IWbemLocator_ConnectServer(pIWbemLocator, bstrNamespace, NULL, NULL, 0L,
   10.66 +        0L, NULL, NULL, &pIWbemServices);
   10.67 +    if (FAILED(hr) || pIWbemServices == NULL) {
   10.68 +        goto LCleanup;
   10.69      }
   10.70  
   10.71 -	// Switch security level to IMPERSONATE. 
   10.72 -	CoSetProxyBlanket((IUnknown *)pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
   10.73 -		RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
   10.74 +    // Switch security level to IMPERSONATE. 
   10.75 +    CoSetProxyBlanket((IUnknown *)pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
   10.76 +        RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
   10.77  
   10.78 -	hr = IWbemServices_CreateInstanceEnum(pIWbemServices, bstrClassName, 0, NULL, &pEnumDevices);
   10.79 -	if (FAILED(hr) || pEnumDevices == NULL)
   10.80 -		goto LCleanup;
   10.81 +    hr = IWbemServices_CreateInstanceEnum(pIWbemServices, bstrClassName, 0, NULL, &pEnumDevices);
   10.82 +    if (FAILED(hr) || pEnumDevices == NULL)
   10.83 +        goto LCleanup;
   10.84  
   10.85 -	// Loop over all devices
   10.86 -	for (;;) {
   10.87 -		// Get 20 at a time
   10.88 -		hr = IEnumWbemClassObject_Next(pEnumDevices, 10000, SDL_arraysize(pDevices), pDevices, &uReturned);
   10.89 -		if (FAILED(hr)) {
   10.90 -			goto LCleanup;
   10.91 +    // Loop over all devices
   10.92 +    for (;;) {
   10.93 +        // Get 20 at a time
   10.94 +        hr = IEnumWbemClassObject_Next(pEnumDevices, 10000, SDL_arraysize(pDevices), pDevices, &uReturned);
   10.95 +        if (FAILED(hr)) {
   10.96 +            goto LCleanup;
   10.97          }
   10.98 -		if (uReturned == 0) {
   10.99 -			break;
  10.100 +        if (uReturned == 0) {
  10.101 +            break;
  10.102          }
  10.103  
  10.104 -		for (iDevice = 0; iDevice < uReturned; iDevice++) {
  10.105 -			// For each device, get its device ID
  10.106 -			hr = IWbemClassObject_Get(pDevices[iDevice], bstrDeviceID, 0L, &var, NULL, NULL);
  10.107 -			if (SUCCEEDED(hr) && var.vt == VT_BSTR && var.bstrVal != NULL) {
  10.108 -				// Check if the device ID contains "IG_".  If it does, then it's an XInput device
  10.109 -				// This information can not be found from DirectInput 
  10.110 -				if (SDL_wcsstr(var.bstrVal, L"IG_")) {
  10.111 -					char *bstrVal = WIN_StringToUTF8(var.bstrVal);
  10.112 +        for (iDevice = 0; iDevice < uReturned; iDevice++) {
  10.113 +            // For each device, get its device ID
  10.114 +            hr = IWbemClassObject_Get(pDevices[iDevice], bstrDeviceID, 0L, &var, NULL, NULL);
  10.115 +            if (SUCCEEDED(hr) && var.vt == VT_BSTR && var.bstrVal != NULL) {
  10.116 +                // Check if the device ID contains "IG_".  If it does, then it's an XInput device
  10.117 +                // This information can not be found from DirectInput 
  10.118 +                if (SDL_wcsstr(var.bstrVal, L"IG_")) {
  10.119 +                    char *bstrVal = WIN_StringToUTF8(var.bstrVal);
  10.120  
  10.121 -					// If it does, then get the VID/PID from var.bstrVal
  10.122 -					DWORD dwPid = 0, dwVid = 0, dwVidPid;
  10.123 -					const char *strVid, *strPid;
  10.124 -					strVid = SDL_strstr(bstrVal, "VID_");
  10.125 -					if (strVid && SDL_sscanf(strVid, "VID_%4X", &dwVid) != 1)
  10.126 -						dwVid = 0;
  10.127 -					strPid = SDL_strstr(bstrVal, "PID_");
  10.128 -					if (strPid && SDL_sscanf(strPid, "PID_%4X", &dwPid) != 1)
  10.129 -						dwPid = 0;
  10.130 +                    // If it does, then get the VID/PID from var.bstrVal
  10.131 +                    DWORD dwPid = 0, dwVid = 0, dwVidPid;
  10.132 +                    const char *strVid, *strPid;
  10.133 +                    strVid = SDL_strstr(bstrVal, "VID_");
  10.134 +                    if (strVid && SDL_sscanf(strVid, "VID_%4X", &dwVid) != 1)
  10.135 +                        dwVid = 0;
  10.136 +                    strPid = SDL_strstr(bstrVal, "PID_");
  10.137 +                    if (strPid && SDL_sscanf(strPid, "PID_%4X", &dwPid) != 1)
  10.138 +                        dwPid = 0;
  10.139  
  10.140 -					SDL_free(bstrVal);
  10.141 +                    SDL_free(bstrVal);
  10.142  
  10.143 -					// Compare the VID/PID to the DInput device
  10.144 -					dwVidPid = MAKELONG(dwVid, dwPid);
  10.145 -					if (dwVidPid == pGuidProductFromDirectInput->Data1) {
  10.146 -						bIsXinputDevice = SDL_TRUE;
  10.147 -						goto LCleanup;
  10.148 -					}
  10.149 -				}
  10.150 -			}
  10.151 -			IWbemClassObject_Release(pDevices[iDevice]);
  10.152 -		}
  10.153 -	}
  10.154 +                    // Compare the VID/PID to the DInput device
  10.155 +                    dwVidPid = MAKELONG(dwVid, dwPid);
  10.156 +                    if (dwVidPid == pGuidProductFromDirectInput->Data1) {
  10.157 +                        bIsXinputDevice = SDL_TRUE;
  10.158 +                        goto LCleanup;
  10.159 +                    }
  10.160 +                }
  10.161 +            }
  10.162 +            IWbemClassObject_Release(pDevices[iDevice]);
  10.163 +        }
  10.164 +    }
  10.165  
  10.166  LCleanup:
  10.167 -	if (bstrNamespace) {
  10.168 -		SysFreeString(bstrNamespace);
  10.169 +    if (bstrNamespace) {
  10.170 +        SysFreeString(bstrNamespace);
  10.171      }
  10.172 -	if (bstrDeviceID) {
  10.173 -		SysFreeString(bstrDeviceID);
  10.174 +    if (bstrDeviceID) {
  10.175 +        SysFreeString(bstrDeviceID);
  10.176      }
  10.177 -	if (bstrClassName) {
  10.178 -		SysFreeString(bstrClassName);
  10.179 +    if (bstrClassName) {
  10.180 +        SysFreeString(bstrClassName);
  10.181      }
  10.182 -	for (iDevice = 0; iDevice < SDL_arraysize(pDevices); iDevice++) {
  10.183 -		if (pDevices[iDevice]) {
  10.184 -			IWbemClassObject_Release(pDevices[iDevice]);
  10.185 -		}
  10.186 -	}
  10.187 -	if (pEnumDevices) {
  10.188 -		IEnumWbemClassObject_Release(pEnumDevices);
  10.189 -	}
  10.190 -	if (pIWbemLocator) {
  10.191 -		IWbemLocator_Release(pIWbemLocator);
  10.192 -	}
  10.193 -	if (pIWbemServices) {
  10.194 -		IWbemServices_Release(pIWbemServices);
  10.195 -	}
  10.196 +    for (iDevice = 0; iDevice < SDL_arraysize(pDevices); iDevice++) {
  10.197 +        if (pDevices[iDevice]) {
  10.198 +            IWbemClassObject_Release(pDevices[iDevice]);
  10.199 +        }
  10.200 +    }
  10.201 +    if (pEnumDevices) {
  10.202 +        IEnumWbemClassObject_Release(pEnumDevices);
  10.203 +    }
  10.204 +    if (pIWbemLocator) {
  10.205 +        IWbemLocator_Release(pIWbemLocator);
  10.206 +    }
  10.207 +    if (pIWbemServices) {
  10.208 +        IWbemServices_Release(pIWbemServices);
  10.209 +    }
  10.210  
  10.211 -	return bIsXinputDevice;
  10.212 +    return bIsXinputDevice;
  10.213  }
  10.214  #endif /* 0 */
  10.215  
  10.216  static SDL_bool
  10.217  SDL_IsXInputDevice(const GUID* pGuidProductFromDirectInput)
  10.218  {
  10.219 -	UINT i;
  10.220 +    UINT i;
  10.221  
  10.222 -	if (!SDL_XINPUT_Enabled()) {
  10.223 -		return SDL_FALSE;
  10.224 -	}
  10.225 +    if (!SDL_XINPUT_Enabled()) {
  10.226 +        return SDL_FALSE;
  10.227 +    }
  10.228  
  10.229 -	if (SDL_memcmp(&pGuidProductFromDirectInput->Data4[2], "PIDVID", 6) == 0) {
  10.230 -		Uint16 vendor_id = (Uint16)LOWORD(pGuidProductFromDirectInput->Data1);
  10.231 -		Uint16 product_id = (Uint16)HIWORD(pGuidProductFromDirectInput->Data1);
  10.232 -		if (SDL_IsJoystickXbox360(vendor_id, product_id) || SDL_IsJoystickXboxOne(vendor_id, product_id) ||
  10.233 -			(vendor_id == 0x28DE && product_id == 0x11FF)) {
  10.234 -			return SDL_TRUE;
  10.235 -		}
  10.236 -	}
  10.237 +    if (SDL_memcmp(&pGuidProductFromDirectInput->Data4[2], "PIDVID", 6) == 0) {
  10.238 +        Uint16 vendor_id = (Uint16)LOWORD(pGuidProductFromDirectInput->Data1);
  10.239 +        Uint16 product_id = (Uint16)HIWORD(pGuidProductFromDirectInput->Data1);
  10.240 +        SDL_GameControllerType type = SDL_GetGameControllerType(vendor_id, product_id);
  10.241 +        if (type == SDL_CONTROLLER_TYPE_XBOX360 ||
  10.242 +            type == SDL_CONTROLLER_TYPE_XBOXONE ||
  10.243 +            (vendor_id == 0x28DE && product_id == 0x11FF)) {
  10.244 +            return SDL_TRUE;
  10.245 +        }
  10.246 +    }
  10.247  
  10.248      /* Go through RAWINPUT (WinXP and later) to find HID devices. */
  10.249      /* Cache this if we end up using it. */
    11.1 --- a/test/testgamecontroller.c	Thu Nov 21 14:04:48 2019 -0800
    11.2 +++ b/test/testgamecontroller.c	Fri Nov 22 13:12:12 2019 -0800
    11.3 @@ -292,7 +292,26 @@
    11.4          {
    11.5              nController++;
    11.6              name = SDL_GameControllerNameForIndex(i);
    11.7 -            description = "Controller";
    11.8 +            switch (SDL_GameControllerTypeForIndex(i)) {
    11.9 +            case SDL_CONTROLLER_TYPE_XBOX360:
   11.10 +                description = "XBox 360 Controller";
   11.11 +                break;
   11.12 +            case SDL_CONTROLLER_TYPE_XBOXONE:
   11.13 +                description = "XBox One Controller";
   11.14 +                break;
   11.15 +            case SDL_CONTROLLER_TYPE_PS3:
   11.16 +                description = "PS3 Controller";
   11.17 +                break;
   11.18 +            case SDL_CONTROLLER_TYPE_PS4:
   11.19 +                description = "PS4 Controller";
   11.20 +                break;
   11.21 +            case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO:
   11.22 +                description = "Nintendo Switch Pro Controller";
   11.23 +                break;
   11.24 +            default:
   11.25 +                description = "Game Controller";
   11.26 +                break;
   11.27 +            }
   11.28          } else {
   11.29              name = SDL_JoystickNameForIndex(i);
   11.30              description = "Joystick";