Skip to content

Commit

Permalink
Unified code to standardize joystick names
Browse files Browse the repository at this point in the history
  • Loading branch information
slouken committed Mar 13, 2020
1 parent db3b3a1 commit c44473b
Show file tree
Hide file tree
Showing 11 changed files with 182 additions and 173 deletions.
132 changes: 102 additions & 30 deletions src/joystick/SDL_joystick.c
Expand Up @@ -278,23 +278,6 @@ SDL_GetDriverAndJoystickIndex(int device_index, SDL_JoystickDriver **driver, int
return SDL_FALSE;
}

/*
* Perform any needed fixups for joystick names
*/
static const char *
SDL_FixupJoystickName(const char *name)
{
if (name) {
const char *skip_prefix = "NVIDIA Corporation ";

if (SDL_strncmp(name, skip_prefix, SDL_strlen(skip_prefix)) == 0) {
name += SDL_strlen(skip_prefix);
}
}
return name;
}


/*
* Get the implementation dependent name of a joystick
*/
Expand All @@ -306,7 +289,7 @@ SDL_JoystickNameForIndex(int device_index)

SDL_LockJoysticks();
if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
name = SDL_FixupJoystickName(driver->GetDeviceName(device_index));
name = driver->GetDeviceName(device_index);
}
SDL_UnlockJoysticks();

Expand Down Expand Up @@ -721,7 +704,7 @@ SDL_JoystickName(SDL_Joystick * joystick)
return NULL;
}

return SDL_FixupJoystickName(joystick->name);
return joystick->name;
}

/**
Expand Down Expand Up @@ -1369,23 +1352,112 @@ void SDL_GetJoystickGUIDInfo(SDL_JoystickGUID guid, Uint16 *vendor, Uint16 *prod
}
}

const char *
SDL_GetCustomJoystickManufacturer(const char *manufacturer)
static int
PrefixMatch(const char *a, const char *b)
{
if (manufacturer) {
if (SDL_strcmp(manufacturer, "Performance Designed Products") == 0) {
return "PDP";
} else if (SDL_strcmp(manufacturer, "HORI CO.,LTD") == 0) {
return "HORI";
int matchlen = 0;
while (*a && *b) {
if (*a++ == *b++) {
++matchlen;
} else {
break;
}
}
return manufacturer;
return matchlen;
}

const char *
SDL_GetCustomJoystickName(Uint16 vendor, Uint16 product)
char *
SDL_CreateJoystickName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name)
{
return GuessControllerName(vendor, product);
static struct {
const char *prefix;
const char *replacement;
} replacements[] = {
{ "NVIDIA Corporation ", "" },
{ "Performance Designed Products", "PDP" },
{ "HORI CO.,LTD", "HORI" },
};
const char *custom_name;
char *name;
size_t i, len;

custom_name = GuessControllerName(vendor, product);
if (custom_name) {
return SDL_strdup(custom_name);
}

if (!vendor_name) {
vendor_name = "";
}
if (!product_name) {
product_name = "";
}

while (*vendor_name == ' ') {
++vendor_name;
}
while (*product_name == ' ') {
++product_name;
}

if (*vendor_name && *product_name) {
len = (SDL_strlen(vendor_name) + 1 + SDL_strlen(product_name) + 1);
name = (char *)SDL_malloc(len);
if (!name) {
return NULL;
}
SDL_snprintf(name, len, "%s %s", vendor_name, product_name);
} else if (*product_name) {
name = SDL_strdup(product_name);
} else if (vendor || product) {
len = (6 + 1 + 6 + 1);
name = (char *)SDL_malloc(len);
if (!name) {
return NULL;
}
SDL_snprintf(name, len, "0x%.4x/0x%.4x", vendor, product);
} else {
name = SDL_strdup("Controller");
}

/* Trim trailing whitespace */
for (len = SDL_strlen(name); (len > 0 && name[len - 1] == ' '); --len) {
/* continue */
}
name[len] = '\0';

/* Compress duplicate spaces */
for (i = 0; i < (len - 1); ) {
if (name[i] == ' ' && name[i+1] == ' ') {
SDL_memmove(&name[i], &name[i+1], (len - i));
--len;
} else {
++i;
}
}

/* Remove duplicate manufacturer in the name */
for (i = 0; i < (len - 1); ++i) {
int matchlen = PrefixMatch(name, &name[i]);
if (matchlen > 0 && name[matchlen - 1] == ' ') {
SDL_memmove(name, name+matchlen, len-matchlen+1);
len -= matchlen;
break;
}
}

