Skip to content

Commit

Permalink
Added broad support for wireless XBox 360 controllers on Linux
Browse files Browse the repository at this point in the history
  • Loading branch information
slouken committed Dec 9, 2015
1 parent 11c1391 commit d1e6a2e
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 65 deletions.
168 changes: 105 additions & 63 deletions src/joystick/SDL_gamecontroller.c
Expand Up @@ -254,36 +254,6 @@ ControllerMapping_t *SDL_PrivateGetControllerMappingForGUID(SDL_JoystickGUID *gu
return NULL;
}

/*
* Helper function to determine pre-calculated offset to certain joystick mappings
*/
ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index)
{
SDL_JoystickGUID jGUID = SDL_JoystickGetDeviceGUID(device_index);
ControllerMapping_t *mapping;

mapping = SDL_PrivateGetControllerMappingForGUID(&jGUID);
#if SDL_JOYSTICK_XINPUT
if (!mapping && SDL_SYS_IsXInputGamepad_DeviceIndex(device_index)) {
mapping = s_pXInputMapping;
}
#endif
#if defined(SDL_JOYSTICK_EMSCRIPTEN)
if (!mapping && s_pEmscriptenMapping) {
mapping = s_pEmscriptenMapping;
}
#endif
if (!mapping) {
const char *name = SDL_JoystickNameForIndex(device_index);
if (name) {
if (SDL_strstr(name, "Xbox") || SDL_strstr(name, "X-Box")) {
mapping = s_pXInputMapping;
}
}
}
return mapping;
}

static const char* map_StringForControllerAxis[] = {
"leftx",
"lefty",
Expand Down Expand Up @@ -581,6 +551,9 @@ char *SDL_PrivateGetControllerMappingFromMappingString(const char *pMapping)
return SDL_strdup(pSecondComma + 1); /* mapping is everything after the 3rd comma */
}

/*
* Helper function to refresh a mapping
*/
void SDL_PrivateGameControllerRefreshMapping(ControllerMapping_t *pControllerMapping)
{
SDL_GameController *gamecontrollerlist = SDL_gamecontrollers;
Expand All @@ -599,6 +572,102 @@ void SDL_PrivateGameControllerRefreshMapping(ControllerMapping_t *pControllerMap
}
}

/*
* Helper function to add a mapping for a guid
*/
static ControllerMapping_t *
SDL_PrivateAddMappingForGUID(SDL_JoystickGUID jGUID, const char *mappingString, SDL_bool *existing)
{
char *pchName;
char *pchMapping;
ControllerMapping_t *pControllerMapping;

pchName = SDL_PrivateGetControllerNameFromMappingString(mappingString);
if (!pchName) {
SDL_SetError("Couldn't parse name from %s", mappingString);
return NULL;
}

pchMapping = SDL_PrivateGetControllerMappingFromMappingString(mappingString);
if (!pchMapping) {
SDL_free(pchName);
SDL_SetError("Couldn't parse %s", mappingString);
return NULL;
}

pControllerMapping = SDL_PrivateGetControllerMappingForGUID(&jGUID);
if (pControllerMapping) {
/* Update existing mapping */
SDL_free(pControllerMapping->name);
pControllerMapping->name = pchName;
SDL_free(pControllerMapping->mapping);
pControllerMapping->mapping = pchMapping;
/* refresh open controllers */
SDL_PrivateGameControllerRefreshMapping(pControllerMapping);
*existing = SDL_TRUE;
} else {
pControllerMapping = SDL_malloc(sizeof(*pControllerMapping));
if (!pControllerMapping) {
SDL_free(pchName);
SDL_free(pchMapping);
SDL_OutOfMemory();
return NULL;
}
pControllerMapping->guid = jGUID;
pControllerMapping->name = pchName;
pControllerMapping->mapping = pchMapping;
pControllerMapping->next = s_pSupportedControllers;
s_pSupportedControllers = pControllerMapping;
*existing = SDL_FALSE;
}
return pControllerMapping;
}

