Skip to content

Commit

Permalink
Added an API to get the type of a connected joystick
Browse files Browse the repository at this point in the history
  • Loading branch information
slouken committed Jan 27, 2017
1 parent ae5e9a3 commit 3c90a52
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 19 deletions.
24 changes: 24 additions & 0 deletions include/SDL_joystick.h
Expand Up @@ -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,
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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).
Expand Down
2 changes: 2 additions & 0 deletions src/dynapi/SDL_dynapi_overrides.h
Expand Up @@ -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
2 changes: 2 additions & 0 deletions src/dynapi/SDL_dynapi_procs.h
Expand Up @@ -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)
132 changes: 113 additions & 19 deletions src/joystick/SDL_joystick.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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);*/

Expand All @@ -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;
}
}
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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)
{
Expand All @@ -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;
}

Expand All @@ -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;
}

Expand All @@ -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)
{
Expand All @@ -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;
}

Expand All @@ -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;
}

Expand All @@ -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)
{
Expand Down
1 change: 1 addition & 0 deletions src/joystick/SDL_sysjoystick.h
Expand Up @@ -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 */
Expand Down

0 comments on commit 3c90a52

Please sign in to comment.