From 3c90a52aa7c04aa746315b3ba94ffb5b83b64561 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Fri, 27 Jan 2017 05:59:58 -0800 Subject: [PATCH] Added an API to get the type of a connected joystick --- include/SDL_joystick.h | 24 ++++++ src/dynapi/SDL_dynapi_overrides.h | 2 + src/dynapi/SDL_dynapi_procs.h | 2 + src/joystick/SDL_joystick.c | 132 +++++++++++++++++++++++++----- src/joystick/SDL_sysjoystick.h | 1 + 5 files changed, 142 insertions(+), 19 deletions(-) diff --git a/include/SDL_joystick.h b/include/SDL_joystick.h index a15fbb539443b..d40432e227b19 100644 --- a/include/SDL_joystick.h +++ b/include/SDL_joystick.h @@ -73,6 +73,19 @@ typedef struct { typedef Sint32 SDL_JoystickID; +typedef enum +{ + SDL_JOYSTICK_TYPE_UNKNOWN, + SDL_JOYSTICK_TYPE_GAMECONTROLLER, + SDL_JOYSTICK_TYPE_WHEEL, + SDL_JOYSTICK_TYPE_ARCADE_STICK, + SDL_JOYSTICK_TYPE_FLIGHT_STICK, + SDL_JOYSTICK_TYPE_DANCE_PAD, + SDL_JOYSTICK_TYPE_GUITAR, + SDL_JOYSTICK_TYPE_DRUM_KIT, + SDL_JOYSTICK_TYPE_ARCADE_PAD, +} SDL_JoystickType; + typedef enum { SDL_JOYSTICK_POWER_UNKNOWN = -1, @@ -124,6 +137,12 @@ extern DECLSPEC Uint16 SDLCALL SDL_JoystickGetDeviceProduct(int device_index); */ extern DECLSPEC Uint16 SDLCALL SDL_JoystickGetDeviceProductVersion(int device_index); +/** + * Get the type of a joystick, if available. + * This can be called before any joysticks are opened. + */ +extern DECLSPEC SDL_JoystickType SDLCALL SDL_JoystickGetDeviceType(int device_index); + /** * Open a joystick for use. * The index passed as an argument refers to the N'th joystick on the system. @@ -169,6 +188,11 @@ extern DECLSPEC Uint16 SDLCALL SDL_JoystickGetProduct(SDL_Joystick * joystick); */ extern DECLSPEC Uint16 SDLCALL SDL_JoystickGetProductVersion(SDL_Joystick * joystick); +/** + * Get the type of an opened joystick. + */ +extern DECLSPEC SDL_JoystickType SDLCALL SDL_JoystickGetType(SDL_Joystick * joystick); + /** * Return a string representation for this guid. pszGUID must point to at least 33 bytes * (32 for the string plus a NULL terminator). diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 3fe4b86da94b5..4e4acecd6554f 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -625,3 +625,5 @@ #define SDL_GameControllerNumMappings SDL_GameControllerNumMappings_REAL #define SDL_GameControllerMappingForIndex SDL_GameControllerMappingForIndex_REAL #define SDL_JoystickGetAxisInitialState SDL_JoystickGetAxisInitialState_REAL +#define SDL_JoystickGetDeviceType SDL_JoystickGetDeviceType_REAL +#define SDL_JoystickGetType SDL_JoystickGetType_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index e416b4a64e718..bec62672aa210 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -657,3 +657,5 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_HasNEON,(void),(),return) SDL_DYNAPI_PROC(int,SDL_GameControllerNumMappings,(void),(),return) SDL_DYNAPI_PROC(char*,SDL_GameControllerMappingForIndex,(int a),(a),return) SDL_DYNAPI_PROC(SDL_bool,SDL_JoystickGetAxisInitialState,(SDL_Joystick *a, int b, Sint16 *c),(a,b,c),return) +SDL_DYNAPI_PROC(SDL_JoystickType,SDL_JoystickGetDeviceType,(int a),(a),return) +SDL_DYNAPI_PROC(SDL_JoystickType,SDL_JoystickGetType,(SDL_Joystick *a),(a),return) diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index c2f107ab34a76..7a6819c68fdfc 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -32,6 +32,8 @@ #include "../events/SDL_events_c.h" #endif +#define MAKE_VIDPID(VID, PID) (((Uint32)(VID))<<16|(PID)) + static SDL_bool SDL_joystick_allows_background_events = SDL_FALSE; static SDL_Joystick *SDL_joysticks = NULL; static SDL_bool SDL_updating_joystick = SDL_FALSE; @@ -121,17 +123,14 @@ SDL_JoystickNameForIndex(int device_index) static SDL_bool SDL_JoystickAxesCenteredAtZero(SDL_Joystick *joystick) { - struct { - Uint16 vendor; - Uint16 product; - } zero_centered_joysticks[] = { - { 0x0e8f, 0x3013 }, /* HuiJia SNES USB adapter */ - { 0x05a0, 0x3232 }, /* 8Bitdo Zero Gamepad */ + static Uint32 zero_centered_joysticks[] = { + MAKE_VIDPID(0x0e8f, 0x3013), /* HuiJia SNES USB adapter */ + MAKE_VIDPID(0x05a0, 0x3232), /* 8Bitdo Zero Gamepad */ }; int i; - Uint16 vendor = SDL_JoystickGetVendor(joystick); - Uint16 product = SDL_JoystickGetProduct(joystick); + Uint32 id = MAKE_VIDPID(SDL_JoystickGetVendor(joystick), + SDL_JoystickGetProduct(joystick)); /*printf("JOYSTICK '%s' VID/PID 0x%.4x/0x%.4x AXES: %d\n", joystick->name, vendor, product, joystick->naxes);*/ @@ -141,8 +140,7 @@ SDL_JoystickAxesCenteredAtZero(SDL_Joystick *joystick) } for (i = 0; i < SDL_arraysize(zero_centered_joysticks); ++i) { - if (vendor == zero_centered_joysticks[i].vendor && - product == zero_centered_joysticks[i].product) { + if (id == zero_centered_joysticks[i]) { return SDL_TRUE; } } @@ -185,14 +183,13 @@ SDL_JoystickOpen(int device_index) } /* Create and initialize the joystick */ - joystick = (SDL_Joystick *) SDL_malloc((sizeof *joystick)); + joystick = (SDL_Joystick *) SDL_calloc(sizeof(*joystick), 1); if (joystick == NULL) { SDL_OutOfMemory(); SDL_UnlockJoystickList(); return NULL; } - SDL_memset(joystick, 0, (sizeof *joystick)); if (SDL_SYS_JoystickOpen(joystick, device_index) < 0) { SDL_free(joystick); SDL_UnlockJoystickList(); @@ -237,6 +234,8 @@ SDL_JoystickOpen(int device_index) } } + joystick->is_game_controller = SDL_IsGameController(device_index); + /* Add joystick to list */ ++joystick->ref_count; /* Link the joystick in the list */ @@ -932,7 +931,7 @@ SDL_JoystickEventState(int state) #endif /* SDL_EVENTS_DISABLED */ } -static void GetJoystickGUIDInfo(SDL_JoystickGUID guid, Uint16 *vendor, Uint16 *product, Uint16 *version) +static void SDL_GetJoystickGUIDInfo(SDL_JoystickGUID guid, Uint16 *vendor, Uint16 *product, Uint16 *version) { Uint16 *guid16 = (Uint16 *)guid.data; @@ -967,6 +966,73 @@ static void GetJoystickGUIDInfo(SDL_JoystickGUID guid, Uint16 *vendor, Uint16 *p } } +static SDL_bool SDL_IsJoystickGUIDWheel(SDL_JoystickGUID guid) +{ + static Uint32 wheel_joysticks[] = { + MAKE_VIDPID(0x046d, 0xc294), /* Logitech generic wheel */ + MAKE_VIDPID(0x046d, 0xc295), /* Logitech Momo Force */ + MAKE_VIDPID(0x046d, 0xc298), /* Logitech Driving Force Pro */ + MAKE_VIDPID(0x046d, 0xc299), /* Logitech G25 */ + MAKE_VIDPID(0x046d, 0xc29a), /* Logitech Driving Force GT */ + MAKE_VIDPID(0x046d, 0xc29b), /* Logitech G27 */ + MAKE_VIDPID(0x046d, 0xc261), /* Logitech G920 (initial mode) */ + MAKE_VIDPID(0x046d, 0xc262), /* Logitech G920 (active mode) */ + MAKE_VIDPID(0x044f, 0xb65d), /* Thrustmaster Wheel FFB */ + MAKE_VIDPID(0x044f, 0xb677), /* Thrustmaster T150 */ + MAKE_VIDPID(0x044f, 0xb664), /* Thrustmaster TX (initial mode) */ + MAKE_VIDPID(0x044f, 0xb669), /* Thrustmaster TX (active mode) */ + }; + Uint16 vendor; + Uint16 product; + Uint32 id; + int i; + + SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL); + id = MAKE_VIDPID(vendor, product); + + for (i = 0; i < SDL_arraysize(wheel_joysticks); ++i) { + if (id == wheel_joysticks[i]) { + return SDL_TRUE; + } + } + return SDL_FALSE; +} + +static SDL_JoystickType SDL_GetJoystickGUIDType(SDL_JoystickGUID guid) +{ + if (guid.data[14] == 'x') { + /* XInput GUID, get the type based on the XInput device subtype */ + switch (guid.data[15]) { + case 0x01: /* XINPUT_DEVSUBTYPE_GAMEPAD */ + return SDL_JOYSTICK_TYPE_GAMECONTROLLER; + case 0x02: /* XINPUT_DEVSUBTYPE_WHEEL */ + return SDL_JOYSTICK_TYPE_WHEEL; + case 0x03: /* XINPUT_DEVSUBTYPE_ARCADE_STICK */ + return SDL_JOYSTICK_TYPE_ARCADE_STICK; + case 0x04: /* XINPUT_DEVSUBTYPE_FLIGHT_STICK */ + return SDL_JOYSTICK_TYPE_FLIGHT_STICK; + case 0x05: /* XINPUT_DEVSUBTYPE_DANCE_PAD */ + return SDL_JOYSTICK_TYPE_DANCE_PAD; + case 0x06: /* XINPUT_DEVSUBTYPE_GUITAR */ + case 0x07: /* XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE */ + case 0x0B: /* XINPUT_DEVSUBTYPE_GUITAR_BASS */ + return SDL_JOYSTICK_TYPE_GUITAR; + case 0x08: /* XINPUT_DEVSUBTYPE_DRUM_KIT */ + return SDL_JOYSTICK_TYPE_DRUM_KIT; + case 0x13: /* XINPUT_DEVSUBTYPE_ARCADE_PAD */ + return SDL_JOYSTICK_TYPE_ARCADE_PAD; + default: + return SDL_JOYSTICK_TYPE_UNKNOWN; + } + } + + if (SDL_IsJoystickGUIDWheel(guid)) { + return SDL_JOYSTICK_TYPE_WHEEL; + } + + return SDL_JOYSTICK_TYPE_UNKNOWN; +} + /* return the guid for this index */ SDL_JoystickGUID SDL_JoystickGetDeviceGUID(int device_index) { @@ -984,7 +1050,7 @@ Uint16 SDL_JoystickGetDeviceVendor(int device_index) Uint16 vendor; SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index); - GetJoystickGUIDInfo(guid, &vendor, NULL, NULL); + SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL); return vendor; } @@ -993,7 +1059,7 @@ Uint16 SDL_JoystickGetDeviceProduct(int device_index) Uint16 product; SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index); - GetJoystickGUIDInfo(guid, NULL, &product, NULL); + SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL); return product; } @@ -1002,10 +1068,24 @@ Uint16 SDL_JoystickGetDeviceProductVersion(int device_index) Uint16 version; SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index); - GetJoystickGUIDInfo(guid, NULL, NULL, &version); + SDL_GetJoystickGUIDInfo(guid, NULL, NULL, &version); return version; } +SDL_JoystickType SDL_JoystickGetDeviceType(int device_index) +{ + SDL_JoystickType type; + SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index); + + type = SDL_GetJoystickGUIDType(guid); + if (type == SDL_JOYSTICK_TYPE_UNKNOWN) { + if (SDL_IsGameController(device_index)) { + type = SDL_JOYSTICK_TYPE_GAMECONTROLLER; + } + } + return type; +} + /* return the guid for this opened device */ SDL_JoystickGUID SDL_JoystickGetGUID(SDL_Joystick * joystick) { @@ -1022,7 +1102,7 @@ Uint16 SDL_JoystickGetVendor(SDL_Joystick * joystick) Uint16 vendor; SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); - GetJoystickGUIDInfo(guid, &vendor, NULL, NULL); + SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL); return vendor; } @@ -1031,7 +1111,7 @@ Uint16 SDL_JoystickGetProduct(SDL_Joystick * joystick) Uint16 product; SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); - GetJoystickGUIDInfo(guid, NULL, &product, NULL); + SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL); return product; } @@ -1040,10 +1120,24 @@ Uint16 SDL_JoystickGetProductVersion(SDL_Joystick * joystick) Uint16 version; SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); - GetJoystickGUIDInfo(guid, NULL, NULL, &version); + SDL_GetJoystickGUIDInfo(guid, NULL, NULL, &version); return version; } +SDL_JoystickType SDL_JoystickGetType(SDL_Joystick * joystick) +{ + SDL_JoystickType type; + SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); + + type = SDL_GetJoystickGUIDType(guid); + if (type == SDL_JOYSTICK_TYPE_UNKNOWN) { + if (joystick && joystick->is_game_controller) { + type = SDL_JOYSTICK_TYPE_GAMECONTROLLER; + } + } + return type; +} + /* convert the guid to a printable string */ void SDL_JoystickGetGUIDString(SDL_JoystickGUID guid, char *pszGUID, int cbGUID) { diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h index 53a7ff75909ca..c3db03bba781f 100644 --- a/src/joystick/SDL_sysjoystick.h +++ b/src/joystick/SDL_sysjoystick.h @@ -62,6 +62,7 @@ struct _SDL_Joystick int ref_count; /* Reference count for multiple opens */ + SDL_bool is_game_controller; SDL_bool force_recentering; /* SDL_TRUE if this device needs to have its state reset to 0 */ SDL_JoystickPowerLevel epowerlevel; /* power level of this joystick, SDL_JOYSTICK_POWER_UNKNOWN if not supported */ struct _SDL_Joystick *next; /* pointer to next joystick we have allocated */