Commit f59b9c8b13811129c620410c7541ec1afe164472

Sam Lantinga 2018-02-06T15:03:38

Replaced SDL_HINT_APPLE_TV_REMOTE_SWIPES_AS_ARROW_KEYS with SDL_HINT_TV_REMOTE_AS_JOYSTICK which controls whether remotes on iOS and Android are interpreted as joysticks (the default) or as return/escape/arrow keys.

diff --git a/include/SDL_hints.h b/include/SDL_hints.h
index 8c0d722..08a00c9 100644
--- a/include/SDL_hints.h
+++ b/include/SDL_hints.h
@@ -356,16 +356,6 @@ extern "C" {
 #define SDL_HINT_APPLE_TV_REMOTE_ALLOW_ROTATION "SDL_APPLE_TV_REMOTE_ALLOW_ROTATION"
 
 /**
- * \brief  A variable controlling whether the Apple TV remote swipes are
- *         translated into arrow key events
- *
- *  This variable can be set to the following values:
- *    "0"       - Swipes are not translated into arrow key events
- *    "1"       - Swipes are translated into arrow key events (the default)
- */
-#define SDL_HINT_APPLE_TV_REMOTE_SWIPES_AS_ARROW_KEYS "SDL_APPLE_TV_REMOTE_SWIPES_AS_ARROW_KEYS"
-
-/**
  * \brief  A variable controlling whether the home indicator bar on iPhone X
  *         should be hidden.
  *
@@ -378,16 +368,25 @@ extern "C" {
 
 /**
  *  \brief  A variable controlling whether the Android / iOS built-in
- *  accelerometer should be listed as a joystick device, rather than listing
- *  actual joysticks only.
+ *  accelerometer should be listed as a joystick device.
  *
  *  This variable can be set to the following values:
- *    "0"       - List only real joysticks and accept input from them
- *    "1"       - List real joysticks along with the accelerometer as if it were a 3 axis joystick (the default).
+ *    "0"       - The accelerometer is not listed as a joystick
+ *    "1"       - The accelerometer is available as a 3 axis joystick (the default).
  */
 #define SDL_HINT_ACCELEROMETER_AS_JOYSTICK "SDL_ACCELEROMETER_AS_JOYSTICK"
 
 /**
+ *  \brief  A variable controlling whether the Android / iOS remotes
+ *  should be listed as joystick devices, instead of sending keyboard events.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - Remotes send enter/escape/arrow key events
+ *    "1"       - Remotes are available as 2 axis, 2 button joysticks (the default).
+ */
+#define SDL_HINT_TV_REMOTE_AS_JOYSTICK "SDL_TV_REMOTE_AS_JOYSTICK"
+
+/**
  *  \brief  A variable that lets you disable the detection and use of Xinput gamepad devices
  *
  *  The variable can be set to the following values:
diff --git a/src/joystick/android/SDL_sysjoystick.c b/src/joystick/android/SDL_sysjoystick.c
index 33e5483..ee6014e 100644
--- a/src/joystick/android/SDL_sysjoystick.c
+++ b/src/joystick/android/SDL_sysjoystick.c
@@ -80,8 +80,7 @@ keycode_to_SDL(int keycode)
 {
     /* FIXME: If this function gets too unwieldy in the future, replace with a lookup table */
     int button = 0;
-    switch(keycode) 
-    {
+    switch (keycode) {
         /* Some gamepad buttons (API 9) */
         case AKEYCODE_BUTTON_A:
             button = SDL_CONTROLLER_BUTTON_A;
@@ -179,7 +178,30 @@ keycode_to_SDL(int keycode)
      */
     SDL_assert(button < ANDROID_MAX_NBUTTONS);
     return button;
-    
+}
+
+static SDL_Scancode
+button_to_scancode(int button)
+{
+    switch (button) {
+    case SDL_CONTROLLER_BUTTON_A:
+        return SDL_SCANCODE_RETURN;
+    case SDL_CONTROLLER_BUTTON_B:
+        return SDL_SCANCODE_ESCAPE;
+    case SDL_CONTROLLER_BUTTON_BACK:
+        return SDL_SCANCODE_ESCAPE;
+    case SDL_CONTROLLER_BUTTON_DPAD_UP:
+        return SDL_SCANCODE_UP;
+    case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
+        return SDL_SCANCODE_DOWN;
+    case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
+        return SDL_SCANCODE_LEFT;
+    case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
+        return SDL_SCANCODE_RIGHT;
+    }
+
+    /* Unsupported button */
+    return SDL_SCANCODE_UNKNOWN;
 }
 
 int
@@ -191,6 +213,8 @@ Android_OnPadDown(int device_id, int keycode)
         item = JoystickByDeviceId(device_id);
         if (item && item->joystick) {
             SDL_PrivateJoystickButton(item->joystick, button , SDL_PRESSED);
+        } else {
+            SDL_SendKeyboardKey(SDL_PRESSED, button_to_scancode(button));
         }
         return 0;
     }
@@ -207,6 +231,8 @@ Android_OnPadUp(int device_id, int keycode)
         item = JoystickByDeviceId(device_id);
         if (item && item->joystick) {
             SDL_PrivateJoystickButton(item->joystick, button, SDL_RELEASED);
+        } else {
+            SDL_SendKeyboardKey(SDL_RELEASED, button_to_scancode(button));
         }
         return 0;
     }