/* Perform any manufacturer replacements */
for (i = 0; i < SDL_arraysize(replacements); ++i) {
size_t prefixlen = SDL_strlen(replacements[i].prefix);
if (SDL_strncasecmp(name, replacements[i].prefix, prefixlen) == 0) {
size_t replacementlen = SDL_strlen(replacements[i].replacement);
SDL_memcpy(name, replacements[i].replacement, replacementlen);
SDL_memmove(name+replacementlen, name+prefixlen, (len-prefixlen+1));
break;
}
}

return name;
}

SDL_GameControllerType
Expand Down
9 changes: 4 additions & 5 deletions src/joystick/SDL_joystick_c.h
Expand Up @@ -52,11 +52,10 @@ extern int SDL_JoystickGetDeviceIndexFromInstanceID(SDL_JoystickID instance_id);
/* Function to extract information from an SDL joystick GUID */
extern void SDL_GetJoystickGUIDInfo(SDL_JoystickGUID guid, Uint16 *vendor, Uint16 *product, Uint16 *version);

/* Function to get a custom name for a controller manufacturer, if it's available */
extern const char *SDL_GetCustomJoystickManufacturer(const char *manufacturer);

/* Function to get a custom name for a controller, if it's available */
extern const char *SDL_GetCustomJoystickName(Uint16 vendor, Uint16 product);
/* Function to standardize the name for a controller
This should be freed with SDL_free() when no longer needed
*/
extern char *SDL_CreateJoystickName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name);

/* Function to return the type of a controller */
extern SDL_GameControllerType SDL_GetJoystickGameControllerTypeFromGUID(SDL_JoystickGUID guid, const char *name);
Expand Down
4 changes: 2 additions & 2 deletions src/joystick/android/SDL_sysjoystick.c
Expand Up @@ -410,7 +410,7 @@ Android_AddJoystick(int device_id, const char *name, const char *desc, int vendo
SDL_zerop(item);
item->guid = guid;
item->device_id = device_id;
item->name = SDL_strdup(name);
item->name = SDL_CreateJoystickName(vendor_id, product_id, NULL, name);
if (item->name == NULL) {
SDL_free(item);
return -1;
Expand Down Expand Up @@ -443,7 +443,7 @@ Android_AddJoystick(int device_id, const char *name, const char *desc, int vendo
SDL_PrivateJoystickAdded(item->device_instance);

#ifdef DEBUG_JOYSTICK
SDL_Log("Added joystick %s with device_id %d", name, device_id);
SDL_Log("Added joystick %s with device_id %d", item->name, device_id);
#endif

return numjoysticks;
Expand Down
40 changes: 11 additions & 29 deletions src/joystick/darwin/SDL_sysjoystick.c
Expand Up @@ -404,7 +404,7 @@ GetDeviceInfo(IOHIDDeviceRef hidDevice, recDevice *pDevice)
Sint32 vendor = 0;
Sint32 product = 0;
Sint32 version = 0;
const char *name;
char *name;
const char *manufacturer_remapped;
char manufacturer_string[256];
char product_string[256];
Expand Down Expand Up @@ -460,36 +460,18 @@ GetDeviceInfo(IOHIDDeviceRef hidDevice, recDevice *pDevice)
}

/* get device name */
name = SDL_GetCustomJoystickName(vendor, product);
refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDManufacturerKey));
if ((!refCF) || (!CFStringGetCString(refCF, manufacturer_string, sizeof(manufacturer_string), kCFStringEncodingUTF8))) {
manufacturer_string[0] = '\0';
}
refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDProductKey));
if ((!refCF) || (!CFStringGetCString(refCF, product_string, sizeof(product_string), kCFStringEncodingUTF8))) {
product_string[0] = '\0';
}
name = SDL_CreateJoystickName(vendor, product, manufacturer_string, product_string);
if (name) {
SDL_strlcpy(pDevice->product, name, sizeof(pDevice->product));
} else {
refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDManufacturerKey));
if ((!refCF) || (!CFStringGetCString(refCF, manufacturer_string, sizeof(manufacturer_string), kCFStringEncodingUTF8))) {
manufacturer_string[0] = '\0';
}
refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDProductKey));
if ((!refCF) || (!CFStringGetCString(refCF, product_string, sizeof(product_string), kCFStringEncodingUTF8))) {
SDL_strlcpy(product_string, "Unidentified joystick", sizeof(product_string));
}
for (i = (int)SDL_strlen(manufacturer_string) - 1; i > 0; --i) {
if (SDL_isspace(manufacturer_string[i])) {
manufacturer_string[i] = '\0';
} else {
break;
}
}

manufacturer_remapped = SDL_GetCustomJoystickManufacturer(manufacturer_string);
if (manufacturer_remapped != manufacturer_string) {
SDL_strlcpy(manufacturer_string, manufacturer_remapped, sizeof(manufacturer_string));
}

