Try to dynamically create a default Android game controller mapping based on the buttons and axes on the controller.
authorSam Lantinga <slouken@libsdl.org>
Tue, 06 Mar 2018 14:51:50 -0800
changeset 1192188a2982221ec
parent 11920 c8b4a5166613
child 11922 5b6c54dc89da
Try to dynamically create a default Android game controller mapping based on the buttons and axes on the controller.
Include the controller USB VID/PID in the GUID where possible, as we do on other platforms.
android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java
src/core/android/SDL_android.c
src/joystick/SDL_gamecontroller.c
src/joystick/SDL_gamecontrollerdb.h
src/joystick/SDL_joystick.c
src/joystick/SDL_sysjoystick.h
src/joystick/android/SDL_sysjoystick.c
src/joystick/android/SDL_sysjoystick_c.h
     1.1 --- a/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java	Fri Mar 02 22:53:25 2018 -0800
     1.2 +++ b/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java	Tue Mar 06 14:51:50 2018 -0800
     1.3 @@ -17,7 +17,8 @@
     1.4      public static native int nativeSetupJNI();
     1.5  
     1.6      public static native int nativeAddJoystick(int device_id, String name, String desc,
     1.7 -                                               int is_accelerometer, int nbuttons,
     1.8 +                                               int vendor_id, int product_id,
     1.9 +                                               boolean is_accelerometer, int button_mask,
    1.10                                                 int naxes, int nhats, int nballs);
    1.11      public static native int nativeRemoveJoystick(int device_id);
    1.12      public static native int nativeAddHaptic(int device_id, String name);
    1.13 @@ -42,7 +43,9 @@
    1.14      }
    1.15  
    1.16      public static void setup() {
    1.17 -        if (Build.VERSION.SDK_INT >= 16) {
    1.18 +        if (Build.VERSION.SDK_INT >= 19) {
    1.19 +            mJoystickHandler = new SDLJoystickHandler_API19();
    1.20 +        } else if (Build.VERSION.SDK_INT >= 16) {
    1.21              mJoystickHandler = new SDLJoystickHandler_API16();
    1.22          } else if (Build.VERSION.SDK_INT >= 12) {
    1.23              mJoystickHandler = new SDLJoystickHandler_API12();
    1.24 @@ -155,12 +158,7 @@
    1.25      @Override
    1.26      public void pollInputDevices() {
    1.27          int[] deviceIds = InputDevice.getDeviceIds();
    1.28 -        // It helps processing the device ids in reverse order
    1.29 -        // For example, in the case of the XBox 360 wireless dongle,
    1.30 -        // so the first controller seen by SDL matches what the receiver
    1.31 -        // considers to be the first controller
    1.32 -
    1.33 -        for(int i=deviceIds.length-1; i>-1; i--) {
    1.34 +        for(int i=0; i < deviceIds.length; ++i) {
    1.35              SDLJoystick joystick = getJoystick(deviceIds[i]);
    1.36              if (joystick == null) {
    1.37                  joystick = new SDLJoystick();
    1.38 @@ -187,8 +185,7 @@
    1.39                      }
    1.40  
    1.41                      mJoysticks.add(joystick);
    1.42 -                    SDLControllerManager.nativeAddJoystick(joystick.device_id, joystick.name, joystick.desc, 0, -1,
    1.43 -                                                           joystick.axes.size(), joystick.hats.size()/2, 0);
    1.44 +                    SDLControllerManager.nativeAddJoystick(joystick.device_id, joystick.name, joystick.desc, getVendorId(joystickDevice), getProductId(joystickDevice), false, getButtonMask(joystickDevice), joystick.axes.size(), joystick.hats.size()/2, 0);
    1.45                  }
    1.46              }
    1.47          }
    1.48 @@ -259,9 +256,17 @@
    1.49      public String getJoystickDescriptor(InputDevice joystickDevice) {
    1.50          return joystickDevice.getName();
    1.51      }
    1.52 +    public int getProductId(InputDevice joystickDevice) {
    1.53 +        return 0;
    1.54 +    }
    1.55 +    public int getVendorId(InputDevice joystickDevice) {
    1.56 +        return 0;
    1.57 +    }
    1.58 +    public int getButtonMask(InputDevice joystickDevice) {
    1.59 +        return -1;
    1.60 +    }
    1.61  }
    1.62  
    1.63 -
    1.64  class SDLJoystickHandler_API16 extends SDLJoystickHandler_API12 {
    1.65  
    1.66      @Override
    1.67 @@ -276,6 +281,112 @@
    1.68      }
    1.69  }
    1.70  
    1.71 +class SDLJoystickHandler_API19 extends SDLJoystickHandler_API16 {
    1.72 +
    1.73 +    @Override
    1.74 +    public int getProductId(InputDevice joystickDevice) {
    1.75 +        return joystickDevice.getProductId();
    1.76 +    }
    1.77 +
    1.78 +    @Override
    1.79 +    public int getVendorId(InputDevice joystickDevice) {
    1.80 +        return joystickDevice.getVendorId();
    1.81 +    }
    1.82 +
    1.83 +    @Override
    1.84 +    public int getButtonMask(InputDevice joystickDevice) {
    1.85 +        int button_mask = 0;
    1.86 +        int[] keys = new int[] {
    1.87 +            KeyEvent.KEYCODE_BUTTON_A,
    1.88 +            KeyEvent.KEYCODE_BUTTON_B,
    1.89 +            KeyEvent.KEYCODE_BUTTON_X,
    1.90 +            KeyEvent.KEYCODE_BUTTON_Y,
    1.91 +            KeyEvent.KEYCODE_BACK,
    1.92 +            KeyEvent.KEYCODE_BUTTON_MODE,
    1.93 +            KeyEvent.KEYCODE_BUTTON_START,
    1.94 +            KeyEvent.KEYCODE_BUTTON_THUMBL,
    1.95 +            KeyEvent.KEYCODE_BUTTON_THUMBR,
    1.96 +            KeyEvent.KEYCODE_BUTTON_L1,
    1.97 +            KeyEvent.KEYCODE_BUTTON_R1,
    1.98 +            KeyEvent.KEYCODE_DPAD_UP,
    1.99 +            KeyEvent.KEYCODE_DPAD_DOWN,
   1.100 +            KeyEvent.KEYCODE_DPAD_LEFT,
   1.101 +            KeyEvent.KEYCODE_DPAD_RIGHT,
   1.102 +            KeyEvent.KEYCODE_BUTTON_SELECT,
   1.103 +            KeyEvent.KEYCODE_DPAD_CENTER,
   1.104 +
   1.105 +            // These don't map into any SDL controller buttons directly
   1.106 +            KeyEvent.KEYCODE_BUTTON_L2,
   1.107 +            KeyEvent.KEYCODE_BUTTON_R2,
   1.108 +            KeyEvent.KEYCODE_BUTTON_C,
   1.109 +            KeyEvent.KEYCODE_BUTTON_Z,
   1.110 +            KeyEvent.KEYCODE_BUTTON_1,
   1.111 +            KeyEvent.KEYCODE_BUTTON_2,
   1.112 +            KeyEvent.KEYCODE_BUTTON_3,
   1.113 +            KeyEvent.KEYCODE_BUTTON_4,
   1.114 +            KeyEvent.KEYCODE_BUTTON_5,
   1.115 +            KeyEvent.KEYCODE_BUTTON_6,
   1.116 +            KeyEvent.KEYCODE_BUTTON_7,
   1.117 +            KeyEvent.KEYCODE_BUTTON_8,
   1.118 +            KeyEvent.KEYCODE_BUTTON_9,
   1.119 +            KeyEvent.KEYCODE_BUTTON_10,
   1.120 +            KeyEvent.KEYCODE_BUTTON_11,
   1.121 +            KeyEvent.KEYCODE_BUTTON_12,
   1.122 +            KeyEvent.KEYCODE_BUTTON_13,
   1.123 +            KeyEvent.KEYCODE_BUTTON_14,
   1.124 +            KeyEvent.KEYCODE_BUTTON_15,
   1.125 +            KeyEvent.KEYCODE_BUTTON_16,
   1.126 +        };
   1.127 +        int[] masks = new int[] {
   1.128 +            (1 << 0),   // A -> A
   1.129 +            (1 << 1),   // B -> B
   1.130 +            (1 << 2),   // X -> X
   1.131 +            (1 << 3),   // Y -> Y
   1.132 +            (1 << 4),   // BACK -> BACK
   1.133 +            (1 << 5),   // MODE -> GUIDE
   1.134 +            (1 << 6),   // START -> START
   1.135 +            (1 << 7),   // THUMBL -> LEFTSTICK
   1.136 +            (1 << 8),   // THUMBR -> RIGHTSTICK
   1.137 +            (1 << 9),   // L1 -> LEFTSHOULDER
   1.138 +            (1 << 10),  // R1 -> RIGHTSHOULDER
   1.139 +            (1 << 11),  // DPAD_UP -> DPAD_UP
   1.140 +            (1 << 12),  // DPAD_DOWN -> DPAD_DOWN
   1.141 +            (1 << 13),  // DPAD_LEFT -> DPAD_LEFT
   1.142 +            (1 << 14),  // DPAD_RIGHT -> DPAD_RIGHT
   1.143 +            (1 << 4),   // SELECT -> BACK
   1.144 +            (1 << 0),   // DPAD_CENTER -> A
   1.145 +            (1 << 15),  // L2 -> ??
   1.146 +            (1 << 16),  // R2 -> ??
   1.147 +            (1 << 17),  // C -> ??
   1.148 +            (1 << 18),  // Z -> ??
   1.149 +            (1 << 20),  // 1 -> ??
   1.150 +            (1 << 21),  // 2 -> ??
   1.151 +            (1 << 22),  // 3 -> ??
   1.152 +            (1 << 23),  // 4 -> ??
   1.153 +            (1 << 24),  // 5 -> ??
   1.154 +            (1 << 25),  // 6 -> ??
   1.155 +            (1 << 26),  // 7 -> ??
   1.156 +            (1 << 27),  // 8 -> ??
   1.157 +            (1 << 28),  // 9 -> ??
   1.158 +            (1 << 29),  // 10 -> ??
   1.159 +            (1 << 30),  // 11 -> ??
   1.160 +            (1 << 31),  // 12 -> ??
   1.161 +            // We're out of room...
   1.162 +            0xFFFFFFFF,  // 13 -> ??
   1.163 +            0xFFFFFFFF,  // 14 -> ??
   1.164 +            0xFFFFFFFF,  // 15 -> ??
   1.165 +            0xFFFFFFFF,  // 16 -> ??
   1.166 +        };
   1.167 +        boolean[] has_keys = joystickDevice.hasKeys(keys);
   1.168 +        for (int i = 0; i < keys.length; ++i) {
   1.169 +            if (has_keys[i]) {
   1.170 +                button_mask |= masks[i];
   1.171 +            }
   1.172 +        }
   1.173 +        return button_mask;
   1.174 +    }
   1.175 +}
   1.176 +
   1.177  class SDLHapticHandler {
   1.178  
   1.179      class SDLHaptic {
     2.1 --- a/src/core/android/SDL_android.c	Fri Mar 02 22:53:25 2018 -0800
     2.2 +++ b/src/core/android/SDL_android.c	Tue Mar 06 14:51:50 2018 -0800
     2.3 @@ -169,8 +169,8 @@
     2.4  
     2.5  JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick)(
     2.6          JNIEnv* env, jclass jcls,
     2.7 -        jint device_id, jstring device_name, jstring device_desc, jint is_accelerometer,
     2.8 -        jint nbuttons, jint naxes, jint nhats, jint nballs);
     2.9 +        jint device_id, jstring device_name, jstring device_desc, jint vendor_id, jint product_id,
    2.10 +        jboolean is_accelerometer, jint button_mask, jint naxes, jint nhats, jint nballs);
    2.11  
    2.12  JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveJoystick)(
    2.13          JNIEnv* env, jclass jcls,
    2.14 @@ -543,14 +543,15 @@
    2.15  
    2.16  JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick)(
    2.17                                      JNIEnv* env, jclass jcls,
    2.18 -                                    jint device_id, jstring device_name, jstring device_desc, jint is_accelerometer,
    2.19 -                                    jint nbuttons, jint naxes, jint nhats, jint nballs)
    2.20 +                                    jint device_id, jstring device_name, jstring device_desc,
    2.21 +                                    jint vendor_id, jint product_id, jboolean is_accelerometer,
    2.22 +                                    jint button_mask, jint naxes, jint nhats, jint nballs)
    2.23  {
    2.24      int retval;
    2.25      const char *name = (*env)->GetStringUTFChars(env, device_name, NULL);
    2.26      const char *desc = (*env)->GetStringUTFChars(env, device_desc, NULL);
    2.27  
    2.28 -    retval = Android_AddJoystick(device_id, name, desc, (SDL_bool) is_accelerometer, nbuttons, naxes, nhats, nballs);
    2.29 +    retval = Android_AddJoystick(device_id, name, desc, vendor_id, product_id, is_accelerometer ? SDL_TRUE : SDL_FALSE, button_mask, naxes, nhats, nballs);
    2.30  
    2.31      (*env)->ReleaseStringUTFChars(env, device_name, name);
    2.32      (*env)->ReleaseStringUTFChars(env, device_desc, desc);
     3.1 --- a/src/joystick/SDL_gamecontroller.c	Fri Mar 02 22:53:25 2018 -0800
     3.2 +++ b/src/joystick/SDL_gamecontroller.c	Tue Mar 06 14:51:50 2018 -0800
     3.3 @@ -97,8 +97,8 @@
     3.4  
     3.5  static SDL_JoystickGUID s_zeroGUID;
     3.6  static ControllerMapping_t *s_pSupportedControllers = NULL;
     3.7 +static ControllerMapping_t *s_pDefaultMapping = NULL;
     3.8  static ControllerMapping_t *s_pXInputMapping = NULL;
     3.9 -static ControllerMapping_t *s_pEmscriptenMapping = NULL;
    3.10  
    3.11  /* The SDL game controller structure */
    3.12  struct _SDL_GameController
    3.13 @@ -869,6 +869,117 @@
    3.14      return pControllerMapping;
    3.15  }
    3.16  
    3.17 +#ifdef __ANDROID__
    3.18 +/*
    3.19 + * Helper function to guess at a mapping based on the elements reported for this controller
    3.20 + */
    3.21 +static ControllerMapping_t *SDL_CreateMappingForAndroidController(const char *name, SDL_JoystickGUID guid)
    3.22 +{
    3.23 +    SDL_bool existing;
    3.24 +    char name_string[128];
    3.25 +    char mapping_string[1024];
    3.26 +    int button_mask;
    3.27 +    int axis_mask;
    3.28 +
    3.29 +    button_mask = SDL_SwapLE16(*(Uint16*)(&guid.data[sizeof(guid.data)-4]));
    3.30 +    axis_mask = SDL_SwapLE16(*(Uint16*)(&guid.data[sizeof(guid.data)-2]));
    3.31 +    if (!button_mask && !axis_mask) {
    3.32 +        /* Accelerometer, shouldn't have a game controller mapping */
    3.33 +        return NULL;
    3.34 +    }
    3.35 +
    3.36 +    /* Remove any commas in the name */
    3.37 +    SDL_strlcpy(name_string, name, sizeof(name_string));
    3.38 +    {
    3.39 +        char *spot;
    3.40 +        for (spot = name_string; *spot; ++spot) {
    3.41 +            if (*spot == ',') {
    3.42 +                *spot = ' ';
    3.43 +            }
    3.44 +        }
    3.45 +    }
    3.46 +    SDL_snprintf(mapping_string, sizeof(mapping_string), "none,%s,", name_string);
    3.47 +    if (button_mask & (1 << SDL_CONTROLLER_BUTTON_A)) {
    3.48 +        SDL_strlcat(mapping_string, "a:b0,", sizeof(mapping_string));
    3.49 +    }
    3.50 +    if (button_mask & (1 << SDL_CONTROLLER_BUTTON_B)) {
    3.51 +        SDL_strlcat(mapping_string, "b:b1,", sizeof(mapping_string));
    3.52 +    } else if (button_mask & (1 << SDL_CONTROLLER_BUTTON_BACK)) {
    3.53 +        /* Use the back button as "B" for easy UI navigation with TV remotes */
    3.54 +        SDL_strlcat(mapping_string, "b:b4,", sizeof(mapping_string));
    3.55 +        button_mask &= ~(1 << SDL_CONTROLLER_BUTTON_BACK);
    3.56 +    }
    3.57 +    if (button_mask & (1 << SDL_CONTROLLER_BUTTON_X)) {
    3.58 +        SDL_strlcat(mapping_string, "x:b2,", sizeof(mapping_string));
    3.59 +    }
    3.60 +    if (button_mask & (1 << SDL_CONTROLLER_BUTTON_Y)) {
    3.61 +        SDL_strlcat(mapping_string, "y:b3,", sizeof(mapping_string));
    3.62 +    }
    3.63 +    if (button_mask & (1 << SDL_CONTROLLER_BUTTON_BACK)) {
    3.64 +        SDL_strlcat(mapping_string, "back:b4,", sizeof(mapping_string));
    3.65 +    }
    3.66 +    if (button_mask & (1 << SDL_CONTROLLER_BUTTON_GUIDE)) {
    3.67 +        SDL_strlcat(mapping_string, "guide:b5,", sizeof(mapping_string));
    3.68 +#if 0 /* Actually this will be done in Steam */
    3.69 +    } else if (button_mask & (1 << SDL_CONTROLLER_BUTTON_START)) {
    3.70 +        /* The guide button doesn't exist, use the start button instead,
    3.71 +           so you can do Steam guide button chords and open the Steam overlay.
    3.72 +         */
    3.73 +        SDL_strlcat(mapping_string, "guide:b6,", sizeof(mapping_string));
    3.74 +        button_mask &= ~(1 << SDL_CONTROLLER_BUTTON_START);
    3.75 +#endif
    3.76 +    }
    3.77 +    if (button_mask & (1 << SDL_CONTROLLER_BUTTON_START)) {
    3.78 +        SDL_strlcat(mapping_string, "start:b6,", sizeof(mapping_string));
    3.79 +    }
    3.80 +    if (button_mask & (1 << SDL_CONTROLLER_BUTTON_LEFTSTICK)) {
    3.81 +        SDL_strlcat(mapping_string, "leftstick:b7,", sizeof(mapping_string));
    3.82 +    }
    3.83 +    if (button_mask & (1 << SDL_CONTROLLER_BUTTON_RIGHTSTICK)) {
    3.84 +        SDL_strlcat(mapping_string, "rightstick:b8,", sizeof(mapping_string));
    3.85 +    }
    3.86 +    if (button_mask & (1 << SDL_CONTROLLER_BUTTON_LEFTSHOULDER)) {
    3.87 +        SDL_strlcat(mapping_string, "leftshoulder:b9,", sizeof(mapping_string));
    3.88 +    }
    3.89 +    if (button_mask & (1 << SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)) {
    3.90 +        SDL_strlcat(mapping_string, "rightshoulder:b10,", sizeof(mapping_string));
    3.91 +    }
    3.92 +    if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_UP)) {
    3.93 +        SDL_strlcat(mapping_string, "dpup:b11,", sizeof(mapping_string));
    3.94 +    }
    3.95 +    if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_DOWN)) {
    3.96 +        SDL_strlcat(mapping_string, "dpdown:b12,", sizeof(mapping_string));
    3.97 +    }
    3.98 +    if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_LEFT)) {
    3.99 +        SDL_strlcat(mapping_string, "dpleft:b13,", sizeof(mapping_string));
   3.100 +    }
   3.101 +    if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_RIGHT)) {
   3.102 +        SDL_strlcat(mapping_string, "dpright:b14,", sizeof(mapping_string));
   3.103 +    }
   3.104 +    if (axis_mask & (1 << SDL_CONTROLLER_AXIS_LEFTX)) {
   3.105 +        SDL_strlcat(mapping_string, "leftx:a0,", sizeof(mapping_string));
   3.106 +    }
   3.107 +    if (axis_mask & (1 << SDL_CONTROLLER_AXIS_LEFTY)) {
   3.108 +        SDL_strlcat(mapping_string, "lefty:a1,", sizeof(mapping_string));
   3.109 +    }
   3.110 +    if (axis_mask & (1 << SDL_CONTROLLER_AXIS_RIGHTX)) {
   3.111 +        SDL_strlcat(mapping_string, "rightx:a2,", sizeof(mapping_string));
   3.112 +    }
   3.113 +    if (axis_mask & (1 << SDL_CONTROLLER_AXIS_RIGHTY)) {
   3.114 +        SDL_strlcat(mapping_string, "righty:a3,", sizeof(mapping_string));
   3.115 +    }
   3.116 +    if (axis_mask & (1 << SDL_CONTROLLER_AXIS_TRIGGERLEFT)) {
   3.117 +        SDL_strlcat(mapping_string, "lefttrigger:a4,", sizeof(mapping_string));
   3.118 +    }
   3.119 +    if (axis_mask & (1 << SDL_CONTROLLER_AXIS_TRIGGERRIGHT)) {
   3.120 +        SDL_strlcat(mapping_string, "righttrigger:a5,", sizeof(mapping_string));
   3.121 +    }
   3.122 +    return SDL_PrivateAddMappingForGUID(guid, mapping_string,
   3.123 +                      &existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT);
   3.124 +}
   3.125 +#endif /* __ANDROID__ */
   3.126 +
   3.127 +
   3.128  /*
   3.129   * Helper function to determine pre-calculated offset to certain joystick mappings
   3.130   */
   3.131 @@ -877,13 +988,6 @@
   3.132      ControllerMapping_t *mapping;
   3.133  
   3.134      mapping = SDL_PrivateGetControllerMappingForGUID(&guid);
   3.135 -#if defined(SDL_JOYSTICK_EMSCRIPTEN)
   3.136 -    if (!mapping && s_pEmscriptenMapping) {
   3.137 -        mapping = s_pEmscriptenMapping;
   3.138 -    }
   3.139 -#else
   3.140 -    (void) s_pEmscriptenMapping;  /* pacify ARMCC */
   3.141 -#endif
   3.142  #ifdef __LINUX__
   3.143      if (!mapping && name) {
   3.144          if (SDL_strstr(name, "Xbox 360 Wireless Receiver")) {
   3.145 @@ -901,6 +1005,14 @@
   3.146              mapping = s_pXInputMapping;
   3.147          }
   3.148      }
   3.149 +#ifdef __ANDROID__
   3.150 +    if (!mapping) {
   3.151 +        mapping = SDL_CreateMappingForAndroidController(name, guid);
   3.152 +    }
   3.153 +#endif
   3.154 +    if (!mapping) {
   3.155 +        mapping = s_pDefaultMapping;
   3.156 +    }
   3.157      return mapping;
   3.158  }
   3.159  
   3.160 @@ -926,15 +1038,6 @@
   3.161          mapping = s_pXInputMapping;
   3.162      }
   3.163  #endif
   3.164 -#if defined(__ANDROID__)
   3.165 -    if (!mapping && SDL_SYS_IsDPAD_DeviceIndex(device_index)) {
   3.166 -        SDL_bool existing;
   3.167 -        char mapping_string[1024];
   3.168 -        SDL_snprintf(mapping_string, sizeof(mapping_string), "none,%s,a:b0,b:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,", name);
   3.169 -        mapping = SDL_PrivateAddMappingForGUID(guid, mapping_string,
   3.170 -                          &existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT);
   3.171 -    }
   3.172 -#endif /* __ANDROID__ */
   3.173      SDL_UnlockJoysticks();
   3.174      return mapping;
   3.175  }
   3.176 @@ -1018,8 +1121,8 @@
   3.177  {
   3.178      char *pchGUID;
   3.179      SDL_JoystickGUID jGUID;
   3.180 +    SDL_bool is_default_mapping = SDL_FALSE;
   3.181      SDL_bool is_xinput_mapping = SDL_FALSE;
   3.182 -    SDL_bool is_emscripten_mapping = SDL_FALSE;
   3.183      SDL_bool existing = SDL_FALSE;
   3.184      ControllerMapping_t *pControllerMapping;
   3.185  
   3.186 @@ -1031,12 +1134,11 @@
   3.187      if (!pchGUID) {
   3.188          return SDL_SetError("Couldn't parse GUID from %s", mappingString);
   3.189      }
   3.190 -    if (!SDL_strcasecmp(pchGUID, "xinput")) {
   3.191 +    if (!SDL_strcasecmp(pchGUID, "default")) {
   3.192 +        is_default_mapping = SDL_TRUE;
   3.193 +    } else if (!SDL_strcasecmp(pchGUID, "xinput")) {
   3.194          is_xinput_mapping = SDL_TRUE;
   3.195      }
   3.196 -    if (!SDL_strcasecmp(pchGUID, "emscripten")) {
   3.197 -        is_emscripten_mapping = SDL_TRUE;
   3.198 -    }
   3.199      jGUID = SDL_JoystickGetGUIDFromString(pchGUID);
   3.200      SDL_free(pchGUID);
   3.201  
   3.202 @@ -1048,12 +1150,11 @@
   3.203      if (existing) {
   3.204          return 0;
   3.205      } else {
   3.206 -        if (is_xinput_mapping) {
   3.207 +        if (is_default_mapping) {
   3.208 +            s_pDefaultMapping = pControllerMapping;
   3.209 +        } else if (is_xinput_mapping) {
   3.210              s_pXInputMapping = pControllerMapping;
   3.211          }
   3.212 -        if (is_emscripten_mapping) {
   3.213 -            s_pEmscriptenMapping = pControllerMapping;
   3.214 -        }
   3.215          return 1;
   3.216      }
   3.217  }
     4.1 --- a/src/joystick/SDL_gamecontrollerdb.h	Fri Mar 02 22:53:25 2018 -0800
     4.2 +++ b/src/joystick/SDL_gamecontrollerdb.h	Tue Mar 06 14:51:50 2018 -0800
     4.3 @@ -208,14 +208,11 @@
     4.4      "03000000830500006020000010010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,",
     4.5  #endif
     4.6  #if defined(__ANDROID__)
     4.7 -    "34323662653333636330306631326233,ASUS Gamepad,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,",
     4.8 -    "64633436313965656664373634323364,Microsoft X-Box 360 pad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,",
     4.9 -    "4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
    4.10 -    "61363931656135336130663561616264,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
    4.11 -    "37336435666338653565313731303834,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
    4.12 -    "35643031303033326130316330353564,PS4 Controller,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,",
    4.13 +    "050000004c05000068020000dfff3f00,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
    4.14 +    "050000004c050000cc090000fffe3f00,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,",
    4.15      "05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
    4.16 -    "34356136633366613530316338376136,Xbox Wireless Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,x:b17,y:b2,",
    4.17 +    "050000005e040000e00200000ffe3f00,Xbox One Wireless Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b17,y:b2,",
    4.18 +    "050000005e04000091020000ff073f00,Xbox Wireless Controller,a:b0,b:b1,back:b4,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,", /* The DPAD doesn't seem to work on this controller on Android TV? */
    4.19  #endif
    4.20  #if defined(SDL_JOYSTICK_MFI)
    4.21      "4d466947616d65706164010000000000,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,",
    4.22 @@ -224,7 +221,7 @@
    4.23      "05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
    4.24  #endif
    4.25  #if defined(SDL_JOYSTICK_EMSCRIPTEN)
    4.26 -    "emscripten,Standard Gamepad,a:b0,b:b1,back:b8,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b16,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,",
    4.27 +    "default,Standard Gamepad,a:b0,b:b1,back:b8,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b16,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,",
    4.28  #endif
    4.29      NULL
    4.30  };
     5.1 --- a/src/joystick/SDL_joystick.c	Fri Mar 02 22:53:25 2018 -0800
     5.2 +++ b/src/joystick/SDL_joystick.c	Tue Mar 06 14:51:50 2018 -0800
     5.3 @@ -105,6 +105,23 @@
     5.4  }
     5.5  
     5.6  /*
     5.7 + * Perform any needed fixups for joystick names
     5.8 + */
     5.9 +static const char *
    5.10 +SDL_FixupJoystickName(const char *name)
    5.11 +{
    5.12 +    if (name) {
    5.13 +        const char *skip_prefix = "NVIDIA Corporation ";
    5.14 +
    5.15 +        if (SDL_strncmp(name, skip_prefix, SDL_strlen(skip_prefix)) == 0) {
    5.16 +            name += SDL_strlen(skip_prefix);
    5.17 +        }
    5.18 +    }
    5.19 +    return name;
    5.20 +}
    5.21 +
    5.22 +
    5.23 +/*
    5.24   * Get the implementation dependent name of a joystick
    5.25   */
    5.26  const char *
    5.27 @@ -114,7 +131,7 @@
    5.28          SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
    5.29          return (NULL);
    5.30      }
    5.31 -    return (SDL_SYS_JoystickNameForDeviceIndex(device_index));
    5.32 +    return SDL_FixupJoystickName(SDL_SYS_JoystickNameForDeviceIndex(device_index));
    5.33  }
    5.34  
    5.35  /*
    5.36 @@ -481,7 +498,7 @@
    5.37          return (NULL);
    5.38      }
    5.39  
    5.40 -    return (joystick->name);
    5.41 +    return SDL_FixupJoystickName(joystick->name);
    5.42  }
    5.43  
    5.44  /*
     6.1 --- a/src/joystick/SDL_sysjoystick.h	Fri Mar 02 22:53:25 2018 -0800
     6.2 +++ b/src/joystick/SDL_sysjoystick.h	Tue Mar 06 14:51:50 2018 -0800
     6.3 @@ -126,11 +126,6 @@
     6.4  extern SDL_bool SDL_SYS_IsXInputGamepad_DeviceIndex(int device_index);
     6.5  #endif
     6.6  
     6.7 -#if defined(__ANDROID__)
     6.8 -/* Function returns SDL_TRUE if this device is a DPAD (maybe a TV remote) */
     6.9 -extern SDL_bool SDL_SYS_IsDPAD_DeviceIndex(int device_index);
    6.10 -#endif
    6.11 -
    6.12  #endif /* SDL_sysjoystick_h_ */
    6.13  
    6.14  /* vi: set ts=4 sw=4 expandtab: */
     7.1 --- a/src/joystick/android/SDL_sysjoystick.c	Fri Mar 02 22:53:25 2018 -0800
     7.2 +++ b/src/joystick/android/SDL_sysjoystick.c	Tue Mar 06 14:51:50 2018 -0800
     7.3 @@ -72,6 +72,28 @@
     7.4  static int instance_counter = 0;
     7.5  
     7.6  
     7.7 +/* Public domain CRC implementation adapted from:
     7.8 +   http://home.thep.lu.se/~bjorn/crc/crc32_simple.c
     7.9 +*/
    7.10 +static Uint32 crc32_for_byte(Uint32 r)
    7.11 +{
    7.12 +    int i;
    7.13 +    for(i = 0; i < 8; ++i) {
    7.14 +        r = (r & 1? 0: (Uint32)0xEDB88320L) ^ r >> 1;
    7.15 +    }
    7.16 +    return r ^ (Uint32)0xFF000000L;
    7.17 +}
    7.18 +
    7.19 +static Uint32 crc32(const void *data, int count)
    7.20 +{
    7.21 +    Uint32 crc = 0;
    7.22 +    int i;
    7.23 +    for(i = 0; i < count; ++i) {
    7.24 +        crc = crc32_for_byte((Uint8)crc ^ ((const Uint8*)data)[i]) ^ crc >> 8;
    7.25 +    }
    7.26 +    return crc;
    7.27 +}
    7.28 +
    7.29  /* Function to convert Android keyCodes into SDL ones.
    7.30   * This code manipulation is done to get a sequential list of codes.
    7.31   * FIXME: This is only suited for the case where we use a fixed number of buttons determined by ANDROID_MAX_NBUTTONS
    7.32 @@ -213,7 +235,7 @@
    7.33      if (button >= 0) {
    7.34          item = JoystickByDeviceId(device_id);
    7.35          if (item && item->joystick) {
    7.36 -            SDL_PrivateJoystickButton(item->joystick, button , SDL_PRESSED);
    7.37 +            SDL_PrivateJoystickButton(item->joystick, button, SDL_PRESSED);
    7.38          } else {
    7.39              SDL_SendKeyboardKey(SDL_PRESSED, button_to_scancode(button));
    7.40          }
    7.41 @@ -256,16 +278,43 @@
    7.42  int
    7.43  Android_OnHat(int device_id, int hat_id, int x, int y)
    7.44  {
    7.45 -    const Uint8 position_map[3][3] = {
    7.46 -        {SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP},
    7.47 -        {SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT},
    7.48 -        {SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN}
    7.49 -    };
    7.50 +    const int DPAD_UP_MASK = (1 << SDL_CONTROLLER_BUTTON_DPAD_UP);
    7.51 +    const int DPAD_DOWN_MASK = (1 << SDL_CONTROLLER_BUTTON_DPAD_DOWN);
    7.52 +    const int DPAD_LEFT_MASK = (1 << SDL_CONTROLLER_BUTTON_DPAD_LEFT);
    7.53 +    const int DPAD_RIGHT_MASK = (1 << SDL_CONTROLLER_BUTTON_DPAD_RIGHT);
    7.54  
    7.55 -    if (x >= -1 && x <=1 && y >= -1 && y <= 1) {
    7.56 +    if (x >= -1 && x <= 1 && y >= -1 && y <= 1) {
    7.57          SDL_joylist_item *item = JoystickByDeviceId(device_id);
    7.58          if (item && item->joystick) {
    7.59 -            SDL_PrivateJoystickHat(item->joystick, hat_id, position_map[y+1][x+1]);
    7.60 +            int dpad_state = 0;
    7.61 +            int dpad_delta;
    7.62 +            if (x < 0) {
    7.63 +                dpad_state |= DPAD_LEFT_MASK;
    7.64 +            } else if (x > 0) {
    7.65 +                dpad_state |= DPAD_RIGHT_MASK;
    7.66 +            }
    7.67 +            if (y < 0) {
    7.68 +                dpad_state |= DPAD_UP_MASK;
    7.69 +            } else if (y > 0) {
    7.70 +                dpad_state |= DPAD_DOWN_MASK;
    7.71 +            }
    7.72 +
    7.73 +            dpad_delta = (dpad_state ^ item->dpad_state);
    7.74 +            if (dpad_delta) {
    7.75 +                if (dpad_delta & DPAD_UP_MASK) {
    7.76 +                    SDL_PrivateJoystickButton(item->joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, (dpad_state & DPAD_UP_MASK) ? SDL_PRESSED : SDL_RELEASED);
    7.77 +                }
    7.78 +                if (dpad_delta & DPAD_DOWN_MASK) {
    7.79 +                    SDL_PrivateJoystickButton(item->joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, (dpad_state & DPAD_DOWN_MASK) ? SDL_PRESSED : SDL_RELEASED);
    7.80 +                }
    7.81 +                if (dpad_delta & DPAD_LEFT_MASK) {
    7.82 +                    SDL_PrivateJoystickButton(item->joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, (dpad_state & DPAD_LEFT_MASK) ? SDL_PRESSED : SDL_RELEASED);
    7.83 +                }
    7.84 +                if (dpad_delta & DPAD_RIGHT_MASK) {
    7.85 +                    SDL_PrivateJoystickButton(item->joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, (dpad_state & DPAD_RIGHT_MASK) ? SDL_PRESSED : SDL_RELEASED);
    7.86 +                }
    7.87 +                item->dpad_state = dpad_state;
    7.88 +            }
    7.89          }
    7.90          return 0;
    7.91      }
    7.92 @@ -275,10 +324,15 @@
    7.93  
    7.94  
    7.95  int
    7.96 -Android_AddJoystick(int device_id, const char *name, const char *desc, SDL_bool is_accelerometer, int nbuttons, int naxes, int nhats, int nballs)
    7.97 +Android_AddJoystick(int device_id, const char *name, const char *desc, int vendor_id, int product_id, SDL_bool is_accelerometer, int button_mask, int naxes, int nhats, int nballs)
    7.98  {
    7.99 +    const Uint16 BUS_BLUETOOTH = 0x05;
   7.100 +    SDL_joylist_item *item;
   7.101      SDL_JoystickGUID guid;
   7.102 -    SDL_joylist_item *item;
   7.103 +    Uint16 *guid16 = (Uint16 *)guid.data;
   7.104 +    int i;
   7.105 +    int axis_mask;
   7.106 +
   7.107  
   7.108      if (!SDL_GetHintBoolean(SDL_HINT_TV_REMOTE_AS_JOYSTICK, SDL_TRUE)) {
   7.109          /* Ignore devices that aren't actually controllers (e.g. remotes), they'll be handled as keyboard input */
   7.110 @@ -291,9 +345,57 @@
   7.111          return -1;
   7.112      }
   7.113      
   7.114 -    /* the GUID is just the first 16 chars of the name for now */
   7.115 -    SDL_zero(guid);
   7.116 -    SDL_memcpy(&guid, desc, SDL_min(sizeof(guid), SDL_strlen(desc)));
   7.117 +#ifdef DEBUG_JOYSTICK
   7.118 +    SDL_Log("Joystick: %s, descriptor %s, vendor = 0x%.4x, product = 0x%.4x, %d axes, %d hats\n", name, desc, vendor_id, product_id, naxes, nhats);
   7.119 +#endif
   7.120 +
   7.121 +    /* Add the available buttons and axes
   7.122 +       The axis mask should probably come from Java where there is more information about the axes...
   7.123 +     */
   7.124 +    axis_mask = 0;
   7.125 +    if (!is_accelerometer) {
   7.126 +        if (naxes >= 2) {
   7.127 +            axis_mask |= ((1 << SDL_CONTROLLER_AXIS_LEFTX) | (1 << SDL_CONTROLLER_AXIS_LEFTY));
   7.128 +        }
   7.129 +        if (naxes >= 4) {
   7.130 +            axis_mask |= ((1 << SDL_CONTROLLER_AXIS_RIGHTX) | (1 << SDL_CONTROLLER_AXIS_RIGHTY));
   7.131 +        }
   7.132 +        if (naxes >= 6) {
   7.133 +            axis_mask |= ((1 << SDL_CONTROLLER_AXIS_TRIGGERLEFT) | (1 << SDL_CONTROLLER_AXIS_TRIGGERRIGHT));
   7.134 +        }
   7.135 +    }
   7.136 +
   7.137 +    if (nhats > 0) {
   7.138 +        /* Hat is translated into DPAD buttons */
   7.139 +        button_mask |= ((1 << SDL_CONTROLLER_BUTTON_DPAD_UP) |
   7.140 +                        (1 << SDL_CONTROLLER_BUTTON_DPAD_DOWN) |
   7.141 +                        (1 << SDL_CONTROLLER_BUTTON_DPAD_LEFT) |
   7.142 +                        (1 << SDL_CONTROLLER_BUTTON_DPAD_RIGHT));
   7.143 +        nhats = 0;
   7.144 +    }
   7.145 +
   7.146 +    SDL_memset(guid.data, 0, sizeof(guid.data));
   7.147 +
   7.148 +    /* We only need 16 bits for each of these; space them out to fill 128. */
   7.149 +    /* Byteswap so devices get same GUID on little/big endian platforms. */
   7.150 +    *guid16++ = SDL_SwapLE16(BUS_BLUETOOTH);
   7.151 +    *guid16++ = 0;
   7.152 +
   7.153 +    if (vendor_id && product_id) {
   7.154 +        *guid16++ = SDL_SwapLE16(vendor_id);
   7.155 +        *guid16++ = 0;
   7.156 +        *guid16++ = SDL_SwapLE16(product_id);
   7.157 +        *guid16++ = 0;
   7.158 +    } else {
   7.159 +        Uint32 crc = crc32(desc, SDL_strlen(desc));
   7.160 +        SDL_memcpy(guid16, desc, SDL_min(2*sizeof(*guid16), SDL_strlen(desc)));
   7.161 +        guid16 += 2;
   7.162 +        *(Uint32 *)guid16 = SDL_SwapLE32(crc);
   7.163 +        guid16 += 2;
   7.164 +    }
   7.165 +
   7.166 +    *guid16++ = SDL_SwapLE16(button_mask);
   7.167 +    *guid16++ = SDL_SwapLE16(axis_mask);
   7.168  
   7.169      item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item));
   7.170      if (item == NULL) {
   7.171 @@ -310,11 +412,14 @@
   7.172      }
   7.173      
   7.174      item->is_accelerometer = is_accelerometer;
   7.175 -    if (nbuttons > -1) {
   7.176 -        item->nbuttons = nbuttons;
   7.177 -    }
   7.178 -    else {
   7.179 +    if (button_mask == 0xFFFFFFFF) {
   7.180          item->nbuttons = ANDROID_MAX_NBUTTONS;
   7.181 +    } else {
   7.182 +        for (i = 0; i < sizeof(button_mask)*8; ++i) {
   7.183 +            if (button_mask & (1 << i)) {
   7.184 +                item->nbuttons = i+1;
   7.185 +            }
   7.186 +        }
   7.187      }
   7.188      item->naxes = naxes;
   7.189      item->nhats = nhats;
   7.190 @@ -467,7 +572,7 @@
   7.191      
   7.192      if (SDL_GetHintBoolean(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, SDL_TRUE)) {
   7.193          /* Default behavior, accelerometer as joystick */
   7.194 -        Android_AddJoystick(ANDROID_ACCELEROMETER_DEVICE_ID, ANDROID_ACCELEROMETER_NAME, ANDROID_ACCELEROMETER_NAME, SDL_TRUE, 0, 3, 0, 0);
   7.195 +        Android_AddJoystick(ANDROID_ACCELEROMETER_DEVICE_ID, ANDROID_ACCELEROMETER_NAME, ANDROID_ACCELEROMETER_NAME, 0, 0, SDL_TRUE, 0, 3, 0, 0);
   7.196      }
   7.197     
   7.198      SDL_InitSteamControllers(SteamControllerConnectedCallback,
   7.199 @@ -677,11 +782,6 @@
   7.200      return guid;
   7.201  }
   7.202  
   7.203 -SDL_bool SDL_SYS_IsDPAD_DeviceIndex(int device_index)
   7.204 -{
   7.205 -    return JoystickByDevIndex(device_index)->naxes == 0;
   7.206 -}
   7.207 -
   7.208  #endif /* SDL_JOYSTICK_ANDROID */
   7.209  
   7.210  /* vi: set ts=4 sw=4 expandtab: */
     8.1 --- a/src/joystick/android/SDL_sysjoystick_c.h	Fri Mar 02 22:53:25 2018 -0800
     8.2 +++ b/src/joystick/android/SDL_sysjoystick_c.h	Tue Mar 06 14:51:50 2018 -0800
     8.3 @@ -32,7 +32,7 @@
     8.4  extern int Android_OnPadUp(int device_id, int keycode);
     8.5  extern int Android_OnJoy(int device_id, int axisnum, float value);
     8.6  extern int Android_OnHat(int device_id, int hat_id, int x, int y);
     8.7 -extern int Android_AddJoystick(int device_id, const char *name, const char *desc, SDL_bool is_accelerometer, int nbuttons, int naxes, int nhats, int nballs);
     8.8 +extern int Android_AddJoystick(int device_id, const char *name, const char *desc, int vendor_id, int product_id, SDL_bool is_accelerometer, int button_mask, int naxes, int nhats, int nballs);
     8.9  extern int Android_RemoveJoystick(int device_id);
    8.10  
    8.11  /* A linked list of available joysticks */
    8.12 @@ -45,6 +45,7 @@
    8.13      SDL_bool is_accelerometer;
    8.14      SDL_Joystick *joystick;
    8.15      int nbuttons, naxes, nhats, nballs;
    8.16 +    int dpad_state;
    8.17      
    8.18      /* Steam Controller support */
    8.19      SDL_bool m_bSteamController;