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.
parent
2419d26724
commit
9e651b6915
|
@ -17,7 +17,8 @@ public class SDLControllerManager
|
|||
public static native int nativeSetupJNI();
|
||||
|
||||
public static native int nativeAddJoystick(int device_id, String name, String desc,
|
||||
int is_accelerometer, int nbuttons,
|
||||
int vendor_id, int product_id,
|
||||
boolean is_accelerometer, int button_mask,
|
||||
int naxes, int nhats, int nballs);
|
||||
public static native int nativeRemoveJoystick(int device_id);
|
||||
public static native int nativeAddHaptic(int device_id, String name);
|
||||
|
@ -42,7 +43,9 @@ public class SDLControllerManager
|
|||
}
|
||||
|
||||
public static void setup() {
|
||||
if (Build.VERSION.SDK_INT >= 16) {
|
||||
if (Build.VERSION.SDK_INT >= 19) {
|
||||
mJoystickHandler = new SDLJoystickHandler_API19();
|
||||
} else if (Build.VERSION.SDK_INT >= 16) {
|
||||
mJoystickHandler = new SDLJoystickHandler_API16();
|
||||
} else if (Build.VERSION.SDK_INT >= 12) {
|
||||
mJoystickHandler = new SDLJoystickHandler_API12();
|
||||
|
@ -155,12 +158,7 @@ class SDLJoystickHandler_API12 extends SDLJoystickHandler {
|
|||
@Override
|
||||
public void pollInputDevices() {
|
||||
int[] deviceIds = InputDevice.getDeviceIds();
|
||||
// It helps processing the device ids in reverse order
|
||||
// For example, in the case of the XBox 360 wireless dongle,
|
||||
// so the first controller seen by SDL matches what the receiver
|
||||
// considers to be the first controller
|
||||
|
||||
for(int i=deviceIds.length-1; i>-1; i--) {
|
||||
for(int i=0; i < deviceIds.length; ++i) {
|
||||
SDLJoystick joystick = getJoystick(deviceIds[i]);
|
||||
if (joystick == null) {
|
||||
joystick = new SDLJoystick();
|
||||
|
@ -187,8 +185,7 @@ class SDLJoystickHandler_API12 extends SDLJoystickHandler {
|
|||
}
|
||||
|
||||
mJoysticks.add(joystick);
|
||||
SDLControllerManager.nativeAddJoystick(joystick.device_id, joystick.name, joystick.desc, 0, -1,
|
||||
joystick.axes.size(), joystick.hats.size()/2, 0);
|
||||
SDLControllerManager.nativeAddJoystick(joystick.device_id, joystick.name, joystick.desc, getVendorId(joystickDevice), getProductId(joystickDevice), false, getButtonMask(joystickDevice), joystick.axes.size(), joystick.hats.size()/2, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -259,9 +256,17 @@ class SDLJoystickHandler_API12 extends SDLJoystickHandler {
|
|||
public String getJoystickDescriptor(InputDevice joystickDevice) {
|
||||
return joystickDevice.getName();
|
||||
}
|
||||
public int getProductId(InputDevice joystickDevice) {
|
||||
return 0;
|
||||
}
|
||||
public int getVendorId(InputDevice joystickDevice) {
|
||||
return 0;
|
||||
}
|
||||
public int getButtonMask(InputDevice joystickDevice) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class SDLJoystickHandler_API16 extends SDLJoystickHandler_API12 {
|
||||
|
||||
@Override
|
||||
|
@ -276,6 +281,112 @@ class SDLJoystickHandler_API16 extends SDLJoystickHandler_API12 {
|
|||
}
|
||||
}
|
||||
|
||||
class SDLJoystickHandler_API19 extends SDLJoystickHandler_API16 {
|
||||
|
||||
@Override
|
||||
public int getProductId(InputDevice joystickDevice) {
|
||||
return joystickDevice.getProductId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVendorId(InputDevice joystickDevice) {
|
||||
return joystickDevice.getVendorId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getButtonMask(InputDevice joystickDevice) {
|
||||
int button_mask = 0;
|
||||
int[] keys = new int[] {
|
||||
KeyEvent.KEYCODE_BUTTON_A,
|
||||
KeyEvent.KEYCODE_BUTTON_B,
|
||||
KeyEvent.KEYCODE_BUTTON_X,
|
||||
KeyEvent.KEYCODE_BUTTON_Y,
|
||||
KeyEvent.KEYCODE_BACK,
|
||||
KeyEvent.KEYCODE_BUTTON_MODE,
|
||||
KeyEvent.KEYCODE_BUTTON_START,
|
||||
KeyEvent.KEYCODE_BUTTON_THUMBL,
|
||||
KeyEvent.KEYCODE_BUTTON_THUMBR,
|
||||
KeyEvent.KEYCODE_BUTTON_L1,
|
||||
KeyEvent.KEYCODE_BUTTON_R1,
|
||||
KeyEvent.KEYCODE_DPAD_UP,
|
||||
KeyEvent.KEYCODE_DPAD_DOWN,
|
||||
KeyEvent.KEYCODE_DPAD_LEFT,
|
||||
KeyEvent.KEYCODE_DPAD_RIGHT,
|
||||
KeyEvent.KEYCODE_BUTTON_SELECT,
|
||||
KeyEvent.KEYCODE_DPAD_CENTER,
|
||||
|
||||
// These don't map into any SDL controller buttons directly
|
||||
KeyEvent.KEYCODE_BUTTON_L2,
|
||||
KeyEvent.KEYCODE_BUTTON_R2,
|
||||
KeyEvent.KEYCODE_BUTTON_C,
|
||||
KeyEvent.KEYCODE_BUTTON_Z,
|
||||
KeyEvent.KEYCODE_BUTTON_1,
|
||||
KeyEvent.KEYCODE_BUTTON_2,
|
||||
KeyEvent.KEYCODE_BUTTON_3,
|
||||
KeyEvent.KEYCODE_BUTTON_4,
|
||||
KeyEvent.KEYCODE_BUTTON_5,
|
||||
KeyEvent.KEYCODE_BUTTON_6,
|
||||
KeyEvent.KEYCODE_BUTTON_7,
|
||||
KeyEvent.KEYCODE_BUTTON_8,
|
||||
KeyEvent.KEYCODE_BUTTON_9,
|
||||
KeyEvent.KEYCODE_BUTTON_10,
|
||||
KeyEvent.KEYCODE_BUTTON_11,
|
||||
KeyEvent.KEYCODE_BUTTON_12,
|
||||
KeyEvent.KEYCODE_BUTTON_13,
|
||||
KeyEvent.KEYCODE_BUTTON_14,
|
||||
KeyEvent.KEYCODE_BUTTON_15,
|
||||
KeyEvent.KEYCODE_BUTTON_16,
|
||||
};
|
||||
int[] masks = new int[] {
|
||||
(1 << 0), // A -> A
|
||||
(1 << 1), // B -> B
|
||||
(1 << 2), // X -> X
|
||||
(1 << 3), // Y -> Y
|
||||
(1 << 4), // BACK -> BACK
|
||||
(1 << 5), // MODE -> GUIDE
|
||||
(1 << 6), // START -> START
|
||||
(1 << 7), // THUMBL -> LEFTSTICK
|
||||
(1 << 8), // THUMBR -> RIGHTSTICK
|
||||
(1 << 9), // L1 -> LEFTSHOULDER
|
||||
(1 << 10), // R1 -> RIGHTSHOULDER
|
||||
(1 << 11), // DPAD_UP -> DPAD_UP
|
||||
(1 << 12), // DPAD_DOWN -> DPAD_DOWN
|
||||
(1 << 13), // DPAD_LEFT -> DPAD_LEFT
|
||||
(1 << 14), // DPAD_RIGHT -> DPAD_RIGHT
|
||||
(1 << 4), // SELECT -> BACK
|
||||
(1 << 0), // DPAD_CENTER -> A
|
||||
(1 << 15), // L2 -> ??
|
||||
(1 << 16), // R2 -> ??
|
||||
(1 << 17), // C -> ??
|
||||
(1 << 18), // Z -> ??
|
||||
(1 << 20), // 1 -> ??
|
||||
(1 << 21), // 2 -> ??
|
||||
(1 << 22), // 3 -> ??
|
||||
(1 << 23), // 4 -> ??
|
||||
(1 << 24), // 5 -> ??
|
||||
(1 << 25), // 6 -> ??
|
||||
(1 << 26), // 7 -> ??
|
||||
(1 << 27), // 8 -> ??
|
||||
(1 << 28), // 9 -> ??
|
||||
(1 << 29), // 10 -> ??
|
||||
(1 << 30), // 11 -> ??
|
||||
(1 << 31), // 12 -> ??
|
||||
// We're out of room...
|
||||
0xFFFFFFFF, // 13 -> ??
|
||||
0xFFFFFFFF, // 14 -> ??
|
||||
0xFFFFFFFF, // 15 -> ??
|
||||
0xFFFFFFFF, // 16 -> ??
|
||||
};
|
||||
boolean[] has_keys = joystickDevice.hasKeys(keys);
|
||||
for (int i = 0; i < keys.length; ++i) {
|
||||
if (has_keys[i]) {
|
||||
button_mask |= masks[i];
|
||||
}
|
||||
}
|
||||
return button_mask;
|
||||
}
|
||||
}
|
||||
|
||||
class SDLHapticHandler {
|
||||
|
||||
class SDLHaptic {
|
||||
|
|
|
@ -169,8 +169,8 @@ JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativeHat)(
|
|||
|
||||
JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick)(
|
||||
JNIEnv* env, jclass jcls,
|
||||
jint device_id, jstring device_name, jstring device_desc, jint is_accelerometer,
|
||||
jint nbuttons, jint naxes, jint nhats, jint nballs);
|
||||
jint device_id, jstring device_name, jstring device_desc, jint vendor_id, jint product_id,
|
||||
jboolean is_accelerometer, jint button_mask, jint naxes, jint nhats, jint nballs);
|
||||
|
||||
JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveJoystick)(
|
||||
JNIEnv* env, jclass jcls,
|
||||
|
@ -543,14 +543,15 @@ JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativeHat)(
|
|||
|
||||
JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick)(
|
||||
JNIEnv* env, jclass jcls,
|
||||
jint device_id, jstring device_name, jstring device_desc, jint is_accelerometer,
|
||||
jint nbuttons, jint naxes, jint nhats, jint nballs)
|
||||
jint device_id, jstring device_name, jstring device_desc,
|
||||
jint vendor_id, jint product_id, jboolean is_accelerometer,
|
||||
jint button_mask, jint naxes, jint nhats, jint nballs)
|
||||
{
|
||||
int retval;
|
||||
const char *name = (*env)->GetStringUTFChars(env, device_name, NULL);
|
||||
const char *desc = (*env)->GetStringUTFChars(env, device_desc, NULL);
|
||||
|
||||
retval = Android_AddJoystick(device_id, name, desc, (SDL_bool) is_accelerometer, nbuttons, naxes, nhats, nballs);
|
||||
retval = Android_AddJoystick(device_id, name, desc, vendor_id, product_id, is_accelerometer ? SDL_TRUE : SDL_FALSE, button_mask, naxes, nhats, nballs);
|
||||
|
||||
(*env)->ReleaseStringUTFChars(env, device_name, name);
|
||||
(*env)->ReleaseStringUTFChars(env, device_desc, desc);
|
||||
|
|
|
@ -97,8 +97,8 @@ typedef struct _ControllerMapping_t
|
|||
|
||||
static SDL_JoystickGUID s_zeroGUID;
|
||||
static ControllerMapping_t *s_pSupportedControllers = NULL;
|
||||
static ControllerMapping_t *s_pDefaultMapping = NULL;
|
||||
static ControllerMapping_t *s_pXInputMapping = NULL;
|
||||
static ControllerMapping_t *s_pEmscriptenMapping = NULL;
|
||||
|
||||
/* The SDL game controller structure */
|
||||
struct _SDL_GameController
|
||||
|
@ -869,6 +869,117 @@ SDL_PrivateAddMappingForGUID(SDL_JoystickGUID jGUID, const char *mappingString,
|
|||
return pControllerMapping;
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
/*
|
||||
* Helper function to guess at a mapping based on the elements reported for this controller
|
||||
*/
|
||||
static ControllerMapping_t *SDL_CreateMappingForAndroidController(const char *name, SDL_JoystickGUID guid)
|
||||
{
|
||||
SDL_bool existing;
|
||||
char name_string[128];
|
||||
char mapping_string[1024];
|
||||
int button_mask;
|
||||
int axis_mask;
|
||||
|
||||
button_mask = SDL_SwapLE16(*(Uint16*)(&guid.data[sizeof(guid.data)-4]));
|
||||
axis_mask = SDL_SwapLE16(*(Uint16*)(&guid.data[sizeof(guid.data)-2]));
|
||||
if (!button_mask && !axis_mask) {
|
||||
/* Accelerometer, shouldn't have a game controller mapping */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Remove any commas in the name */
|
||||
SDL_strlcpy(name_string, name, sizeof(name_string));
|
||||
{
|
||||
char *spot;
|
||||
for (spot = name_string; *spot; ++spot) {
|
||||
if (*spot == ',') {
|
||||
*spot = ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
SDL_snprintf(mapping_string, sizeof(mapping_string), "none,%s,", name_string);
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_A)) {
|
||||
SDL_strlcat(mapping_string, "a:b0,", sizeof(mapping_string));
|
||||
}
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_B)) {
|
||||
SDL_strlcat(mapping_string, "b:b1,", sizeof(mapping_string));
|
||||
} else if (button_mask & (1 << SDL_CONTROLLER_BUTTON_BACK)) {
|
||||
/* Use the back button as "B" for easy UI navigation with TV remotes */
|
||||
SDL_strlcat(mapping_string, "b:b4,", sizeof(mapping_string));
|
||||
button_mask &= ~(1 << SDL_CONTROLLER_BUTTON_BACK);
|
||||
}
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_X)) {
|
||||
SDL_strlcat(mapping_string, "x:b2,", sizeof(mapping_string));
|
||||
}
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_Y)) {
|
||||
SDL_strlcat(mapping_string, "y:b3,", sizeof(mapping_string));
|
||||
}
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_BACK)) {
|
||||
SDL_strlcat(mapping_string, "back:b4,", sizeof(mapping_string));
|
||||
}
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_GUIDE)) {
|
||||
SDL_strlcat(mapping_string, "guide:b5,", sizeof(mapping_string));
|
||||
#if 0 /* Actually this will be done in Steam */
|
||||
} else if (button_mask & (1 << SDL_CONTROLLER_BUTTON_START)) {
|
||||
/* The guide button doesn't exist, use the start button instead,
|
||||
so you can do Steam guide button chords and open the Steam overlay.
|
||||
*/
|
||||
SDL_strlcat(mapping_string, "guide:b6,", sizeof(mapping_string));
|
||||
button_mask &= ~(1 << SDL_CONTROLLER_BUTTON_START);
|
||||
#endif
|
||||
}
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_START)) {
|
||||
SDL_strlcat(mapping_string, "start:b6,", sizeof(mapping_string));
|
||||
}
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_LEFTSTICK)) {
|
||||
SDL_strlcat(mapping_string, "leftstick:b7,", sizeof(mapping_string));
|
||||
}
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_RIGHTSTICK)) {
|
||||
SDL_strlcat(mapping_string, "rightstick:b8,", sizeof(mapping_string));
|
||||
}
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_LEFTSHOULDER)) {
|
||||
SDL_strlcat(mapping_string, "leftshoulder:b9,", sizeof(mapping_string));
|
||||
}
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)) {
|
||||
SDL_strlcat(mapping_string, "rightshoulder:b10,", sizeof(mapping_string));
|
||||
}
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_UP)) {
|
||||
SDL_strlcat(mapping_string, "dpup:b11,", sizeof(mapping_string));
|
||||
}
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_DOWN)) {
|
||||
SDL_strlcat(mapping_string, "dpdown:b12,", sizeof(mapping_string));
|
||||
}
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_LEFT)) {
|
||||
SDL_strlcat(mapping_string, "dpleft:b13,", sizeof(mapping_string));
|
||||
}
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_RIGHT)) {
|
||||
SDL_strlcat(mapping_string, "dpright:b14,", sizeof(mapping_string));
|
||||
}
|
||||
if (axis_mask & (1 << SDL_CONTROLLER_AXIS_LEFTX)) {
|
||||
SDL_strlcat(mapping_string, "leftx:a0,", sizeof(mapping_string));
|
||||
}
|
||||
if (axis_mask & (1 << SDL_CONTROLLER_AXIS_LEFTY)) {
|
||||
SDL_strlcat(mapping_string, "lefty:a1,", sizeof(mapping_string));
|
||||
}
|
||||
if (axis_mask & (1 << SDL_CONTROLLER_AXIS_RIGHTX)) {
|
||||
SDL_strlcat(mapping_string, "rightx:a2,", sizeof(mapping_string));
|
||||
}
|
||||
if (axis_mask & (1 << SDL_CONTROLLER_AXIS_RIGHTY)) {
|
||||
SDL_strlcat(mapping_string, "righty:a3,", sizeof(mapping_string));
|
||||
}
|
||||
if (axis_mask & (1 << SDL_CONTROLLER_AXIS_TRIGGERLEFT)) {
|
||||
SDL_strlcat(mapping_string, "lefttrigger:a4,", sizeof(mapping_string));
|
||||
}
|
||||
if (axis_mask & (1 << SDL_CONTROLLER_AXIS_TRIGGERRIGHT)) {
|
||||
SDL_strlcat(mapping_string, "righttrigger:a5,", sizeof(mapping_string));
|
||||
}
|
||||
return SDL_PrivateAddMappingForGUID(guid, mapping_string,
|
||||
&existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT);
|
||||
}
|
||||
#endif /* __ANDROID__ */
|
||||
|
||||
|
||||
/*
|
||||
* Helper function to determine pre-calculated offset to certain joystick mappings
|
||||
*/
|
||||
|
@ -877,13 +988,6 @@ static ControllerMapping_t *SDL_PrivateGetControllerMappingForNameAndGUID(const
|
|||
ControllerMapping_t *mapping;
|
||||
|
||||
mapping = SDL_PrivateGetControllerMappingForGUID(&guid);
|
||||
#if defined(SDL_JOYSTICK_EMSCRIPTEN)
|
||||
if (!mapping && s_pEmscriptenMapping) {
|
||||
mapping = s_pEmscriptenMapping;
|
||||
}
|
||||
#else
|
||||
(void) s_pEmscriptenMapping; /* pacify ARMCC */
|
||||
#endif
|
||||
#ifdef __LINUX__
|
||||
if (!mapping && name) {
|
||||
if (SDL_strstr(name, "Xbox 360 Wireless Receiver")) {
|
||||
|
@ -901,6 +1005,14 @@ static ControllerMapping_t *SDL_PrivateGetControllerMappingForNameAndGUID(const
|
|||
mapping = s_pXInputMapping;
|
||||
}
|
||||
}
|
||||
#ifdef __ANDROID__
|
||||
if (!mapping) {
|
||||
mapping = SDL_CreateMappingForAndroidController(name, guid);
|
||||
}
|
||||
#endif
|
||||
if (!mapping) {
|
||||
mapping = s_pDefaultMapping;
|
||||
}
|
||||
return mapping;
|
||||
}
|
||||
|
||||
|
@ -926,15 +1038,6 @@ static ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index)
|
|||
mapping = s_pXInputMapping;
|
||||
}
|
||||
#endif
|
||||
#if defined(__ANDROID__)
|
||||
if (!mapping && SDL_SYS_IsDPAD_DeviceIndex(device_index)) {
|
||||
SDL_bool existing;
|
||||
char mapping_string[1024];
|
||||
SDL_snprintf(mapping_string, sizeof(mapping_string), "none,%s,a:b0,b:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,", name);
|
||||
mapping = SDL_PrivateAddMappingForGUID(guid, mapping_string,
|
||||
&existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT);
|
||||
}
|
||||
#endif /* __ANDROID__ */
|
||||
SDL_UnlockJoysticks();
|
||||
return mapping;
|
||||
}
|
||||
|
@ -1018,8 +1121,8 @@ SDL_PrivateGameControllerAddMapping(const char *mappingString, SDL_ControllerMap
|
|||
{
|
||||
char *pchGUID;
|
||||
SDL_JoystickGUID jGUID;
|
||||
SDL_bool is_default_mapping = SDL_FALSE;
|
||||
SDL_bool is_xinput_mapping = SDL_FALSE;
|
||||
SDL_bool is_emscripten_mapping = SDL_FALSE;
|
||||
SDL_bool existing = SDL_FALSE;
|
||||
ControllerMapping_t *pControllerMapping;
|
||||
|
||||
|
@ -1031,12 +1134,11 @@ SDL_PrivateGameControllerAddMapping(const char *mappingString, SDL_ControllerMap
|
|||
if (!pchGUID) {
|
||||
return SDL_SetError("Couldn't parse GUID from %s", mappingString);
|
||||
}
|
||||
if (!SDL_strcasecmp(pchGUID, "xinput")) {
|
||||
if (!SDL_strcasecmp(pchGUID, "default")) {
|
||||
is_default_mapping = SDL_TRUE;
|
||||
} else if (!SDL_strcasecmp(pchGUID, "xinput")) {
|
||||
is_xinput_mapping = SDL_TRUE;
|
||||
}
|
||||
if (!SDL_strcasecmp(pchGUID, "emscripten")) {
|
||||
is_emscripten_mapping = SDL_TRUE;
|
||||
}
|
||||
jGUID = SDL_JoystickGetGUIDFromString(pchGUID);
|
||||
SDL_free(pchGUID);
|
||||
|
||||
|
@ -1048,12 +1150,11 @@ SDL_PrivateGameControllerAddMapping(const char *mappingString, SDL_ControllerMap
|
|||
if (existing) {
|
||||
return 0;
|
||||
} else {
|
||||
if (is_xinput_mapping) {
|
||||
if (is_default_mapping) {
|
||||
s_pDefaultMapping = pControllerMapping;
|
||||
} else if (is_xinput_mapping) {
|
||||
s_pXInputMapping = pControllerMapping;
|
||||
}
|
||||
if (is_emscripten_mapping) {
|
||||
s_pEmscriptenMapping = pControllerMapping;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -208,14 +208,11 @@ static const char *s_ControllerMappings [] =
|
|||
"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,",
|
||||
#endif
|
||||
#if defined(__ANDROID__)
|
||||
"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,",
|
||||
"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,",
|
||||
"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,",
|
||||
"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,",
|
||||
"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,",
|
||||
"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,",
|
||||
"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,",
|
||||
"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,",
|
||||
"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,",
|
||||
"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,",
|
||||
"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,",
|
||||
"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? */
|
||||
#endif
|
||||
#if defined(SDL_JOYSTICK_MFI)
|
||||
"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,",
|
||||
|
@ -224,7 +221,7 @@ static const char *s_ControllerMappings [] =
|
|||
"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,",
|
||||
#endif
|
||||
#if defined(SDL_JOYSTICK_EMSCRIPTEN)
|
||||
"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,",
|
||||
"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,",
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
|
|
@ -104,6 +104,23 @@ SDL_NumJoysticks(void)
|
|||
return SDL_SYS_NumJoysticks();
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform any needed fixups for joystick names
|
||||
*/
|
||||
static const char *
|
||||
SDL_FixupJoystickName(const char *name)
|
||||
{
|
||||
if (name) {
|
||||
const char *skip_prefix = "NVIDIA Corporation ";
|
||||
|
||||
if (SDL_strncmp(name, skip_prefix, SDL_strlen(skip_prefix)) == 0) {
|
||||
name += SDL_strlen(skip_prefix);
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get the implementation dependent name of a joystick
|
||||
*/
|
||||
|
@ -114,7 +131,7 @@ SDL_JoystickNameForIndex(int device_index)
|
|||
SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
|
||||
return (NULL);
|
||||
}
|
||||
return (SDL_SYS_JoystickNameForDeviceIndex(device_index));
|
||||
return SDL_FixupJoystickName(SDL_SYS_JoystickNameForDeviceIndex(device_index));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -481,7 +498,7 @@ SDL_JoystickName(SDL_Joystick * joystick)
|
|||
return (NULL);
|
||||
}
|
||||
|
||||
return (joystick->name);
|
||||
return SDL_FixupJoystickName(joystick->name);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -126,11 +126,6 @@ extern SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick);
|
|||
extern SDL_bool SDL_SYS_IsXInputGamepad_DeviceIndex(int device_index);
|
||||
#endif
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
/* Function returns SDL_TRUE if this device is a DPAD (maybe a TV remote) */
|
||||
extern SDL_bool SDL_SYS_IsDPAD_DeviceIndex(int device_index);
|
||||
#endif
|
||||
|
||||
#endif /* SDL_sysjoystick_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
@ -72,6 +72,28 @@ static int numjoysticks = 0;
|
|||
static int instance_counter = 0;
|
||||
|
||||
|
||||
/* Public domain CRC implementation adapted from:
|
||||
http://home.thep.lu.se/~bjorn/crc/crc32_simple.c
|
||||
*/
|
||||
static Uint32 crc32_for_byte(Uint32 r)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < 8; ++i) {
|
||||
r = (r & 1? 0: (Uint32)0xEDB88320L) ^ r >> 1;
|
||||
}
|
||||
return r ^ (Uint32)0xFF000000L;
|
||||
}
|
||||
|
||||
static Uint32 crc32(const void *data, int count)
|
||||
{
|
||||
Uint32 crc = 0;
|
||||
int i;
|
||||
for(i = 0; i < count; ++i) {
|
||||
crc = crc32_for_byte((Uint8)crc ^ ((const Uint8*)data)[i]) ^ crc >> 8;
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
/* Function to convert Android keyCodes into SDL ones.
|
||||
* This code manipulation is done to get a sequential list of codes.
|
||||
* FIXME: This is only suited for the case where we use a fixed number of buttons determined by ANDROID_MAX_NBUTTONS
|
||||
|
@ -213,7 +235,7 @@ Android_OnPadDown(int device_id, int keycode)
|
|||
if (button >= 0) {
|
||||
item = JoystickByDeviceId(device_id);
|
||||
if (item && item->joystick) {
|
||||
SDL_PrivateJoystickButton(item->joystick, button , SDL_PRESSED);
|
||||
SDL_PrivateJoystickButton(item->joystick, button, SDL_PRESSED);
|
||||
} else {
|
||||
SDL_SendKeyboardKey(SDL_PRESSED, button_to_scancode(button));
|
||||
}
|
||||
|
@ -256,16 +278,43 @@ Android_OnJoy(int device_id, int axis, float value)
|
|||
int
|
||||
Android_OnHat(int device_id, int hat_id, int x, int y)
|
||||
{
|
||||
const Uint8 position_map[3][3] = {
|
||||
{SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP},
|
||||
{SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT},
|
||||
{SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN}
|
||||
};
|
||||
const int DPAD_UP_MASK = (1 << SDL_CONTROLLER_BUTTON_DPAD_UP);
|
||||
const int DPAD_DOWN_MASK = (1 << SDL_CONTROLLER_BUTTON_DPAD_DOWN);
|
||||
const int DPAD_LEFT_MASK = (1 << SDL_CONTROLLER_BUTTON_DPAD_LEFT);
|
||||
const int DPAD_RIGHT_MASK = (1 << SDL_CONTROLLER_BUTTON_DPAD_RIGHT);
|
||||
|
||||
if (x >= -1 && x <=1 && y >= -1 && y <= 1) {
|
||||
if (x >= -1 && x <= 1 && y >= -1 && y <= 1) {
|
||||
SDL_joylist_item *item = JoystickByDeviceId(device_id);
|
||||
if (item && item->joystick) {
|
||||
SDL_PrivateJoystickHat(item->joystick, hat_id, position_map[y+1][x+1]);
|
||||
int dpad_state = 0;
|
||||
int dpad_delta;
|
||||
if (x < 0) {
|
||||
dpad_state |= DPAD_LEFT_MASK;
|
||||
} else if (x > 0) {
|
||||
dpad_state |= DPAD_RIGHT_MASK;
|
||||
}
|
||||
if (y < 0) {
|
||||
dpad_state |= DPAD_UP_MASK;
|
||||
} else if (y > 0) {
|
||||
dpad_state |= DPAD_DOWN_MASK;
|
||||
}
|
||||
|
||||
dpad_delta = (dpad_state ^ item->dpad_state);
|
||||
if (dpad_delta) {
|
||||
if (dpad_delta & DPAD_UP_MASK) {
|
||||
SDL_PrivateJoystickButton(item->joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, (dpad_state & DPAD_UP_MASK) ? SDL_PRESSED : SDL_RELEASED);
|
||||
}
|
||||
if (dpad_delta & DPAD_DOWN_MASK) {
|
||||
SDL_PrivateJoystickButton(item->joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, (dpad_state & DPAD_DOWN_MASK) ? SDL_PRESSED : SDL_RELEASED);
|
||||
}
|
||||
if (dpad_delta & DPAD_LEFT_MASK) {
|
||||
SDL_PrivateJoystickButton(item->joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, (dpad_state & DPAD_LEFT_MASK) ? SDL_PRESSED : SDL_RELEASED);
|
||||
}
|
||||
if (dpad_delta & DPAD_RIGHT_MASK) {
|
||||
SDL_PrivateJoystickButton(item->joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, (dpad_state & DPAD_RIGHT_MASK) ? SDL_PRESSED : SDL_RELEASED);
|
||||
}
|
||||
item->dpad_state = dpad_state;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -275,10 +324,15 @@ Android_OnHat(int device_id, int hat_id, int x, int y)
|
|||
|
||||
|
||||
int
|
||||
Android_AddJoystick(int device_id, const char *name, const char *desc, SDL_bool is_accelerometer, int nbuttons, int naxes, int nhats, int nballs)
|
||||
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)
|
||||
{
|
||||
SDL_JoystickGUID guid;
|
||||
const Uint16 BUS_BLUETOOTH = 0x05;
|
||||
SDL_joylist_item *item;
|
||||
SDL_JoystickGUID guid;
|
||||
Uint16 *guid16 = (Uint16 *)guid.data;
|
||||
int i;
|
||||
int axis_mask;
|
||||
|
||||
|
||||
if (!SDL_GetHintBoolean(SDL_HINT_TV_REMOTE_AS_JOYSTICK, SDL_TRUE)) {
|
||||
/* Ignore devices that aren't actually controllers (e.g. remotes), they'll be handled as keyboard input */
|
||||
|
@ -291,9 +345,57 @@ Android_AddJoystick(int device_id, const char *name, const char *desc, SDL_bool
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* the GUID is just the first 16 chars of the name for now */
|
||||
SDL_zero(guid);
|
||||
SDL_memcpy(&guid, desc, SDL_min(sizeof(guid), SDL_strlen(desc)));
|
||||
#ifdef DEBUG_JOYSTICK
|
||||
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);
|
||||
#endif
|
||||
|
||||
/* Add the available buttons and axes
|
||||
The axis mask should probably come from Java where there is more information about the axes...
|
||||
*/
|
||||
axis_mask = 0;
|
||||
if (!is_accelerometer) {
|
||||
if (naxes >= 2) {
|
||||
axis_mask |= ((1 << SDL_CONTROLLER_AXIS_LEFTX) | (1 << SDL_CONTROLLER_AXIS_LEFTY));
|
||||
}
|
||||
if (naxes >= 4) {
|
||||
axis_mask |= ((1 << SDL_CONTROLLER_AXIS_RIGHTX) | (1 << SDL_CONTROLLER_AXIS_RIGHTY));
|
||||
}
|
||||
if (naxes >= 6) {
|
||||
axis_mask |= ((1 << SDL_CONTROLLER_AXIS_TRIGGERLEFT) | (1 << SDL_CONTROLLER_AXIS_TRIGGERRIGHT));
|
||||
}
|
||||
}
|
||||
|
||||
if (nhats > 0) {
|
||||
/* Hat is translated into DPAD buttons */
|
||||
button_mask |= ((1 << SDL_CONTROLLER_BUTTON_DPAD_UP) |
|
||||
(1 << SDL_CONTROLLER_BUTTON_DPAD_DOWN) |
|
||||
(1 << SDL_CONTROLLER_BUTTON_DPAD_LEFT) |
|
||||
(1 << SDL_CONTROLLER_BUTTON_DPAD_RIGHT));
|
||||
nhats = 0;
|
||||
}
|
||||
|
||||
SDL_memset(guid.data, 0, sizeof(guid.data));
|
||||
|
||||
/* We only need 16 bits for each of these; space them out to fill 128. */
|
||||
/* Byteswap so devices get same GUID on little/big endian platforms. */
|
||||
*guid16++ = SDL_SwapLE16(BUS_BLUETOOTH);
|
||||
*guid16++ = 0;
|
||||
|
||||
if (vendor_id && product_id) {
|
||||
*guid16++ = SDL_SwapLE16(vendor_id);
|
||||
*guid16++ = 0;
|
||||
*guid16++ = SDL_SwapLE16(product_id);
|
||||
*guid16++ = 0;
|
||||
} else {
|
||||
Uint32 crc = crc32(desc, SDL_strlen(desc));
|
||||
SDL_memcpy(guid16, desc, SDL_min(2*sizeof(*guid16), SDL_strlen(desc)));
|
||||
guid16 += 2;
|
||||
*(Uint32 *)guid16 = SDL_SwapLE32(crc);
|
||||
guid16 += 2;
|
||||
}
|
||||
|
||||
*guid16++ = SDL_SwapLE16(button_mask);
|
||||
*guid16++ = SDL_SwapLE16(axis_mask);
|
||||
|
||||
item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item));
|
||||
if (item == NULL) {
|
||||
|
@ -310,11 +412,14 @@ Android_AddJoystick(int device_id, const char *name, const char *desc, SDL_bool
|
|||
}
|
||||
|
||||
item->is_accelerometer = is_accelerometer;
|
||||
if (nbuttons > -1) {
|
||||
item->nbuttons = nbuttons;
|
||||
}
|
||||
else {
|
||||
if (button_mask == 0xFFFFFFFF) {
|
||||
item->nbuttons = ANDROID_MAX_NBUTTONS;
|
||||
} else {
|
||||
for (i = 0; i < sizeof(button_mask)*8; ++i) {
|
||||
if (button_mask & (1 << i)) {
|
||||
item->nbuttons = i+1;
|
||||
}
|
||||
}
|
||||
}
|
||||
item->naxes = naxes;
|
||||
item->nhats = nhats;
|
||||
|
@ -467,7 +572,7 @@ SDL_SYS_JoystickInit(void)
|
|||
|
||||
if (SDL_GetHintBoolean(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, SDL_TRUE)) {
|
||||
/* Default behavior, accelerometer as joystick */
|
||||
Android_AddJoystick(ANDROID_ACCELEROMETER_DEVICE_ID, ANDROID_ACCELEROMETER_NAME, ANDROID_ACCELEROMETER_NAME, SDL_TRUE, 0, 3, 0, 0);
|
||||
Android_AddJoystick(ANDROID_ACCELEROMETER_DEVICE_ID, ANDROID_ACCELEROMETER_NAME, ANDROID_ACCELEROMETER_NAME, 0, 0, SDL_TRUE, 0, 3, 0, 0);
|
||||
}
|
||||
|
||||
SDL_InitSteamControllers(SteamControllerConnectedCallback,
|
||||
|
@ -677,11 +782,6 @@ SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
|
|||
return guid;
|
||||
}
|
||||
|
||||
SDL_bool SDL_SYS_IsDPAD_DeviceIndex(int device_index)
|
||||
{
|
||||
return JoystickByDevIndex(device_index)->naxes == 0;
|
||||
}
|
||||
|
||||
#endif /* SDL_JOYSTICK_ANDROID */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
@ -32,7 +32,7 @@ extern int Android_OnPadDown(int device_id, int keycode);
|
|||
extern int Android_OnPadUp(int device_id, int keycode);
|
||||
extern int Android_OnJoy(int device_id, int axisnum, float value);
|
||||
extern int Android_OnHat(int device_id, int hat_id, int x, int y);
|
||||
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);
|
||||
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);
|
||||
extern int Android_RemoveJoystick(int device_id);
|
||||
|
||||
/* A linked list of available joysticks */
|
||||
|
@ -45,6 +45,7 @@ typedef struct SDL_joylist_item
|
|||
SDL_bool is_accelerometer;
|
||||
SDL_Joystick *joystick;
|
||||
int nbuttons, naxes, nhats, nballs;
|
||||
int dpad_state;
|
||||
|
||||
/* Steam Controller support */
|
||||
SDL_bool m_bSteamController;
|
||||
|
|
Loading…
Reference in New Issue