@@ -252,8 +278,15 @@ Android_AddJoystick(int device_id, const char *name, const char *desc, SDL_bool 
 {
     SDL_JoystickGUID guid;
     SDL_joylist_item *item;
+
+    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 */
+        if (naxes < 2 && nhats < 1) {
+            return -1;
+        }
+    }
     
-    if(JoystickByDeviceId(device_id) != NULL || name == NULL) {
+    if (JoystickByDeviceId(device_id) != NULL || name == NULL) {
         return -1;
     }
     
diff --git a/src/joystick/iphoneos/SDL_sysjoystick.m b/src/joystick/iphoneos/SDL_sysjoystick.m
index 2d20f92..e1602e5 100644
--- a/src/joystick/iphoneos/SDL_sysjoystick.m
+++ b/src/joystick/iphoneos/SDL_sysjoystick.m
@@ -150,6 +150,15 @@ SDL_SYS_AddJoystickDevice(GCController *controller, SDL_bool accelerometer)
 {
     SDL_JoystickDeviceItem *device = deviceList;
 
+#if TARGET_OS_TV
+    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 */
+        if (controller && !controller.extendedGamepad && !controller.gamepad && controller.microGamepad) {
+            return;
+        }
+    }
+#endif
+
     while (device != NULL) {
         if (device->controller == controller) {
             return;
@@ -157,13 +166,11 @@ SDL_SYS_AddJoystickDevice(GCController *controller, SDL_bool accelerometer)
         device = device->next;
     }
 
-    device = (SDL_JoystickDeviceItem *) SDL_malloc(sizeof(SDL_JoystickDeviceItem));
+    device = (SDL_JoystickDeviceItem *) SDL_calloc(1, sizeof(SDL_JoystickDeviceItem));
     if (device == NULL) {
         return;
     }
 
-    SDL_zerop(device);
-
     device->accelerometer = accelerometer;
     device->instance_id = instancecounter++;
 
@@ -277,11 +284,11 @@ static SDL_bool SteamControllerConnectedCallback(const char *name, SDL_JoystickG
     }
 
     *device_instance = device->instance_id = instancecounter++;
-	device->name = SDL_strdup(name);
-	device->guid = guid;
-	SDL_GetSteamControllerInputs(&device->nbuttons,
-								 &device->naxes,
-								 &device->nhats);
+    device->name = SDL_strdup(name);
+    device->guid = guid;
+    SDL_GetSteamControllerInputs(&device->nbuttons,
+                                 &device->naxes,
+                                 &device->nhats);
     device->m_bSteamController = SDL_TRUE;
 
     if (deviceList == NULL) {
@@ -305,10 +312,10 @@ static void SteamControllerDisconnectedCallback(int device_instance)
 {
     SDL_JoystickDeviceItem *item;
 
-	for (item = deviceList; item; item = item->next) {
+    for (item = deviceList; item; item = item->next) {
         if (item->instance_id == device_instance) {
-			SDL_SYS_RemoveJoystickDevice(item);
-			break;
+            SDL_SYS_RemoveJoystickDevice(item);
+            break;
         }
     }
 }
@@ -608,9 +615,6 @@ SDL_SYS_MFIJoystickUpdate(SDL_Joystick * joystick)
                 SDL_PrivateJoystickAxis(joystick, i, axes[i]);
             }
 
-            /* Apparently the dpad values are not accurate enough to be useful. */
-            /* hatstate = SDL_SYS_MFIJoystickHatStateForDPad(gamepad.dpad); */
-
             Uint8 buttons[] = {
                 gamepad.buttonA.isPressed,
                 gamepad.buttonX.isPressed,
@@ -620,8 +624,6 @@ SDL_SYS_MFIJoystickUpdate(SDL_Joystick * joystick)
                 updateplayerindex |= (joystick->buttons[i] != buttons[i]);
                 SDL_PrivateJoystickButton(joystick, i, buttons[i]);
             }
-
-            /* TODO: Figure out what to do with reportsAbsoluteDpadValues */
         }
 #endif /* TARGET_OS_TV */
 
diff --git a/src/video/uikit/SDL_uikitview.m b/src/video/uikit/SDL_uikitview.m
index e5dc99a..b4f0f33 100644
--- a/src/video/uikit/SDL_uikitview.m
+++ b/src/video/uikit/SDL_uikitview.m
@@ -44,7 +44,7 @@
 {
     if ((self = [super initWithFrame:frame])) {
 #if TARGET_OS_TV
-        if (SDL_GetHintBoolean(SDL_HINT_APPLE_TV_REMOTE_SWIPES_AS_ARROW_KEYS, SDL_TRUE)) {
+        if (!SDL_GetHintBoolean(SDL_HINT_TV_REMOTE_AS_JOYSTICK, SDL_TRUE)) {
             /* Apple TV Remote touchpad swipe gestures. */
             UISwipeGestureRecognizer *swipeUp = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeGesture:)];
             swipeUp.direction = UISwipeGestureRecognizerDirectionUp;
@@ -237,10 +237,10 @@
         return SDL_SCANCODE_RIGHT;
     case UIPressTypeSelect:
         /* HIG says: "primary button behavior" */
-        return SDL_SCANCODE_SELECT;
+        return SDL_SCANCODE_RETURN;
     case UIPressTypeMenu:
         /* HIG says: "returns to previous screen" */
-        return SDL_SCANCODE_MENU;
+        return SDL_SCANCODE_ESCAPE;
     case UIPressTypePlayPause:
         /* HIG says: "secondary button behavior" */
         return SDL_SCANCODE_PAUSE;
@@ -251,31 +251,34 @@
 
 - (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
 {
-    for (UIPress *press in presses) {
-        SDL_Scancode scancode = [self scancodeFromPressType:press.type];
-        SDL_SendKeyboardKey(SDL_PRESSED, scancode);
-    }
-
+	if (!SDL_GetHintBoolean(SDL_HINT_TV_REMOTE_AS_JOYSTICK, SDL_TRUE)) {
+    	for (UIPress *press in presses) {
+        	SDL_Scancode scancode = [self scancodeFromPressType:press.type];
+        	SDL_SendKeyboardKey(SDL_PRESSED, scancode);
+    	}
+	}
     [super pressesBegan:presses withEvent:event];
 }
 
 - (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
 {
-    for (UIPress *press in presses) {
-        SDL_Scancode scancode = [self scancodeFromPressType:press.type];
-        SDL_SendKeyboardKey(SDL_RELEASED, scancode);
-    }
-
+	if (!SDL_GetHintBoolean(SDL_HINT_TV_REMOTE_AS_JOYSTICK, SDL_TRUE)) {
+		for (UIPress *press in presses) {
+			SDL_Scancode scancode = [self scancodeFromPressType:press.type];
+			SDL_SendKeyboardKey(SDL_RELEASED, scancode);
+		}
+	}
     [super pressesEnded:presses withEvent:event];
 }
 
 - (void)pressesCancelled:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
 {
-    for (UIPress *press in presses) {
-        SDL_Scancode scancode = [self scancodeFromPressType:press.type];
-        SDL_SendKeyboardKey(SDL_RELEASED, scancode);
-    }
-
+	if (!SDL_GetHintBoolean(SDL_HINT_TV_REMOTE_AS_JOYSTICK, SDL_TRUE)) {
+		for (UIPress *press in presses) {
+			SDL_Scancode scancode = [self scancodeFromPressType:press.type];
+			SDL_SendKeyboardKey(SDL_RELEASED, scancode);
+		}
+	}
     [super pressesCancelled:presses withEvent:event];
 }