From 1f1ee6f77c492e17a9691c367110c11529fab3fb Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Wed, 20 Dec 2023 19:05:20 -0800
Subject: [PATCH] Use the original manufacturer and product strings for the
joystick CRC
This allows the most information possible for the CRC string, which is used to differentiate controllers with the same VID/PID.
Fixes https://github.com/libsdl-org/SDL/issues/8724
---
src/joystick/SDL_joystick.c | 17 +++++++++------
src/joystick/SDL_joystick_c.h | 2 +-
src/joystick/android/SDL_sysjoystick.c | 2 +-
src/joystick/apple/SDL_mfijoystick.m | 2 +-
src/joystick/bsd/SDL_bsdjoystick.c | 2 +-
src/joystick/darwin/SDL_iokitjoystick.c | 2 +-
src/joystick/hidapi/SDL_hidapijoystick.c | 21 ++++++++-----------
src/joystick/hidapi/SDL_hidapijoystick_c.h | 2 ++
src/joystick/linux/SDL_sysjoystick.c | 2 +-
src/joystick/virtual/SDL_virtualjoystick.c | 2 +-
src/joystick/windows/SDL_dinputjoystick.c | 4 ++--
src/joystick/windows/SDL_rawinputjoystick.c | 3 +--
.../windows/SDL_windows_gaming_input.c | 2 +-
src/joystick/windows/SDL_xinputjoystick.c | 6 ++++--
14 files changed, 37 insertions(+), 32 deletions(-)
diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
index b555449e53fa..b40f405c952d 100644
--- a/src/joystick/SDL_joystick.c
+++ b/src/joystick/SDL_joystick.c
@@ -2606,21 +2606,26 @@ char *SDL_CreateJoystickName(Uint16 vendor, Uint16 product, const char *vendor_n
return name;
}
-SDL_JoystickGUID SDL_CreateJoystickGUID(Uint16 bus, Uint16 vendor, Uint16 product, Uint16 version, const char *name, Uint8 driver_signature, Uint8 driver_data)
+SDL_JoystickGUID SDL_CreateJoystickGUID(Uint16 bus, Uint16 vendor, Uint16 product, Uint16 version, const char *vendor_name, const char *product_name, Uint8 driver_signature, Uint8 driver_data)
{
SDL_JoystickGUID guid;
Uint16 *guid16 = (Uint16 *)guid.data;
+ Uint16 crc = 0;
SDL_zero(guid);
- if (!name) {
- name = "";
+ if (vendor_name && *vendor_name && product_name && *product_name) {
+ SDL_crc16(crc, vendor_name, SDL_strlen(vendor_name));
+ SDL_crc16(crc, " ", 1);
+ SDL_crc16(crc, product_name, SDL_strlen(product_name));
+ } else if (product_name) {
+ SDL_crc16(crc, product_name, SDL_strlen(product_name));
}
/* We only need 16 bits for each of these; space them out to fill 128. */
/* Byteswap so devices get same GUID on little/big endian platforms. */
*guid16++ = SDL_SwapLE16(bus);
- *guid16++ = SDL_SwapLE16(SDL_crc16(0, name, SDL_strlen(name)));
+ *guid16++ = SDL_SwapLE16(crc);
if (vendor && product) {
*guid16++ = SDL_SwapLE16(vendor);
@@ -2638,14 +2643,14 @@ SDL_JoystickGUID SDL_CreateJoystickGUID(Uint16 bus, Uint16 vendor, Uint16 produc
guid.data[14] = driver_signature;
guid.data[15] = driver_data;
}
- SDL_strlcpy((char *)guid16, name, available_space);
+ SDL_strlcpy((char *)guid16, product_name, available_space);
}
return guid;
}
SDL_JoystickGUID SDL_CreateJoystickGUIDForName(const char *name)
{
- return SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_UNKNOWN, 0, 0, 0, name, 0, 0);
+ return SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_UNKNOWN, 0, 0, 0, NULL, name, 0, 0);
}
void SDL_SetJoystickGUIDVendor(SDL_JoystickGUID *guid, Uint16 vendor)
diff --git a/src/joystick/SDL_joystick_c.h b/src/joystick/SDL_joystick_c.h
index 636b79ef5f42..10dd13696a7b 100644
--- a/src/joystick/SDL_joystick_c.h
+++ b/src/joystick/SDL_joystick_c.h
@@ -60,7 +60,7 @@ extern SDL_bool SDL_JoysticksOpened(void);
extern char *SDL_CreateJoystickName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name);
/* Function to create a GUID for a joystick based on the VID/PID and name */
-extern SDL_JoystickGUID SDL_CreateJoystickGUID(Uint16 bus, Uint16 vendor, Uint16 product, Uint16 version, const char *name, Uint8 driver_signature, Uint8 driver_data);
+extern SDL_JoystickGUID SDL_CreateJoystickGUID(Uint16 bus, Uint16 vendor, Uint16 product, Uint16 version, const char *vendor_name, const char *product_name, Uint8 driver_signature, Uint8 driver_data);
/* Function to create a GUID for a joystick based on the name, with no VID/PID information */
extern SDL_JoystickGUID SDL_CreateJoystickGUIDForName(const char *name);
diff --git a/src/joystick/android/SDL_sysjoystick.c b/src/joystick/android/SDL_sysjoystick.c
index 601053659e6e..9eeed2384ac4 100644
--- a/src/joystick/android/SDL_sysjoystick.c
+++ b/src/joystick/android/SDL_sysjoystick.c
@@ -343,7 +343,7 @@ int Android_AddJoystick(int device_id, const char *name, const char *desc, int v
nhats = 0;
}
- guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_BLUETOOTH, vendor_id, product_id, 0, desc, 0, 0);
+ guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_BLUETOOTH, vendor_id, product_id, 0, NULL, desc, 0, 0);
/* Update the GUID with capability bits */
{
diff --git a/src/joystick/apple/SDL_mfijoystick.m b/src/joystick/apple/SDL_mfijoystick.m
index 3923e87a0500..1eb65697af10 100644
--- a/src/joystick/apple/SDL_mfijoystick.m
+++ b/src/joystick/apple/SDL_mfijoystick.m
@@ -659,7 +659,7 @@ static BOOL IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle
} else {
signature = device->button_mask;
}
- device->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_BLUETOOTH, vendor, product, signature, name, 'm', subtype);
+ device->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_BLUETOOTH, vendor, product, signature, NULL, name, 'm', subtype);
if (SDL_ShouldIgnoreJoystick(name, device->guid)) {
return SDL_FALSE;
diff --git a/src/joystick/bsd/SDL_bsdjoystick.c b/src/joystick/bsd/SDL_bsdjoystick.c
index 4a0403076759..27276af08bfa 100644
--- a/src/joystick/bsd/SDL_bsdjoystick.c
+++ b/src/joystick/bsd/SDL_bsdjoystick.c
@@ -425,7 +425,7 @@ static int MaybeAddDevice(const char *path)
struct usb_device_info di;
if (ioctl(hw->fd, USB_GET_DEVICEINFO, &di) != -1) {
name = SDL_CreateJoystickName(di.udi_vendorNo, di.udi_productNo, di.udi_vendor, di.udi_product);
- guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_USB, di.udi_vendorNo, di.udi_productNo, di.udi_releaseNo, name, 0, 0);
+ guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_USB, di.udi_vendorNo, di.udi_productNo, di.udi_releaseNo, di.udi_vendor, di.udi_product, 0, 0);
#ifdef SDL_JOYSTICK_HIDAPI
if (HIDAPI_IsDevicePresent(di.udi_vendorNo, di.udi_productNo, di.udi_releaseNo, name)) {
diff --git a/src/joystick/darwin/SDL_iokitjoystick.c b/src/joystick/darwin/SDL_iokitjoystick.c
index f5a7d76516a2..74a588be415c 100644
--- a/src/joystick/darwin/SDL_iokitjoystick.c
+++ b/src/joystick/darwin/SDL_iokitjoystick.c
@@ -497,7 +497,7 @@ static SDL_bool GetDeviceInfo(IOHIDDeviceRef hidDevice, recDevice *pDevice)
}
#endif
- pDevice->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_USB, (Uint16)vendor, (Uint16)product, (Uint16)version, pDevice->product, 0, 0);
+ pDevice->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_USB, (Uint16)vendor, (Uint16)product, (Uint16)version, manufacturer_string, product_string, 0, 0);
pDevice->steam_virtual_gamepad_slot = GetSteamVirtualGamepadSlot((Uint16)vendor, (Uint16)product, product_string);
array = IOHIDDeviceCopyMatchingElements(hidDevice, NULL, kIOHIDOptionsTypeNone);
diff --git a/src/joystick/hidapi/SDL_hidapijoystick.c b/src/joystick/hidapi/SDL_hidapijoystick.c
index 7f4558baa271..ce06c1172267 100644
--- a/src/joystick/hidapi/SDL_hidapijoystick.c
+++ b/src/joystick/hidapi/SDL_hidapijoystick.c
@@ -661,7 +661,7 @@ void HIDAPI_SetDeviceName(SDL_HIDAPI_Device *device, const char *name)
void HIDAPI_SetDeviceProduct(SDL_HIDAPI_Device *device, Uint16 vendor_id, Uint16 product_id)
{
/* Don't set the device product ID directly, or we'll constantly re-enumerate this device */
- device->guid = SDL_CreateJoystickGUID(device->guid.data[0], vendor_id, product_id, device->version, device->name, 'h', 0);
+ device->guid = SDL_CreateJoystickGUID(device->guid.data[0], vendor_id, product_id, device->version, device->manufacturer_string, device->product_string, 'h', 0);
}
static void HIDAPI_UpdateJoystickSerial(SDL_HIDAPI_Device *device)
@@ -894,18 +894,11 @@ static SDL_HIDAPI_Device *HIDAPI_AddDevice(const struct SDL_hid_device_info *inf
/* Need the device name before getting the driver to know whether to ignore this device */
{
- char *manufacturer_string = HIDAPI_ConvertString(info->manufacturer_string);
- char *product_string = HIDAPI_ConvertString(info->product_string);
char *serial_number = HIDAPI_ConvertString(info->serial_number);
- device->name = SDL_CreateJoystickName(device->vendor_id, device->product_id, manufacturer_string, product_string);
-
- if (manufacturer_string) {
- SDL_free(manufacturer_string);
- }
- if (product_string) {
- SDL_free(product_string);
- }
+ device->manufacturer_string = HIDAPI_ConvertString(info->manufacturer_string);
+ device->product_string = HIDAPI_ConvertString(info->product_string);
+ device->name = SDL_CreateJoystickName(device->vendor_id, device->product_id, device->manufacturer_string, device->product_string);
if (serial_number && *serial_number) {
device->serial = serial_number;
@@ -914,6 +907,8 @@ static SDL_HIDAPI_Device *HIDAPI_AddDevice(const struct SDL_hid_device_info *inf
}
if (!device->name) {
+ SDL_free(device->manufacturer_string);
+ SDL_free(device->product_string);
SDL_free(device->serial);
SDL_free(device->path);
SDL_free(device);
@@ -926,7 +921,7 @@ static SDL_HIDAPI_Device *HIDAPI_AddDevice(const struct SDL_hid_device_info *inf
} else {
bus = SDL_HARDWARE_BUS_USB;
}
- device->guid = SDL_CreateJoystickGUID(bus, device->vendor_id, device->product_id, device->version, device->name, 'h', 0);
+ device->guid = SDL_CreateJoystickGUID(bus, device->vendor_id, device->product_id, device->version, device->manufacturer_string, device->product_string, 'h', 0);
device->joystick_type = SDL_JOYSTICK_TYPE_GAMEPAD;
device->type = SDL_GetJoystickGameControllerProtocol(device->name, device->vendor_id, device->product_id, device->interface_number, device->interface_class, device->interface_subclass, device->interface_protocol);
@@ -996,6 +991,8 @@ static void HIDAPI_DelDevice(SDL_HIDAPI_Device *device)
device->magic = NULL;
SDL_DestroyMutex(device->dev_lock);
+ SDL_free(device->manufacturer_string);
+ SDL_free(device->product_string);
SDL_free(device->serial);
SDL_free(device->name);
SDL_free(device->path);
diff --git a/src/joystick/hidapi/SDL_hidapijoystick_c.h b/src/joystick/hidapi/SDL_hidapijoystick_c.h
index acca9a5c85ba..74f0b749c6f4 100644
--- a/src/joystick/hidapi/SDL_hidapijoystick_c.h
+++ b/src/joystick/hidapi/SDL_hidapijoystick_c.h
@@ -53,6 +53,8 @@ typedef struct SDL_HIDAPI_Device
{
const void *magic;
char *name;
+ char *manufacturer_string;
+ char *product_string;
char *path;
Uint16 vendor_id;
Uint16 product_id;
diff --git a/src/joystick/linux/SDL_sysjoystick.c b/src/joystick/linux/SDL_sysjoystick.c
index aef90cba9377..660887a93a90 100644
--- a/src/joystick/linux/SDL_sysjoystick.c
+++ b/src/joystick/linux/SDL_sysjoystick.c
@@ -323,7 +323,7 @@ static int IsJoystick(const char *path, int fd, char **name_return, Uint16 *vend
SDL_Log("Joystick: %s, bustype = %d, vendor = 0x%.4x, product = 0x%.4x, version = %d\n", name, inpid.bustype, inpid.vendor, inpid.product, inpid.version);
#endif
- *guid = SDL_CreateJoystickGUID(inpid.bustype, inpid.vendor, inpid.product, inpid.version, name, 0, 0);
+ *guid = SDL_CreateJoystickGUID(inpid.bustype, inpid.vendor, inpid.product, inpid.version, NULL, product_string, 0, 0);
if (SDL_ShouldIgnoreJoystick(name, *guid)) {
SDL_free(name);
diff --git a/src/joystick/virtual/SDL_virtualjoystick.c b/src/joystick/virtual/SDL_virtualjoystick.c
index 6fcdde1a8213..89b60d74eaa6 100644
--- a/src/joystick/virtual/SDL_virtualjoystick.c
+++ b/src/joystick/virtual/SDL_virtualjoystick.c
@@ -203,7 +203,7 @@ SDL_JoystickID SDL_JoystickAttachVirtualInner(const SDL_VirtualJoystickDesc *des
}
}
- hwdata->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_VIRTUAL, hwdata->desc.vendor_id, hwdata->desc.product_id, 0, name, 'v', (Uint8)hwdata->desc.type);
+ hwdata->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_VIRTUAL, hwdata->desc.vendor_id, hwdata->desc.product_id, 0, NULL, name, 'v', (Uint8)hwdata->desc.type);
/* Allocate fields for different control-types */
if (hwdata->desc.naxes > 0) {
diff --git a/src/joystick/windows/SDL_dinputjoystick.c b/src/joystick/windows/SDL_dinputjoystick.c
index 84cdae810490..bc79a97736de 100644
--- a/src/joystick/windows/SDL_dinputjoystick.c
+++ b/src/joystick/windows/SDL_dinputjoystick.c
@@ -509,9 +509,9 @@ static BOOL CALLBACK EnumJoystickDetectCallback(LPCDIDEVICEINSTANCE pDeviceInsta
CHECK(pNewJoystick->joystickname);
if (vendor && product) {
- pNewJoystick->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_USB, vendor, product, version, pNewJoystick->joystickname, 0, 0);
+ pNewJoystick->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_USB, vendor, product, version, NULL, name, 0, 0);
} else {
- pNewJoystick->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_BLUETOOTH, vendor, product, version, pNewJoystick->joystickname, 0, 0);
+ pNewJoystick->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_BLUETOOTH, vendor, product, version, NULL, name, 0, 0);
}
CHECK(!SDL_ShouldIgnoreJoystick(pNewJoystick->joystickname, pNewJoystick->guid));
diff --git a/src/joystick/windows/SDL_rawinputjoystick.c b/src/joystick/windows/SDL_rawinputjoystick.c
index 221e15132527..9c21352370b4 100644
--- a/src/joystick/windows/SDL_rawinputjoystick.c
+++ b/src/joystick/windows/SDL_rawinputjoystick.c
@@ -922,6 +922,7 @@ static void RAWINPUT_AddDevice(HANDLE hDevice)
}
device->name = SDL_CreateJoystickName(device->vendor_id, device->product_id, manufacturer_string, product_string);
+ device->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_USB, device->vendor_id, device->product_id, device->version, manufacturer_string, product_string, 'r', 0);
if (manufacturer_string) {
SDL_free(manufacturer_string);
@@ -931,8 +932,6 @@ static void RAWINPUT_AddDevice(HANDLE hDevice)
}
}
- device->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_USB, device->vendor_id, device->product_id, device->version, device->name, 'r', 0);
-
device->path = SDL_strdup(dev_name);
CloseHandle(hFile);
diff --git a/src/joystick/windows/SDL_windows_gaming_input.c b/src/joystick/windows/SDL_windows_gaming_input.c
index fe48b816fcc9..05efad4538e8 100644
--- a/src/joystick/windows/SDL_windows_gaming_input.c
+++ b/src/joystick/windows/SDL_windows_gaming_input.c
@@ -473,7 +473,7 @@ static HRESULT STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_InvokeAdde
type = GetGameControllerType(game_controller);
}
- guid = SDL_CreateJoystickGUID(bus, vendor, product, version, name, 'w', (Uint8)type);
+ guid = SDL_CreateJoystickGUID(bus, vendor, product, version, NULL, name, 'w', (Uint8)type);
if (SDL_ShouldIgnoreJoystick(name, guid)) {
ignore_joystick = SDL_TRUE;
diff --git a/src/joystick/windows/SDL_xinputjoystick.c b/src/joystick/windows/SDL_xinputjoystick.c
index 0949fe803090..0e00de57985a 100644
--- a/src/joystick/windows/SDL_xinputjoystick.c
+++ b/src/joystick/windows/SDL_xinputjoystick.c
@@ -154,6 +154,7 @@ int SDL_XINPUT_GetSteamVirtualGamepadSlot(Uint8 userid)
static void AddXInputDevice(Uint8 userid, BYTE SubType, JoyStick_DeviceData **pContext)
{
+ const char *name = NULL;
Uint16 vendor = 0;
Uint16 product = 0;
Uint16 version = 0;
@@ -205,16 +206,17 @@ static void AddXInputDevice(Uint8 userid, BYTE SubType, JoyStick_DeviceData **pC
return; /* better luck next time? */
}
+ name = GetXInputName(userid, SubType);
GetXInputDeviceInfo(userid, &vendor, &product, &version);
pNewJoystick->bXInputDevice = SDL_TRUE;
- pNewJoystick->joystickname = SDL_CreateJoystickName(vendor, product, NULL, GetXInputName(userid, SubType));
+ pNewJoystick->joystickname = SDL_CreateJoystickName(vendor, product, NULL, name);
if (!pNewJoystick->joystickname) {
SDL_free(pNewJoystick);
return; /* better luck next time? */
}
(void)SDL_snprintf(pNewJoystick->path, sizeof(pNewJoystick->path), "XInput#%u", userid);
if (!SDL_XInputUseOldJoystickMapping()) {
- pNewJoystick->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_USB, vendor, product, version, pNewJoystick->joystickname, 'x', SubType);
+ pNewJoystick->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_USB, vendor, product, version, NULL, name, 'x', SubType);
}
pNewJoystick->SubType = SubType;
pNewJoystick->XInputUserId = userid;