Added broad support for wireless XBox 360 controllers on Linux
authorSam Lantinga <slouken@libsdl.org>
Wed, 09 Dec 2015 12:11:40 -0800
changeset 99560b3b1f767eb1
parent 9955 cd98cb69906d
child 9957 0be86b512d34
Added broad support for wireless XBox 360 controllers on Linux
src/joystick/SDL_gamecontroller.c
src/joystick/SDL_gamecontrollerdb.h
     1.1 --- a/src/joystick/SDL_gamecontroller.c	Mon Dec 07 21:43:16 2015 +0100
     1.2 +++ b/src/joystick/SDL_gamecontroller.c	Wed Dec 09 12:11:40 2015 -0800
     1.3 @@ -254,36 +254,6 @@
     1.4      return NULL;
     1.5  }
     1.6  
     1.7 -/*
     1.8 - * Helper function to determine pre-calculated offset to certain joystick mappings
     1.9 - */
    1.10 -ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index)
    1.11 -{
    1.12 -    SDL_JoystickGUID jGUID = SDL_JoystickGetDeviceGUID(device_index);
    1.13 -    ControllerMapping_t *mapping;
    1.14 -
    1.15 -    mapping = SDL_PrivateGetControllerMappingForGUID(&jGUID);
    1.16 -#if SDL_JOYSTICK_XINPUT
    1.17 -    if (!mapping && SDL_SYS_IsXInputGamepad_DeviceIndex(device_index)) {
    1.18 -        mapping = s_pXInputMapping;
    1.19 -    }
    1.20 -#endif
    1.21 -#if defined(SDL_JOYSTICK_EMSCRIPTEN)
    1.22 -    if (!mapping && s_pEmscriptenMapping) {
    1.23 -        mapping = s_pEmscriptenMapping;
    1.24 -    }
    1.25 -#endif
    1.26 -    if (!mapping) {
    1.27 -        const char *name = SDL_JoystickNameForIndex(device_index);
    1.28 -        if (name) {
    1.29 -            if (SDL_strstr(name, "Xbox") || SDL_strstr(name, "X-Box")) {
    1.30 -                mapping = s_pXInputMapping;
    1.31 -            }
    1.32 -        }
    1.33 -    }
    1.34 -    return mapping;
    1.35 -}
    1.36 -
    1.37  static const char* map_StringForControllerAxis[] = {
    1.38      "leftx",
    1.39      "lefty",
    1.40 @@ -581,6 +551,9 @@
    1.41      return SDL_strdup(pSecondComma + 1); /* mapping is everything after the 3rd comma */
    1.42  }
    1.43  
    1.44 +/*
    1.45 + * Helper function to refresh a mapping
    1.46 + */
    1.47  void SDL_PrivateGameControllerRefreshMapping(ControllerMapping_t *pControllerMapping)
    1.48  {
    1.49      SDL_GameController *gamecontrollerlist = SDL_gamecontrollers;
    1.50 @@ -600,6 +573,102 @@
    1.51  }
    1.52  
    1.53  /*
    1.54 + * Helper function to add a mapping for a guid
    1.55 + */
    1.56 +static ControllerMapping_t *
    1.57 +SDL_PrivateAddMappingForGUID(SDL_JoystickGUID jGUID, const char *mappingString, SDL_bool *existing)
    1.58 +{
    1.59 +    char *pchName;
    1.60 +    char *pchMapping;
    1.61 +    ControllerMapping_t *pControllerMapping;
    1.62 +
    1.63 +    pchName = SDL_PrivateGetControllerNameFromMappingString(mappingString);
    1.64 +    if (!pchName) {
    1.65 +        SDL_SetError("Couldn't parse name from %s", mappingString);
    1.66 +        return NULL;
    1.67 +    }
    1.68 +
    1.69 +    pchMapping = SDL_PrivateGetControllerMappingFromMappingString(mappingString);
    1.70 +    if (!pchMapping) {
    1.71 +        SDL_free(pchName);
    1.72 +        SDL_SetError("Couldn't parse %s", mappingString);
    1.73 +        return NULL;
    1.74 +    }
    1.75 +
    1.76 +    pControllerMapping = SDL_PrivateGetControllerMappingForGUID(&jGUID);
    1.77 +    if (pControllerMapping) {
    1.78 +        /* Update existing mapping */
    1.79 +        SDL_free(pControllerMapping->name);
    1.80 +        pControllerMapping->name = pchName;
    1.81 +        SDL_free(pControllerMapping->mapping);
    1.82 +        pControllerMapping->mapping = pchMapping;
    1.83 +        /* refresh open controllers */
    1.84 +        SDL_PrivateGameControllerRefreshMapping(pControllerMapping);
    1.85 +        *existing = SDL_TRUE;
    1.86 +    } else {
    1.87 +        pControllerMapping = SDL_malloc(sizeof(*pControllerMapping));
    1.88 +        if (!pControllerMapping) {
    1.89 +            SDL_free(pchName);
    1.90 +            SDL_free(pchMapping);
    1.91 +            SDL_OutOfMemory();
    1.92 +            return NULL;
    1.93 +        }
    1.94 +        pControllerMapping->guid = jGUID;
    1.95 +        pControllerMapping->name = pchName;
    1.96 +        pControllerMapping->mapping = pchMapping;
    1.97 +        pControllerMapping->next = s_pSupportedControllers;
    1.98 +        s_pSupportedControllers = pControllerMapping;
    1.99 +        *existing = SDL_FALSE;
   1.100 +    }
   1.101 +    return pControllerMapping;
   1.102 +}
   1.103 +
   1.104 +/*
   1.105 + * Helper function to determine pre-calculated offset to certain joystick mappings
   1.106 + */
   1.107 +ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index)
   1.108 +{
   1.109 +    SDL_JoystickGUID jGUID = SDL_JoystickGetDeviceGUID(device_index);
   1.110 +    ControllerMapping_t *mapping;
   1.111 +
   1.112 +    mapping = SDL_PrivateGetControllerMappingForGUID(&jGUID);
   1.113 +#if SDL_JOYSTICK_XINPUT
   1.114 +    if (!mapping && SDL_SYS_IsXInputGamepad_DeviceIndex(device_index)) {
   1.115 +        mapping = s_pXInputMapping;
   1.116 +    }
   1.117 +#endif
   1.118 +#if defined(SDL_JOYSTICK_EMSCRIPTEN)
   1.119 +    if (!mapping && s_pEmscriptenMapping) {
   1.120 +        mapping = s_pEmscriptenMapping;
   1.121 +    }
   1.122 +#endif
   1.123 +#ifdef __LINUX__
   1.124 +    if (!mapping) {
   1.125 +        const char *name = SDL_JoystickNameForIndex(device_index);
   1.126 +        if (name) {
   1.127 +            if (SDL_strstr(name, "Xbox 360 Wireless Receiver")) {
   1.128 +                /* The Linux driver xpad.c maps the wireless dpad to buttons */
   1.129 +                SDL_bool existing;
   1.130 +                mapping = SDL_PrivateAddMappingForGUID(jGUID,
   1.131 +"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,",
   1.132 +                              &existing);
   1.133 +            }
   1.134 +        }
   1.135 +    }
   1.136 +#endif /* __LINUX__ */
   1.137 +
   1.138 +    if (!mapping) {
   1.139 +        const char *name = SDL_JoystickNameForIndex(device_index);
   1.140 +        if (name) {
   1.141 +            if (SDL_strstr(name, "Xbox") || SDL_strstr(name, "X-Box")) {
   1.142 +                mapping = s_pXInputMapping;
   1.143 +            }
   1.144 +        }
   1.145 +    }
   1.146 +    return mapping;
   1.147 +}
   1.148 +
   1.149 +/*
   1.150   * Add or update an entry into the Mappings Database
   1.151   */
   1.152  int
   1.153 @@ -677,12 +746,11 @@
   1.154  SDL_GameControllerAddMapping(const char *mappingString)
   1.155  {
   1.156      char *pchGUID;
   1.157 -    char *pchName;
   1.158 -    char *pchMapping;
   1.159      SDL_JoystickGUID jGUID;
   1.160 -    ControllerMapping_t *pControllerMapping;
   1.161      SDL_bool is_xinput_mapping = SDL_FALSE;
   1.162      SDL_bool is_emscripten_mapping = SDL_FALSE;
   1.163 +    SDL_bool existing = SDL_FALSE;
   1.164 +    ControllerMapping_t *pControllerMapping;
   1.165  
   1.166      if (!mappingString) {
   1.167          return SDL_InvalidParamError("mappingString");
   1.168 @@ -701,46 +769,20 @@
   1.169      jGUID = SDL_JoystickGetGUIDFromString(pchGUID);
   1.170      SDL_free(pchGUID);
   1.171  
   1.172 -    pchName = SDL_PrivateGetControllerNameFromMappingString(mappingString);
   1.173 -    if (!pchName) {
   1.174 -        return SDL_SetError("Couldn't parse name from %s", mappingString);
   1.175 -    }
   1.176 -
   1.177 -    pchMapping = SDL_PrivateGetControllerMappingFromMappingString(mappingString);
   1.178 -    if (!pchMapping) {
   1.179 -        SDL_free(pchName);
   1.180 -        return SDL_SetError("Couldn't parse %s", mappingString);
   1.181 +    pControllerMapping = SDL_PrivateAddMappingForGUID(jGUID, mappingString, &existing);
   1.182 +    if (!pControllerMapping) {
   1.183 +        return -1;
   1.184      }
   1.185  
   1.186 -    pControllerMapping = SDL_PrivateGetControllerMappingForGUID(&jGUID);
   1.187 -
   1.188 -    if (pControllerMapping) {
   1.189 -        /* Update existing mapping */
   1.190 -        SDL_free(pControllerMapping->name);
   1.191 -        pControllerMapping->name = pchName;
   1.192 -        SDL_free(pControllerMapping->mapping);
   1.193 -        pControllerMapping->mapping = pchMapping;
   1.194 -        /* refresh open controllers */
   1.195 -        SDL_PrivateGameControllerRefreshMapping(pControllerMapping);
   1.196 +    if (existing) {
   1.197          return 0;
   1.198      } else {
   1.199 -        pControllerMapping = SDL_malloc(sizeof(*pControllerMapping));
   1.200 -        if (!pControllerMapping) {
   1.201 -            SDL_free(pchName);
   1.202 -            SDL_free(pchMapping);
   1.203 -            return SDL_OutOfMemory();
   1.204 -        }
   1.205          if (is_xinput_mapping) {
   1.206              s_pXInputMapping = pControllerMapping;
   1.207          }
   1.208          if (is_emscripten_mapping) {
   1.209              s_pEmscriptenMapping = pControllerMapping;
   1.210          }
   1.211 -        pControllerMapping->guid = jGUID;
   1.212 -        pControllerMapping->name = pchName;
   1.213 -        pControllerMapping->mapping = pchMapping;
   1.214 -        pControllerMapping->next = s_pSupportedControllers;
   1.215 -        s_pSupportedControllers = pControllerMapping;
   1.216          return 1;
   1.217      }
   1.218  }
     2.1 --- a/src/joystick/SDL_gamecontrollerdb.h	Mon Dec 07 21:43:16 2015 +0100
     2.2 +++ b/src/joystick/SDL_gamecontrollerdb.h	Wed Dec 09 12:11:40 2015 -0800
     2.3 @@ -83,8 +83,6 @@
     2.4      "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,",
     2.5      "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,",
     2.6      "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,",
     2.7 -    "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,",
     2.8 -    "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,",
     2.9      "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,",
    2.10      "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,",
    2.11  #endif