/*
* Helper function to determine pre-calculated offset to certain joystick mappings
*/
ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index)
{
SDL_JoystickGUID jGUID = SDL_JoystickGetDeviceGUID(device_index);
ControllerMapping_t *mapping;

mapping = SDL_PrivateGetControllerMappingForGUID(&jGUID);
#if SDL_JOYSTICK_XINPUT
if (!mapping && SDL_SYS_IsXInputGamepad_DeviceIndex(device_index)) {
mapping = s_pXInputMapping;
}
#endif
#if defined(SDL_JOYSTICK_EMSCRIPTEN)
if (!mapping && s_pEmscriptenMapping) {
mapping = s_pEmscriptenMapping;
}
#endif
#ifdef __LINUX__
if (!mapping) {
const char *name = SDL_JoystickNameForIndex(device_index);
if (name) {
if (SDL_strstr(name, "Xbox 360 Wireless Receiver")) {
/* The Linux driver xpad.c maps the wireless dpad to buttons */
SDL_bool existing;
mapping = SDL_PrivateAddMappingForGUID(jGUID,
"none,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
&existing);
}
}
}
#endif /* __LINUX__ */

if (!mapping) {
const char *name = SDL_JoystickNameForIndex(device_index);
if (name) {
if (SDL_strstr(name, "Xbox") || SDL_strstr(name, "X-Box")) {
mapping = s_pXInputMapping;
}
}
}
return mapping;
}

/*
* Add or update an entry into the Mappings Database
*/
Expand Down Expand Up @@ -677,12 +746,11 @@ int
SDL_GameControllerAddMapping(const char *mappingString)
{
char *pchGUID;
char *pchName;
char *pchMapping;
SDL_JoystickGUID jGUID;
ControllerMapping_t *pControllerMapping;
SDL_bool is_xinput_mapping = SDL_FALSE;
SDL_bool is_emscripten_mapping = SDL_FALSE;
SDL_bool existing = SDL_FALSE;
ControllerMapping_t *pControllerMapping;

if (!mappingString) {
return SDL_InvalidParamError("mappingString");
Expand All @@ -701,46 +769,20 @@ SDL_GameControllerAddMapping(const char *mappingString)
jGUID = SDL_JoystickGetGUIDFromString(pchGUID);
SDL_free(pchGUID);

pchName = SDL_PrivateGetControllerNameFromMappingString(mappingString);
if (!pchName) {
return SDL_SetError("Couldn't parse name from %s", mappingString);
}

pchMapping = SDL_PrivateGetControllerMappingFromMappingString(mappingString);
if (!pchMapping) {
SDL_free(pchName);
return SDL_SetError("Couldn't parse %s", mappingString);
pControllerMapping = SDL_PrivateAddMappingForGUID(jGUID, mappingString, &existing);
if (!pControllerMapping) {
return -1;
}

pControllerMapping = SDL_PrivateGetControllerMappingForGUID(&jGUID);

if (pControllerMapping) {
/* Update existing mapping */
SDL_free(pControllerMapping->name);
pControllerMapping->name = pchName;
SDL_free(pControllerMapping->mapping);
pControllerMapping->mapping = pchMapping;
/* refresh open controllers */
SDL_PrivateGameControllerRefreshMapping(pControllerMapping);
if (existing) {
return 0;
} else {
pControllerMapping = SDL_malloc(sizeof(*pControllerMapping));
if (!pControllerMapping) {
SDL_free(pchName);
SDL_free(pchMapping);
return SDL_OutOfMemory();
}
if (is_xinput_mapping) {
s_pXInputMapping = pControllerMapping;
}
if (is_emscripten_mapping) {
s_pEmscriptenMapping = pControllerMapping;
}
pControllerMapping->guid = jGUID;
pControllerMapping->name = pchName;
pControllerMapping->mapping = pchMapping;
pControllerMapping->next = s_pSupportedControllers;
s_pSupportedControllers = pControllerMapping;
return 1;
}
}
Expand Down
2 changes: 0 additions & 2 deletions src/joystick/SDL_gamecontrollerdb.h
Expand Up @@ -83,8 +83,6 @@ static const char *s_ControllerMappings [] =
"050000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
"03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000de280000ff11000001000000,Valve Streaming Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000005e040000d102000001010000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
#endif
Expand Down

0 comments on commit d1e6a2e

Please sign in to comment.