From d1e6a2ebe6a48b50431b20a4a85edfbe36090f0d Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Wed, 9 Dec 2015 12:11:40 -0800 Subject: [PATCH] Added broad support for wireless XBox 360 controllers on Linux --- src/joystick/SDL_gamecontroller.c | 168 +++++++++++++++++----------- src/joystick/SDL_gamecontrollerdb.h | 2 - 2 files changed, 105 insertions(+), 65 deletions(-) diff --git a/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c index 37e0a8bda9406..be181caa9e888 100644 --- a/src/joystick/SDL_gamecontroller.c +++ b/src/joystick/SDL_gamecontroller.c @@ -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", @@ -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; @@ -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 */ @@ -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"); @@ -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; } } diff --git a/src/joystick/SDL_gamecontrollerdb.h b/src/joystick/SDL_gamecontrollerdb.h index 8f42f6b5a364d..4f4c1240fe71d 100644 --- a/src/joystick/SDL_gamecontrollerdb.h +++ b/src/joystick/SDL_gamecontrollerdb.h @@ -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