if (SDL_strncasecmp(manufacturer_string, product_string, SDL_strlen(manufacturer_string)) == 0) {
SDL_strlcpy(pDevice->product, product_string, sizeof(pDevice->product));
} else {
SDL_snprintf(pDevice->product, sizeof(pDevice->product), "%s %s", manufacturer_string, product_string);
}
SDL_free(name);
}

#ifdef SDL_JOYSTICK_HIDAPI
Expand Down
2 changes: 1 addition & 1 deletion src/joystick/emscripten/SDL_sysjoystick.c
Expand Up @@ -60,7 +60,7 @@ Emscripten_JoyStickConnected(int eventType, const EmscriptenGamepadEvent *gamepa
SDL_zerop(item);
item->index = gamepadEvent->index;

item->name = SDL_strdup(gamepadEvent->id);
item->name = SDL_CreateJoystickName(0, 0, NULL, gamepadEvent->id);
if ( item->name == NULL ) {
SDL_free(item);
return 1;
Expand Down
2 changes: 1 addition & 1 deletion src/joystick/haiku/SDL_haikujoystick.cc
Expand Up @@ -75,7 +75,7 @@ extern "C"
BString stick_name;
joystick.GetControllerName(&stick_name);
SDL_joyport[numjoysticks] = SDL_strdup(name);
SDL_joyname[numjoysticks] = SDL_strdup(stick_name.String());
SDL_joyname[numjoysticks] = SDL_CreateJoystickName(0, 0, NULL, stick_name.String());
numjoysticks++;
joystick.Close();
}
Expand Down
32 changes: 3 additions & 29 deletions src/joystick/hidapi/SDL_hidapijoystick.c
Expand Up @@ -698,14 +698,7 @@ HIDAPI_AddDevice(struct hid_device_info *info)
device->dev_lock = SDL_CreateMutex();

/* Need the device name before getting the driver to know whether to ignore this device */
if (!device->name) {
const char *name = SDL_GetCustomJoystickName(device->vendor_id, device->product_id);
if (name) {
device->name = SDL_strdup(name);
}
}
if (!device->name && info->manufacturer_string && info->product_string) {
const char *manufacturer_remapped;
{
char *manufacturer_string = SDL_iconv_string("UTF-8", "WCHAR_T", (char*)info->manufacturer_string, (SDL_wcslen(info->manufacturer_string)+1)*sizeof(wchar_t));
char *product_string = SDL_iconv_string("UTF-8", "WCHAR_T", (char*)info->product_string, (SDL_wcslen(info->product_string)+1)*sizeof(wchar_t));
if (!manufacturer_string && !product_string) {
Expand All @@ -718,39 +711,20 @@ HIDAPI_AddDevice(struct hid_device_info *info)
}
}

manufacturer_remapped = SDL_GetCustomJoystickManufacturer(manufacturer_string);
if (manufacturer_remapped != manufacturer_string) {
SDL_free(manufacturer_string);
manufacturer_string = SDL_strdup(manufacturer_remapped);
}
device->name = SDL_CreateJoystickName(device->vendor_id, device->product_id, manufacturer_string, product_string);

if (manufacturer_string && product_string) {
size_t name_size = (SDL_strlen(manufacturer_string) + 1 + SDL_strlen(product_string) + 1);
device->name = (char *)SDL_malloc(name_size);
if (device->name) {
if (SDL_strncasecmp(manufacturer_string, product_string, SDL_strlen(manufacturer_string)) == 0) {
SDL_strlcpy(device->name, product_string, name_size);
} else {
SDL_snprintf(device->name, name_size, "%s %s", manufacturer_string, product_string);
}
}
}
if (manufacturer_string) {
SDL_free(manufacturer_string);
}
if (product_string) {
SDL_free(product_string);
}
}
if (!device->name) {
size_t name_size = (6 + 1 + 6 + 1);
device->name = (char *)SDL_malloc(name_size);

if (!device->name) {
SDL_free(device->path);
SDL_free(device);
return;
}
SDL_snprintf(device->name, name_size, "0x%.4x/0x%.4x", info->vendor_id, info->product_id);
}

/* Add it to the list */
Expand Down
2 changes: 1 addition & 1 deletion src/joystick/iphoneos/SDL_sysjoystick.m
Expand Up @@ -125,7 +125,7 @@ @interface GCMicroGamepad (SDL)
name = "MFi Gamepad";
}

device->name = SDL_strdup(name);
device->name = SDL_CreateJoystickName(0, 0, NULL, name);

if (controller.extendedGamepad) {
GCExtendedGamepad *gamepad = controller.extendedGamepad;
Expand Down

0 comments on commit c44473b

Please sign in to comment.