Skip to content
Permalink
Browse files

Fixed bug 2553 - Add support to all XInput devices

This adds support for all XInput devices, exposed through the SDL joystick API.
The button and axis reporting for XInput devices has been changed to match DirectInput and other platforms.
The game controller xinput mapping has been updated so this change is seamless.
There is a new hint, SDL_HINT_XINPUT_USE_OLD_JOYSTICK_MAPPING, for any applications that have hardcoded the old xinput button and axis set. This hint will be removed in SDL 2.1.
  • Loading branch information
slouken committed Jun 24, 2014
1 parent cbafb15 commit 52ec151fb00f498851f18edbeafb7b095b7a9a69
@@ -281,6 +281,16 @@ extern "C" {
#define SDL_HINT_XINPUT_ENABLED "SDL_XINPUT_ENABLED"


/**
* \brief A variable that causes SDL to use the old axis and button mapping for XInput devices.
*
* This hint is for backwards compatibility only and will be removed in SDL 2.1
*
* The default value is "0". This hint must be set before SDL_Init()
*/
#define SDL_HINT_XINPUT_USE_OLD_JOYSTICK_MAPPING "SDL_XINPUT_USE_OLD_JOYSTICK_MAPPING"


/**
* \brief A variable that lets you manually hint extra gamecontroller db entries
*
@@ -261,7 +261,7 @@ ControllerMapping_t *SDL_PrivateGetControllerMappingForGUID(SDL_JoystickGUID *gu
ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index)
{
#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT)
if (SDL_SYS_IsXInputDeviceIndex(device_index) && s_pXInputMapping) {
if (SDL_SYS_IsXInputGamepad_DeviceIndex(device_index) && s_pXInputMapping) {
return s_pXInputMapping;
}
else
@@ -41,9 +41,9 @@ static const char *s_ControllerMappings [] =
"4c056802000000000000504944564944,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
"25090500000000000000504944564944,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,",
"4c05c405000000000000504944564944,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"xinput,X360 Controller,a:b10,b:b11,back:b5,dpdown:b1,dpleft:b2,dpright:b3,dpup:b0,guide:b14,leftshoulder:b8,leftstick:b6,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:a5,rightx:a2,righty:a3,start:b4,x:b12,y:b13,",
"xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
#elif defined(SDL_JOYSTICK_XINPUT)
"xinput,X360 Controller,a:b10,b:b11,back:b5,dpdown:b1,dpleft:b2,dpright:b3,dpup:b0,guide:b14,leftshoulder:b8,leftstick:b6,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:a5,rightx:a2,righty:a3,start:b4,x:b12,y:b13,",
"xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
#elif defined(__MACOSX__)
"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"6d0400000000000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", /* Guide button doesn't seem to be sent in DInput mode. */
@@ -113,9 +113,8 @@ SDL_JoystickOpen(int device_index)
/* If the joystick is already open, return it
* it is important that we have a single joystick * for each instance id
*/
while ( joysticklist )
{
if ( SDL_SYS_GetInstanceIdOfDeviceIndex(device_index) == joysticklist->instance_id ) {
while (joysticklist) {
if (SDL_SYS_GetInstanceIdOfDeviceIndex(device_index) == joysticklist->instance_id) {
joystick = joysticklist;
++joystick->ref_count;
return (joystick);
@@ -136,9 +135,9 @@ SDL_JoystickOpen(int device_index)
return NULL;
}

joystickname = SDL_SYS_JoystickNameForDeviceIndex( device_index );
if ( joystickname )
joystick->name = SDL_strdup( joystickname );
joystickname = SDL_SYS_JoystickNameForDeviceIndex(device_index);
if (joystickname)
joystick->name = SDL_strdup(joystickname);
else
joystick->name = NULL;

@@ -186,7 +185,7 @@ SDL_JoystickOpen(int device_index)
joystick->next = SDL_joysticks;
SDL_joysticks = joystick;

SDL_SYS_JoystickUpdate( joystick );
SDL_SYS_JoystickUpdate(joystick);

return (joystick);
}
@@ -200,15 +199,14 @@ SDL_PrivateJoystickValid(SDL_Joystick * joystick)
{
int valid;

if ( joystick == NULL ) {
if (joystick == NULL) {
SDL_SetError("Joystick hasn't been opened yet");
valid = 0;
} else {
valid = 1;
}

if ( joystick && joystick->closed )
{
if (joystick && joystick->closed) {
valid = 0;
}

@@ -417,20 +415,14 @@ SDL_JoystickClose(SDL_Joystick * joystick)

joysticklist = SDL_joysticks;
joysticklistprev = NULL;
while ( joysticklist )
{
if (joystick == joysticklist)
{
if ( joysticklistprev )
{
while (joysticklist) {
if (joystick == joysticklist) {
if (joysticklistprev) {
/* unlink this entry */
joysticklistprev->next = joysticklist->next;
}
else
{
} else {
SDL_joysticks = joystick->next;
}

break;
}
joysticklistprev = joysticklist;
@@ -454,8 +446,7 @@ SDL_JoystickQuit(void)
SDL_assert(!SDL_updating_joystick);

/* Stop the event polling */
while ( SDL_joysticks )
{
while (SDL_joysticks) {
SDL_joysticks->ref_count = 1;
SDL_JoystickClose(SDL_joysticks);
}
@@ -472,8 +463,7 @@ SDL_JoystickQuit(void)
static SDL_bool
SDL_PrivateJoystickShouldIgnoreEvent()
{
if (SDL_joystick_allows_background_events)
{
if (SDL_joystick_allows_background_events) {
return SDL_FALSE;
}

@@ -497,10 +487,13 @@ SDL_PrivateJoystickAxis(SDL_Joystick * joystick, Uint8 axis, Sint16 value)
{
int posted;

/* Make sure we're not getting garbage events */
/* Make sure we're not getting garbage or duplicate events */
if (axis >= joystick->naxes) {
return 0;
}
if (value == joystick->axes[axis]) {
return 0;
}

/* We ignore events if we don't have keyboard focus, except for centering
* events.
@@ -513,9 +506,6 @@ SDL_PrivateJoystickAxis(SDL_Joystick * joystick, Uint8 axis, Sint16 value)
}

/* Update internal joystick state */
if (value == joystick->axes[axis]) {
return 0;
}
joystick->axes[axis] = value;

/* Post the event, if desired */
@@ -538,10 +528,13 @@ SDL_PrivateJoystickHat(SDL_Joystick * joystick, Uint8 hat, Uint8 value)
{
int posted;

/* Make sure we're not getting garbage events */
/* Make sure we're not getting garbage or duplicate events */
if (hat >= joystick->nhats) {
return 0;
}
if (value == joystick->hats[hat]) {
return 0;
}

/* We ignore events if we don't have keyboard focus, except for centering
* events.
@@ -553,9 +546,6 @@ SDL_PrivateJoystickHat(SDL_Joystick * joystick, Uint8 hat, Uint8 value)
}

/* Update internal joystick state */
if (value == joystick->hats[hat]) {
return 0;
}
joystick->hats[hat] = value;

/* Post the event, if desired */
@@ -629,10 +619,13 @@ SDL_PrivateJoystickButton(SDL_Joystick * joystick, Uint8 button, Uint8 state)
}
#endif /* !SDL_EVENTS_DISABLED */

/* Make sure we're not getting garbage events */
/* Make sure we're not getting garbage or duplicate events */
if (button >= joystick->nbuttons) {
return 0;
}
}
if (state == joystick->buttons[button]) {
return 0;
}

/* We ignore events if we don't have keyboard focus, except for button
* release. */
@@ -643,9 +636,6 @@ SDL_PrivateJoystickButton(SDL_Joystick * joystick, Uint8 button, Uint8 state)
}

/* Update internal joystick state */
if (state == joystick->buttons[button]) {
return 0;
}
joystick->buttons[button] = state;

/* Post the event, if desired */
@@ -667,8 +657,7 @@ SDL_JoystickUpdate(void)
SDL_Joystick *joystick;

joystick = SDL_joysticks;
while ( joystick )
{
while (joystick) {
SDL_Joystick *joysticknext;
/* save off the next pointer, the Update call may cause a joystick removed event
* and cause our joystick pointer to be freed
@@ -677,10 +666,9 @@ SDL_JoystickUpdate(void)

SDL_updating_joystick = joystick;

SDL_SYS_JoystickUpdate( joystick );
SDL_SYS_JoystickUpdate(joystick);

if ( joystick->closed && joystick->uncentered )
{
if (joystick->closed && joystick->uncentered) {
int i;

/* Tell the app that everything is centered/unpressed... */
@@ -693,13 +681,13 @@ SDL_JoystickUpdate(void)
for (i = 0; i < joystick->nhats; i++)
SDL_PrivateJoystickHat(joystick, i, SDL_HAT_CENTERED);

joystick->uncentered = 0;
joystick->uncentered = SDL_FALSE;
}

SDL_updating_joystick = NULL;

/* If the joystick was closed while updating, free it here */
if ( joystick->ref_count <= 0 ) {
if (joystick->ref_count <= 0) {
SDL_JoystickClose(joystick);
}

@@ -750,25 +738,25 @@ SDL_JoystickGUID SDL_JoystickGetDeviceGUID(int device_index)
if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
SDL_JoystickGUID emptyGUID;
SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
SDL_zero( emptyGUID );
SDL_zero(emptyGUID);
return emptyGUID;
}
return SDL_SYS_JoystickGetDeviceGUID( device_index );
return SDL_SYS_JoystickGetDeviceGUID(device_index);
}

/* return the guid for this opened device */
SDL_JoystickGUID SDL_JoystickGetGUID(SDL_Joystick * joystick)
{
if (!SDL_PrivateJoystickValid(joystick)) {
SDL_JoystickGUID emptyGUID;
SDL_zero( emptyGUID );
SDL_zero(emptyGUID);
return emptyGUID;
}
return SDL_SYS_JoystickGetGUID( joystick );
return SDL_SYS_JoystickGetGUID(joystick);
}

/* convert the guid to a printable string */
void SDL_JoystickGetGUIDString( SDL_JoystickGUID guid, char *pszGUID, int cbGUID )
void SDL_JoystickGetGUIDString(SDL_JoystickGUID guid, char *pszGUID, int cbGUID)
{
static const char k_rgchHexToASCII[] = "0123456789abcdef";
int i;
@@ -777,14 +765,13 @@ void SDL_JoystickGetGUIDString( SDL_JoystickGUID guid, char *pszGUID, int cbGUID
return;
}

for ( i = 0; i < sizeof(guid.data) && i < (cbGUID-1)/2; i++ )
{
for (i = 0; i < sizeof(guid.data) && i < (cbGUID-1)/2; i++) {
/* each input byte writes 2 ascii chars, and might write a null byte. */
/* If we don't have room for next input byte, stop */
unsigned char c = guid.data[i];

*pszGUID++ = k_rgchHexToASCII[ c >> 4 ];
*pszGUID++ = k_rgchHexToASCII[ c & 0x0F ];
*pszGUID++ = k_rgchHexToASCII[c >> 4];
*pszGUID++ = k_rgchHexToASCII[c & 0x0F];
}
*pszGUID = '\0';
}
@@ -795,28 +782,22 @@ void SDL_JoystickGetGUIDString( SDL_JoystickGUID guid, char *pszGUID, int cbGUID
* Input : c -
* Output : unsigned char
*-----------------------------------------------------------------------------*/
static unsigned char nibble( char c )
static unsigned char nibble(char c)
{
if ( ( c >= '0' ) &&
( c <= '9' ) )
{
if ((c >= '0') && (c <= '9')) {
return (unsigned char)(c - '0');
}

if ( ( c >= 'A' ) &&
( c <= 'F' ) )
{
if ((c >= 'A') && (c <= 'F')) {
return (unsigned char)(c - 'A' + 0x0a);
}

if ( ( c >= 'a' ) &&
( c <= 'f' ) )
{
if ((c >= 'a') && (c <= 'f')) {
return (unsigned char)(c - 'a' + 0x0a);
}

/* received an invalid character, and no real way to return an error */
/* AssertMsg1( false, "Q_nibble invalid hex character '%c' ", c ); */
/* AssertMsg1(false, "Q_nibble invalid hex character '%c' ", c); */
return 0;
}

@@ -826,21 +807,18 @@ SDL_JoystickGUID SDL_JoystickGetGUIDFromString(const char *pchGUID)
{
SDL_JoystickGUID guid;
int maxoutputbytes= sizeof(guid);
size_t len = SDL_strlen( pchGUID );
size_t len = SDL_strlen(pchGUID);
Uint8 *p;
size_t i;

/* Make sure it's even */
len = ( len ) & ~0x1;
len = (len) & ~0x1;

SDL_memset( &guid, 0x00, sizeof(guid) );
SDL_memset(&guid, 0x00, sizeof(guid));

p = (Uint8 *)&guid;
for ( i = 0;
( i < len ) && ( ( p - (Uint8 *)&guid ) < maxoutputbytes );
i+=2, p++ )
{
*p = ( nibble( pchGUID[i] ) << 4 ) | nibble( pchGUID[i+1] );
for (i = 0; (i < len) && ((p - (Uint8 *)&guid) < maxoutputbytes); i+=2, p++) {
*p = (nibble(pchGUID[i]) << 4) | nibble(pchGUID[i+1]);
}

return guid;
@@ -50,8 +50,8 @@ struct _SDL_Joystick

int ref_count; /* Reference count for multiple opens */

Uint8 closed; /* 1 if this device is no longer valid */
Uint8 uncentered; /* 1 if this device needs to have its state reset to 0 */
SDL_bool closed; /* SDL_TRUE if this device is no longer valid */
SDL_bool uncentered; /* SDL_TRUE if this device needs to have its state reset to 0 */
struct _SDL_Joystick *next; /* pointer to next joystick we have allocated */
};

@@ -106,9 +106,8 @@ extern SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID(int device_index);
extern SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick);

#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT)
/* Function to get the current instance id of the joystick located at device_index */
extern SDL_bool SDL_SYS_IsXInputDeviceIndex( int device_index );
extern SDL_bool SDL_SYS_IsXInputJoystick(SDL_Joystick * joystick);
/* Function returns SDL_TRUE if this device is an XInput gamepad */
extern SDL_bool SDL_SYS_IsXInputGamepad_DeviceIndex( int device_index );
#endif

/* vi: set ts=4 sw=4 expandtab: */

0 comments on commit 52ec151

Please sign in to comment.