From 1e9380584a5393e6b664bcf3ca566dcca70ac0d4 Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+iacore@users.noreply.github.com> Date: Mon, 12 Jun 2023 22:44:29 +0000 Subject: [PATCH] Match gamepad by USB vendor+product on Linux --- src/input.c | 41 ++++++++++++++++++++++++++++++++++++++--- src/internal.h | 12 ++++++++++++ src/linux_joystick.c | 7 +++++++ 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/input.c b/src/input.c index 36128e10..f0e27369 100644 --- a/src/input.c +++ b/src/input.c @@ -67,15 +67,50 @@ static GLFWbool initJoysticks(void) return _glfw.joysticksInitialized = GLFW_TRUE; } +uint16_t parseHexDigit(char c) +{ + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return c - 'a' + 10; + if (c >= 'A' && c <= 'F') return c - 'A' + 10; + assert(GLFW_FALSE); +} + +struct vendor_product +{ + uint16_t vendor; + uint16_t product; +}; + +static struct vendor_product parseGUID(const char* guid) +{ + struct vendor_product result; + result.vendor = parseHexDigit(guid[8]) | (parseHexDigit(guid[9]) << 8); + result.product = parseHexDigit(guid[16]) | (parseHexDigit(guid[17]) << 8); + return result; +} + // Finds a mapping based on joystick GUID // static _GLFWmapping* findMapping(const char* guid) { - int i; + struct vendor_product this; - for (i = 0; i < _glfw.mappingCount; i++) + // exact match + for (int i = 0; i < _glfw.mappingCount; i++) { - if (strcmp(_glfw.mappings[i].guid, guid) == 0) + if (strncmp(_glfw.mappings[i].guid, guid, 32) == 0) + return _glfw.mappings + i; + } + + // only match vendor product + + this = parseGUID(guid); + + for (int i = 0; i < _glfw.mappingCount; i++) + { + struct vendor_product that = parseGUID(_glfw.mappings[i].guid); + + if (memcmp(&this, &that, sizeof(struct vendor_product)) == 0) return _glfw.mappings + i; } diff --git a/src/internal.h b/src/internal.h index fe0369aa..72f85dd5 100644 --- a/src/internal.h +++ b/src/internal.h @@ -74,6 +74,7 @@ typedef struct _GLFWmonitor _GLFWmonitor; typedef struct _GLFWcursor _GLFWcursor; typedef struct _GLFWmapelement _GLFWmapelement; typedef struct _GLFWmapping _GLFWmapping; +typedef struct _GLFWusbinfo _GLFWusbinfo; typedef struct _GLFWjoystick _GLFWjoystick; typedef struct _GLFWtls _GLFWtls; typedef struct _GLFWmutex _GLFWmutex; @@ -631,6 +632,16 @@ struct _GLFWmapping _GLFWmapelement axes[6]; }; +// USB vendor, product, version +// +struct _GLFWusbinfo +{ + uint16_t bustype; + uint16_t vendor; + uint16_t product; + uint16_t version; +}; + // Joystick structure // struct _GLFWjoystick @@ -646,6 +657,7 @@ struct _GLFWjoystick char name[128]; void* userPointer; char guid[33]; + _GLFWusbinfo usbInfo; _GLFWmapping* mapping; // This is defined in platform.h diff --git a/src/linux_joystick.c b/src/linux_joystick.c index 26db853e..8f7e481a 100644 --- a/src/linux_joystick.c +++ b/src/linux_joystick.c @@ -172,6 +172,12 @@ static GLFWbool openJoystickDevice(const char* path) char guid[33] = ""; + _GLFWusbinfo usbinfo; + usbinfo.bustype = id.bustype; + usbinfo.vendor = id.vendor; + usbinfo.product = id.product; + usbinfo.version = id.version; + // Generate a joystick GUID that matches the SDL 2.0.5+ one if (id.vendor && id.product && id.version) { @@ -231,6 +237,7 @@ static GLFWbool openJoystickDevice(const char* path) close(linjs.fd); return GLFW_FALSE; } + js->usbInfo = usbinfo; strncpy(linjs.path, path, sizeof(linjs.path) - 1); memcpy(&js->linjs, &linjs, sizeof(linjs));