Unified code to standardize joystick names
authorSam Lantinga <slouken@libsdl.org>
Thu, 12 Mar 2020 19:47:30 -0700
changeset 13611bcbfec15e25f
parent 13610 e60a1b63742b
child 13612 66b28c199af1
Unified code to standardize joystick names
src/joystick/SDL_joystick.c
src/joystick/SDL_joystick_c.h
src/joystick/android/SDL_sysjoystick.c
src/joystick/darwin/SDL_sysjoystick.c
src/joystick/emscripten/SDL_sysjoystick.c
src/joystick/haiku/SDL_haikujoystick.cc
src/joystick/hidapi/SDL_hidapijoystick.c
src/joystick/iphoneos/SDL_sysjoystick.m
src/joystick/linux/SDL_sysjoystick.c
src/joystick/windows/SDL_dinputjoystick.c
src/joystick/windows/SDL_xinputjoystick.c
     1.1 --- a/src/joystick/SDL_joystick.c	Thu Mar 12 19:47:28 2020 -0700
     1.2 +++ b/src/joystick/SDL_joystick.c	Thu Mar 12 19:47:30 2020 -0700
     1.3 @@ -279,23 +279,6 @@
     1.4  }
     1.5  
     1.6  /*
     1.7 - * Perform any needed fixups for joystick names
     1.8 - */
     1.9 -static const char *
    1.10 -SDL_FixupJoystickName(const char *name)
    1.11 -{
    1.12 -    if (name) {
    1.13 -        const char *skip_prefix = "NVIDIA Corporation ";
    1.14 -
    1.15 -        if (SDL_strncmp(name, skip_prefix, SDL_strlen(skip_prefix)) == 0) {
    1.16 -            name += SDL_strlen(skip_prefix);
    1.17 -        }
    1.18 -    }
    1.19 -    return name;
    1.20 -}
    1.21 -
    1.22 -
    1.23 -/*
    1.24   * Get the implementation dependent name of a joystick
    1.25   */
    1.26  const char *
    1.27 @@ -306,7 +289,7 @@
    1.28  
    1.29      SDL_LockJoysticks();
    1.30      if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
    1.31 -        name = SDL_FixupJoystickName(driver->GetDeviceName(device_index));
    1.32 +        name = driver->GetDeviceName(device_index);
    1.33      }
    1.34      SDL_UnlockJoysticks();
    1.35  
    1.36 @@ -721,7 +704,7 @@
    1.37          return NULL;
    1.38      }
    1.39  
    1.40 -    return SDL_FixupJoystickName(joystick->name);
    1.41 +    return joystick->name;
    1.42  }
    1.43  
    1.44  /**
    1.45 @@ -1369,23 +1352,112 @@
    1.46      }
    1.47  }
    1.48  
    1.49 -const char *
    1.50 -SDL_GetCustomJoystickManufacturer(const char *manufacturer)
    1.51 +static int
    1.52 +PrefixMatch(const char *a, const char *b)
    1.53  {
    1.54 -    if (manufacturer) {
    1.55 -        if (SDL_strcmp(manufacturer, "Performance Designed Products") == 0) {
    1.56 -            return "PDP";
    1.57 -        } else if (SDL_strcmp(manufacturer, "HORI CO.,LTD") == 0) {
    1.58 -            return "HORI";
    1.59 +    int matchlen = 0;
    1.60 +    while (*a && *b) {
    1.61 +        if (*a++ == *b++) {
    1.62 +            ++matchlen;
    1.63 +        } else {
    1.64 +            break;
    1.65          }
    1.66      }
    1.67 -    return manufacturer;
    1.68 +    return matchlen;
    1.69  }
    1.70  
    1.71 -const char *
    1.72 -SDL_GetCustomJoystickName(Uint16 vendor, Uint16 product)
    1.73 +char *
    1.74 +SDL_CreateJoystickName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name)
    1.75  {
    1.76 -    return GuessControllerName(vendor, product);
    1.77 +    static struct {
    1.78 +        const char *prefix;
    1.79 +        const char *replacement;
    1.80 +    } replacements[] = {
    1.81 +        { "NVIDIA Corporation ", "" },
    1.82 +        { "Performance Designed Products", "PDP" },
    1.83 +        { "HORI CO.,LTD", "HORI" },
    1.84 +    };
    1.85 +    const char *custom_name;
    1.86 +    char *name;
    1.87 +    size_t i, len;
    1.88 +
    1.89 +    custom_name = GuessControllerName(vendor, product);
    1.90 +    if (custom_name) {
    1.91 +        return SDL_strdup(custom_name);
    1.92 +    }
    1.93 +
    1.94 +    if (!vendor_name) {
    1.95 +        vendor_name = "";
    1.96 +    }
    1.97 +    if (!product_name) {
    1.98 +        product_name = "";
    1.99 +    }
   1.100 +
   1.101 +    while (*vendor_name == ' ') {
   1.102 +        ++vendor_name;
   1.103 +    }
   1.104 +    while (*product_name == ' ') {
   1.105 +        ++product_name;
   1.106 +    }
   1.107 +
   1.108 +    if (*vendor_name && *product_name) {
   1.109 +        len = (SDL_strlen(vendor_name) + 1 + SDL_strlen(product_name) + 1);
   1.110 +        name = (char *)SDL_malloc(len);
   1.111 +        if (!name) {
   1.112 +            return NULL;
   1.113 +        }
   1.114 +        SDL_snprintf(name, len, "%s %s", vendor_name, product_name);
   1.115 +    } else if (*product_name) {
   1.116 +        name = SDL_strdup(product_name);
   1.117 +    } else if (vendor || product) {
   1.118 +        len = (6 + 1 + 6 + 1);
   1.119 +        name = (char *)SDL_malloc(len);
   1.120 +        if (!name) {
   1.121 +            return NULL;
   1.122 +        }
   1.123 +        SDL_snprintf(name, len, "0x%.4x/0x%.4x", vendor, product);
   1.124 +    } else {
   1.125 +        name = SDL_strdup("Controller");
   1.126 +    }
   1.127 +
   1.128 +    /* Trim trailing whitespace */
   1.129 +    for (len = SDL_strlen(name); (len > 0 && name[len - 1] == ' '); --len) {
   1.130 +        /* continue */
   1.131 +    }
   1.132 +    name[len] = '\0';
   1.133 +
   1.134 +    /* Compress duplicate spaces */
   1.135 +    for (i = 0; i < (len - 1); ) {
   1.136 +        if (name[i] == ' ' && name[i+1] == ' ') {
   1.137 +            SDL_memmove(&name[i], &name[i+1], (len - i));
   1.138 +            --len;
   1.139 +        } else {
   1.140 +            ++i;
   1.141 +        }
   1.142 +    }
   1.143 +
   1.144 +    /* Remove duplicate manufacturer in the name */
   1.145 +    for (i = 0; i < (len - 1); ++i) {
   1.146 +        int matchlen = PrefixMatch(name, &name[i]);
   1.147 +        if (matchlen > 0 && name[matchlen - 1] == ' ') {
   1.148 +            SDL_memmove(name, name+matchlen, len-matchlen+1);
   1.149 +            len -= matchlen;
   1.150 +            break;
   1.151 +        }
   1.152 +    }
   1.153 +
   1.154 +    /* Perform any manufacturer replacements */
   1.155 +    for (i = 0; i < SDL_arraysize(replacements); ++i) {
   1.156 +        size_t prefixlen = SDL_strlen(replacements[i].prefix);
   1.157 +        if (SDL_strncasecmp(name, replacements[i].prefix, prefixlen) == 0) {
   1.158 +            size_t replacementlen = SDL_strlen(replacements[i].replacement);
   1.159 +            SDL_memcpy(name, replacements[i].replacement, replacementlen);
   1.160 +            SDL_memmove(name+replacementlen, name+prefixlen, (len-prefixlen+1));
   1.161 +            break;
   1.162 +        }
   1.163 +    }
   1.164 +
   1.165 +    return name;
   1.166  }
   1.167  
   1.168  SDL_GameControllerType
     2.1 --- a/src/joystick/SDL_joystick_c.h	Thu Mar 12 19:47:28 2020 -0700
     2.2 +++ b/src/joystick/SDL_joystick_c.h	Thu Mar 12 19:47:30 2020 -0700
     2.3 @@ -52,11 +52,10 @@
     2.4  /* Function to extract information from an SDL joystick GUID */
     2.5  extern void SDL_GetJoystickGUIDInfo(SDL_JoystickGUID guid, Uint16 *vendor, Uint16 *product, Uint16 *version);
     2.6  
     2.7 -/* Function to get a custom name for a controller manufacturer, if it's available */
     2.8 -extern const char *SDL_GetCustomJoystickManufacturer(const char *manufacturer);
     2.9 -
    2.10 -/* Function to get a custom name for a controller, if it's available */
    2.11 -extern const char *SDL_GetCustomJoystickName(Uint16 vendor, Uint16 product);
    2.12 +/* Function to standardize the name for a controller
    2.13 +   This should be freed with SDL_free() when no longer needed
    2.14 + */
    2.15 +extern char *SDL_CreateJoystickName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name);
    2.16  
    2.17  /* Function to return the type of a controller */
    2.18  extern SDL_GameControllerType SDL_GetJoystickGameControllerTypeFromGUID(SDL_JoystickGUID guid, const char *name);
     3.1 --- a/src/joystick/android/SDL_sysjoystick.c	Thu Mar 12 19:47:28 2020 -0700
     3.2 +++ b/src/joystick/android/SDL_sysjoystick.c	Thu Mar 12 19:47:30 2020 -0700
     3.3 @@ -410,7 +410,7 @@
     3.4      SDL_zerop(item);
     3.5      item->guid = guid;
     3.6      item->device_id = device_id;
     3.7 -    item->name = SDL_strdup(name);
     3.8 +    item->name = SDL_CreateJoystickName(vendor_id, product_id, NULL, name);
     3.9      if (item->name == NULL) {
    3.10           SDL_free(item);
    3.11           return -1;
    3.12 @@ -443,7 +443,7 @@
    3.13      SDL_PrivateJoystickAdded(item->device_instance);
    3.14  
    3.15  #ifdef DEBUG_JOYSTICK
    3.16 -    SDL_Log("Added joystick %s with device_id %d", name, device_id);
    3.17 +    SDL_Log("Added joystick %s with device_id %d", item->name, device_id);
    3.18  #endif
    3.19  
    3.20      return numjoysticks;
     4.1 --- a/src/joystick/darwin/SDL_sysjoystick.c	Thu Mar 12 19:47:28 2020 -0700
     4.2 +++ b/src/joystick/darwin/SDL_sysjoystick.c	Thu Mar 12 19:47:30 2020 -0700
     4.3 @@ -404,7 +404,7 @@
     4.4      Sint32 vendor = 0;
     4.5      Sint32 product = 0;
     4.6      Sint32 version = 0;
     4.7 -    const char *name;
     4.8 +    char *name;
     4.9      const char *manufacturer_remapped;
    4.10      char manufacturer_string[256];
    4.11      char product_string[256];
    4.12 @@ -460,36 +460,18 @@
    4.13      }
    4.14  
    4.15      /* get device name */
    4.16 -    name = SDL_GetCustomJoystickName(vendor, product);
    4.17 +    refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDManufacturerKey));
    4.18 +    if ((!refCF) || (!CFStringGetCString(refCF, manufacturer_string, sizeof(manufacturer_string), kCFStringEncodingUTF8))) {
    4.19 +        manufacturer_string[0] = '\0';
    4.20 +    }
    4.21 +    refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDProductKey));
    4.22 +    if ((!refCF) || (!CFStringGetCString(refCF, product_string, sizeof(product_string), kCFStringEncodingUTF8))) {
    4.23 +        product_string[0] = '\0';
    4.24 +    }
    4.25 +    name = SDL_CreateJoystickName(vendor, product, manufacturer_string, product_string);
    4.26      if (name) {
    4.27          SDL_strlcpy(pDevice->product, name, sizeof(pDevice->product));
    4.28 -    } else {
    4.29 -        refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDManufacturerKey));
    4.30 -        if ((!refCF) || (!CFStringGetCString(refCF, manufacturer_string, sizeof(manufacturer_string), kCFStringEncodingUTF8))) {
    4.31 -            manufacturer_string[0] = '\0';
    4.32 -        }
    4.33 -        refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDProductKey));
    4.34 -        if ((!refCF) || (!CFStringGetCString(refCF, product_string, sizeof(product_string), kCFStringEncodingUTF8))) {
    4.35 -            SDL_strlcpy(product_string, "Unidentified joystick", sizeof(product_string));
    4.36 -        }
    4.37 -        for (i = (int)SDL_strlen(manufacturer_string) - 1; i > 0; --i) {
    4.38 -            if (SDL_isspace(manufacturer_string[i])) {
    4.39 -                manufacturer_string[i] = '\0';
    4.40 -            } else {
    4.41 -                break;
    4.42 -            }
    4.43 -        }
    4.44 -
    4.45 -        manufacturer_remapped = SDL_GetCustomJoystickManufacturer(manufacturer_string);
    4.46 -        if (manufacturer_remapped != manufacturer_string) {
    4.47 -            SDL_strlcpy(manufacturer_string, manufacturer_remapped, sizeof(manufacturer_string));
    4.48 -        }
    4.49 -
    4.50 -        if (SDL_strncasecmp(manufacturer_string, product_string, SDL_strlen(manufacturer_string)) == 0) {
    4.51 -            SDL_strlcpy(pDevice->product, product_string, sizeof(pDevice->product));
    4.52 -        } else {
    4.53 -            SDL_snprintf(pDevice->product, sizeof(pDevice->product), "%s %s", manufacturer_string, product_string);
    4.54 -        }
    4.55 +        SDL_free(name);
    4.56      }
    4.57  
    4.58  #ifdef SDL_JOYSTICK_HIDAPI
     5.1 --- a/src/joystick/emscripten/SDL_sysjoystick.c	Thu Mar 12 19:47:28 2020 -0700
     5.2 +++ b/src/joystick/emscripten/SDL_sysjoystick.c	Thu Mar 12 19:47:30 2020 -0700
     5.3 @@ -60,7 +60,7 @@
     5.4      SDL_zerop(item);
     5.5      item->index = gamepadEvent->index;
     5.6  
     5.7 -    item->name = SDL_strdup(gamepadEvent->id);
     5.8 +    item->name = SDL_CreateJoystickName(0, 0, NULL, gamepadEvent->id);
     5.9      if ( item->name == NULL ) {
    5.10          SDL_free(item);
    5.11          return 1;
     6.1 --- a/src/joystick/haiku/SDL_haikujoystick.cc	Thu Mar 12 19:47:28 2020 -0700
     6.2 +++ b/src/joystick/haiku/SDL_haikujoystick.cc	Thu Mar 12 19:47:30 2020 -0700
     6.3 @@ -75,7 +75,7 @@
     6.4                      BString stick_name;
     6.5                        joystick.GetControllerName(&stick_name);
     6.6                        SDL_joyport[numjoysticks] = SDL_strdup(name);
     6.7 -                      SDL_joyname[numjoysticks] = SDL_strdup(stick_name.String());
     6.8 +                      SDL_joyname[numjoysticks] = SDL_CreateJoystickName(0, 0, NULL, stick_name.String());
     6.9                        numjoysticks++;
    6.10                        joystick.Close();
    6.11                  }
     7.1 --- a/src/joystick/hidapi/SDL_hidapijoystick.c	Thu Mar 12 19:47:28 2020 -0700
     7.2 +++ b/src/joystick/hidapi/SDL_hidapijoystick.c	Thu Mar 12 19:47:30 2020 -0700
     7.3 @@ -698,14 +698,7 @@
     7.4      device->dev_lock = SDL_CreateMutex();
     7.5  
     7.6      /* Need the device name before getting the driver to know whether to ignore this device */
     7.7 -    if (!device->name) {
     7.8 -        const char *name = SDL_GetCustomJoystickName(device->vendor_id, device->product_id);
     7.9 -        if (name) {
    7.10 -            device->name = SDL_strdup(name);
    7.11 -        }
    7.12 -    }
    7.13 -    if (!device->name && info->manufacturer_string && info->product_string) {
    7.14 -        const char *manufacturer_remapped;
    7.15 +    {
    7.16          char *manufacturer_string = SDL_iconv_string("UTF-8", "WCHAR_T", (char*)info->manufacturer_string, (SDL_wcslen(info->manufacturer_string)+1)*sizeof(wchar_t));
    7.17          char *product_string = SDL_iconv_string("UTF-8", "WCHAR_T", (char*)info->product_string, (SDL_wcslen(info->product_string)+1)*sizeof(wchar_t));
    7.18          if (!manufacturer_string && !product_string) {
    7.19 @@ -718,39 +711,20 @@
    7.20              }
    7.21          }
    7.22  
    7.23 -        manufacturer_remapped = SDL_GetCustomJoystickManufacturer(manufacturer_string);
    7.24 -        if (manufacturer_remapped != manufacturer_string) {
    7.25 -            SDL_free(manufacturer_string);
    7.26 -            manufacturer_string = SDL_strdup(manufacturer_remapped);
    7.27 -        }
    7.28 +        device->name = SDL_CreateJoystickName(device->vendor_id, device->product_id, manufacturer_string, product_string);
    7.29  
    7.30 -        if (manufacturer_string && product_string) {
    7.31 -            size_t name_size = (SDL_strlen(manufacturer_string) + 1 + SDL_strlen(product_string) + 1);
    7.32 -            device->name = (char *)SDL_malloc(name_size);
    7.33 -            if (device->name) {
    7.34 -                if (SDL_strncasecmp(manufacturer_string, product_string, SDL_strlen(manufacturer_string)) == 0) {
    7.35 -                    SDL_strlcpy(device->name, product_string, name_size);
    7.36 -                } else {
    7.37 -                    SDL_snprintf(device->name, name_size, "%s %s", manufacturer_string, product_string);
    7.38 -                }
    7.39 -            }
    7.40 -        }
    7.41          if (manufacturer_string) {
    7.42              SDL_free(manufacturer_string);
    7.43          }
    7.44          if (product_string) {
    7.45              SDL_free(product_string);
    7.46          }
    7.47 -    }
    7.48 -    if (!device->name) {
    7.49 -        size_t name_size = (6 + 1 + 6 + 1);
    7.50 -        device->name = (char *)SDL_malloc(name_size);
    7.51 +
    7.52          if (!device->name) {
    7.53              SDL_free(device->path);
    7.54              SDL_free(device);
    7.55              return;
    7.56          }
    7.57 -        SDL_snprintf(device->name, name_size, "0x%.4x/0x%.4x", info->vendor_id, info->product_id);
    7.58      }
    7.59  
    7.60      /* Add it to the list */
     8.1 --- a/src/joystick/iphoneos/SDL_sysjoystick.m	Thu Mar 12 19:47:28 2020 -0700
     8.2 +++ b/src/joystick/iphoneos/SDL_sysjoystick.m	Thu Mar 12 19:47:30 2020 -0700
     8.3 @@ -125,7 +125,7 @@
     8.4          name = "MFi Gamepad";
     8.5      }
     8.6  
     8.7 -    device->name = SDL_strdup(name);
     8.8 +    device->name = SDL_CreateJoystickName(0, 0, NULL, name);
     8.9  
    8.10      if (controller.extendedGamepad) {
    8.11          GCExtendedGamepad *gamepad = controller.extendedGamepad;
     9.1 --- a/src/joystick/linux/SDL_sysjoystick.c	Thu Mar 12 19:47:28 2020 -0700
     9.2 +++ b/src/joystick/linux/SDL_sysjoystick.c	Thu Mar 12 19:47:30 2020 -0700
     9.3 @@ -88,20 +88,6 @@
     9.4      (((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0)
     9.5  #define NBITS(x) ((((x)-1)/(sizeof(long) * 8))+1)
     9.6  
     9.7 -static int
     9.8 -PrefixMatch(const char *a, const char *b)
     9.9 -{
    9.10 -    int matchlen = 0;
    9.11 -    while (*a && *b) {
    9.12 -        if (*a++ == *b++) {
    9.13 -            ++matchlen;
    9.14 -        } else {
    9.15 -            break;
    9.16 -        }
    9.17 -    }
    9.18 -    return matchlen;
    9.19 -}
    9.20 -
    9.21  static void
    9.22  FixupDeviceInfoForMapping(int fd, struct input_id *inpid)
    9.23  {
    9.24 @@ -120,12 +106,12 @@
    9.25  
    9.26  
    9.27  static int
    9.28 -IsJoystick(int fd, char *namebuf, const size_t namebuflen, SDL_JoystickGUID *guid)
    9.29 +IsJoystick(int fd, char **name_return, SDL_JoystickGUID *guid)
    9.30  {
    9.31      struct input_id inpid;
    9.32      Uint16 *guid16 = (Uint16 *)guid->data;
    9.33 -    const char *name;
    9.34 -    const char *spot;
    9.35 +    char *name;
    9.36 +    char product_string[128];
    9.37  
    9.38  #if !SDL_USE_LIBUDEV
    9.39      /* When udev is enabled we only get joystick devices here, so there's no need to test them */
    9.40 @@ -149,27 +135,19 @@
    9.41          return 0;
    9.42      }
    9.43  
    9.44 -    name = SDL_GetCustomJoystickName(inpid.vendor, inpid.product);
    9.45 -    if (name) {
    9.46 -        SDL_strlcpy(namebuf, name, namebuflen);
    9.47 -    } else {
    9.48 -        if (ioctl(fd, EVIOCGNAME(namebuflen), namebuf) < 0) {
    9.49 -            return 0;
    9.50 -        }
    9.51 +    if (ioctl(fd, EVIOCGNAME(sizeof(product_string)), product_string) < 0) {
    9.52 +        return 0;
    9.53 +    }
    9.54  
    9.55 -        /* Remove duplicate manufacturer in the name */
    9.56 -        for (spot = namebuf + 1; *spot; ++spot) {
    9.57 -            int matchlen = PrefixMatch(namebuf, spot);
    9.58 -            if (matchlen > 0 && spot[matchlen - 1] == ' ') {
    9.59 -                SDL_memmove(namebuf, spot, SDL_strlen(spot)+1);
    9.60 -                break;
    9.61 -            }
    9.62 -        }
    9.63 +    name = SDL_CreateJoystickName(inpid.vendor, inpid.product, NULL, product_string);
    9.64 +    if (!name) {
    9.65 +        return 0;
    9.66      }
    9.67  
    9.68  #ifdef SDL_JOYSTICK_HIDAPI
    9.69 -    if (HIDAPI_IsDevicePresent(inpid.vendor, inpid.product, inpid.version, namebuf)) {
    9.70 +    if (HIDAPI_IsDevicePresent(inpid.vendor, inpid.product, inpid.version, name)) {
    9.71          /* The HIDAPI driver is taking care of this device */
    9.72 +        SDL_free(name);
    9.73          return 0;
    9.74      }
    9.75  #endif
    9.76 @@ -177,7 +155,7 @@
    9.77      FixupDeviceInfoForMapping(fd, &inpid);
    9.78  
    9.79  #ifdef DEBUG_JOYSTICK
    9.80 -    printf("Joystick: %s, bustype = %d, vendor = 0x%.4x, product = 0x%.4x, version = %d\n", namebuf, inpid.bustype, inpid.vendor, inpid.product, inpid.version);
    9.81 +    printf("Joystick: %s, bustype = %d, vendor = 0x%.4x, product = 0x%.4x, version = %d\n", name, inpid.bustype, inpid.vendor, inpid.product, inpid.version);
    9.82  #endif
    9.83  
    9.84      SDL_memset(guid->data, 0, sizeof(guid->data));
    9.85 @@ -195,12 +173,14 @@
    9.86          *guid16++ = SDL_SwapLE16(inpid.version);
    9.87          *guid16++ = 0;
    9.88      } else {
    9.89 -        SDL_strlcpy((char*)guid16, namebuf, sizeof(guid->data) - 4);
    9.90 +        SDL_strlcpy((char*)guid16, name, sizeof(guid->data) - 4);
    9.91      }
    9.92  
    9.93 -    if (SDL_ShouldIgnoreJoystick(namebuf, *guid)) {
    9.94 +    if (SDL_ShouldIgnoreJoystick(name, *guid)) {
    9.95 +        SDL_free(name);
    9.96          return 0;
    9.97      }
    9.98 +    *name_return = name;
    9.99      return 1;
   9.100  }
   9.101  
   9.102 @@ -236,7 +216,7 @@
   9.103      struct stat sb;
   9.104      int fd = -1;
   9.105      int isstick = 0;
   9.106 -    char namebuf[128];
   9.107 +    char *name = NULL;
   9.108      SDL_JoystickGUID guid;
   9.109      SDL_joylist_item *item;
   9.110  
   9.111 @@ -264,7 +244,7 @@
   9.112      printf("Checking %s\n", path);
   9.113  #endif
   9.114  
   9.115 -    isstick = IsJoystick(fd, namebuf, sizeof (namebuf), &guid);
   9.116 +    isstick = IsJoystick(fd, &name, &guid);
   9.117      close(fd);
   9.118      if (!isstick) {
   9.119          return -1;
   9.120 @@ -278,7 +258,7 @@
   9.121      SDL_zerop(item);
   9.122      item->devnum = sb.st_rdev;
   9.123      item->path = SDL_strdup(path);
   9.124 -    item->name = SDL_strdup(namebuf);
   9.125 +    item->name = name;
   9.126      item->guid = guid;
   9.127  
   9.128      if ((item->path == NULL) || (item->name == NULL)) {
    10.1 --- a/src/joystick/windows/SDL_dinputjoystick.c	Thu Mar 12 19:47:28 2020 -0700
    10.2 +++ b/src/joystick/windows/SDL_dinputjoystick.c	Thu Mar 12 19:47:30 2020 -0700
    10.3 @@ -244,7 +244,7 @@
    10.4  static const IID IID_IWbemLocator = { 0xdc12a687, 0x737f, 0x11cf,{ 0x88, 0x4d, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24 } };
    10.5  
    10.6  static SDL_bool
    10.7 -WIN_IsXInputDevice(const GUID* pGuidProductFromDirectInput)
    10.8 +WIN_IsXInputDevice(LPTSTR *name, const GUID* pGuidProductFromDirectInput)
    10.9  {
   10.10      IWbemLocator*           pIWbemLocator = NULL;
   10.11      IEnumWbemClassObject*   pEnumDevices = NULL;
   10.12 @@ -259,6 +259,17 @@
   10.13      VARIANT                 var;
   10.14      HRESULT                 hr;
   10.15  
   10.16 +    if (!SDL_XINPUT_Enabled()) {
   10.17 +        return SDL_FALSE;
   10.18 +    }
   10.19 +
   10.20 +    if (SDL_wcsstr(name, " XINPUT ") != NULL) {
   10.21 +        /* This is a duplicate interface for a controller that will show up with XInput,
   10.22 +           e.g. Xbox One Elite Series 2 in Bluetooth mode.
   10.23 +         */
   10.24 +        return SDL_TRUE;
   10.25 +    }
   10.26 +
   10.27      SDL_zeroa(pDevices);
   10.28  
   10.29      // Create WMI
   10.30 @@ -363,7 +374,7 @@
   10.31  #endif /* 0 */
   10.32  
   10.33  static SDL_bool
   10.34 -SDL_IsXInputDevice(const GUID* pGuidProductFromDirectInput)
   10.35 +SDL_IsXInputDevice(LPTSTR *name, const GUID* pGuidProductFromDirectInput)
   10.36  {
   10.37      UINT i;
   10.38  
   10.39 @@ -371,6 +382,13 @@
   10.40          return SDL_FALSE;
   10.41      }
   10.42  
   10.43 +    if (SDL_wcsstr(name, " XINPUT ") != NULL) {
   10.44 +        /* This is a duplicate interface for a controller that will show up with XInput,
   10.45 +           e.g. Xbox One Elite Series 2 in Bluetooth mode.
   10.46 +         */
   10.47 +        return SDL_TRUE;
   10.48 +    }
   10.49 +
   10.50      if (SDL_memcmp(&pGuidProductFromDirectInput->Data4[2], "PIDVID", 6) == 0) {
   10.51          Uint16 vendor_id = (Uint16)LOWORD(pGuidProductFromDirectInput->Data1);
   10.52          Uint16 product_id = (Uint16)HIWORD(pGuidProductFromDirectInput->Data1);
   10.53 @@ -521,7 +539,7 @@
   10.54      Uint16 product = 0;
   10.55      Uint16 version = 0;
   10.56      WCHAR hidPath[MAX_PATH];
   10.57 -    const char *name;
   10.58 +    char *name;
   10.59  
   10.60      if (devtype == DI8DEVTYPE_SUPPLEMENTAL) {
   10.61          /* Add any supplemental devices that should be ignored here */
   10.62 @@ -539,7 +557,7 @@
   10.63          }
   10.64      }
   10.65  
   10.66 -    if (SDL_IsXInputDevice(&pdidInstance->guidProduct)) {
   10.67 +    if (SDL_IsXInputDevice(pdidInstance->tszProductName, &pdidInstance->guidProduct)) {
   10.68          return DIENUM_CONTINUE;  /* ignore XInput devices here, keep going. */
   10.69      }
   10.70  
   10.71 @@ -609,12 +627,22 @@
   10.72      SDL_memcpy(&pNewJoystick->dxdevice, pdidInstance, sizeof(DIDEVICEINSTANCE));
   10.73      SDL_memset(pNewJoystick->guid.data, 0, sizeof(pNewJoystick->guid.data));
   10.74  
   10.75 -    guid16 = (Uint16 *)pNewJoystick->guid.data;
   10.76      if (SDL_memcmp(&pdidInstance->guidProduct.Data4[2], "PIDVID", 6) == 0) {
   10.77          vendor = (Uint16)LOWORD(pdidInstance->guidProduct.Data1);
   10.78          product = (Uint16)HIWORD(pdidInstance->guidProduct.Data1);
   10.79 -        version = 0;
   10.80 +    }
   10.81 +
   10.82 +    name = WIN_StringToUTF8(pdidInstance->tszProductName);
   10.83 +    pNewJoystick->joystickname = SDL_CreateJoystickName(vendor, product, NULL, name);
   10.84 +    SDL_free(name);
   10.85  
   10.86 +    if (!pNewJoystick->joystickname) {
   10.87 +        SDL_free(pNewJoystick);
   10.88 +        return DIENUM_CONTINUE; /* better luck next time? */
   10.89 +    }
   10.90 +
   10.91 +    guid16 = (Uint16 *)pNewJoystick->guid.data;
   10.92 +    if (SDL_memcmp(&pdidInstance->guidProduct.Data4[2], "PIDVID", 6) == 0) {
   10.93          *guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_USB);
   10.94          *guid16++ = 0;
   10.95          *guid16++ = SDL_SwapLE16(vendor);
   10.96 @@ -629,26 +657,6 @@
   10.97          SDL_strlcpy((char*)guid16, pNewJoystick->joystickname, sizeof(pNewJoystick->guid.data) - 4);
   10.98      }
   10.99  
  10.100 -    name = SDL_GetCustomJoystickName(vendor, product);
  10.101 -    if (name) {
  10.102 -        pNewJoystick->joystickname = SDL_strdup(name);
  10.103 -    } else {
  10.104 -        pNewJoystick->joystickname = WIN_StringToUTF8(pdidInstance->tszProductName);
  10.105 -    }
  10.106 -    if (!pNewJoystick->joystickname) {
  10.107 -        SDL_free(pNewJoystick);
  10.108 -        return DIENUM_CONTINUE; /* better luck next time? */
  10.109 -    }
  10.110 -
  10.111 -    if (SDL_strstr(pNewJoystick->joystickname, " XINPUT ") != NULL) {
  10.112 -        /* This is a duplicate interface for a controller that will show up with XInput,
  10.113 -           e.g. Xbox One Elite Series 2 in Bluetooth mode.
  10.114 -         */
  10.115 -        SDL_free(pNewJoystick->joystickname);
  10.116 -        SDL_free(pNewJoystick);
  10.117 -        return DIENUM_CONTINUE;
  10.118 -    }
  10.119 -
  10.120      if (SDL_ShouldIgnoreJoystick(pNewJoystick->joystickname, pNewJoystick->guid)) {
  10.121          SDL_free(pNewJoystick->joystickname);
  10.122          SDL_free(pNewJoystick);
    11.1 --- a/src/joystick/windows/SDL_xinputjoystick.c	Thu Mar 12 19:47:28 2020 -0700
    11.2 +++ b/src/joystick/windows/SDL_xinputjoystick.c	Thu Mar 12 19:47:30 2020 -0700
    11.3 @@ -71,10 +71,10 @@
    11.4      return 0;
    11.5  }
    11.6  
    11.7 -static char *
    11.8 +static const char *
    11.9  GetXInputName(const Uint8 userid, BYTE SubType)
   11.10  {
   11.11 -    char name[32];
   11.12 +    static char name[32];
   11.13  
   11.14      if (SDL_XInputUseOldJoystickMapping()) {
   11.15          SDL_snprintf(name, sizeof(name), "X360 Controller #%u", 1 + userid);
   11.16 @@ -111,7 +111,7 @@
   11.17              break;
   11.18          }
   11.19      }
   11.20 -    return SDL_strdup(name);
   11.21 +    return name;
   11.22  }
   11.23  
   11.24  /* We can't really tell what device is being used for XInput, but we can guess
   11.25 @@ -274,13 +274,7 @@
   11.26      }
   11.27      pNewJoystick->SubType = SubType;
   11.28      pNewJoystick->XInputUserId = userid;
   11.29 -
   11.30 -    name = SDL_GetCustomJoystickName(vendor, product);
   11.31 -    if (name) {
   11.32 -        pNewJoystick->joystickname = SDL_strdup(name);
   11.33 -    } else {
   11.34 -        pNewJoystick->joystickname = GetXInputName(userid, SubType);
   11.35 -    }
   11.36 +    pNewJoystick->joystickname = SDL_CreateJoystickName(vendor, product, NULL, GetXInputName(userid, SubType));
   11.37      if (!pNewJoystick->joystickname) {
   11.38          SDL_free(pNewJoystick);
   11.39          return; /* better luck next time? */