From c3fdd5a3fbded6323177441045af340fd0ceed6c Mon Sep 17 00:00:00 2001 From: antoniou79 Date: Sat, 25 Mar 2023 00:01:37 +0200 Subject: [PATCH] ANDROID: Basic support for some TV remotes And some fixes for DPAD handling More fixes for DPAD will be coming. We currently don't handle DPAD Center, and also do not handle the case where DPAD is HATs (motion events) --- backends/platform/android/android.cpp | 22 ++++++ backends/platform/android/events.cpp | 67 +++++++++++++++++++ .../scummvm/scummvm/ScummVMEventsBase.java | 34 ++++++++-- 3 files changed, 117 insertions(+), 6 deletions(-) diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 5e38b82a125..96dc8dbadab 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -623,6 +623,28 @@ Common::KeymapperDefaultBindings *OSystem_Android::getKeymapperDefaultBindings() // See: backends/keymapper/remap-widget.cpp: kCloseCmd = 'CLOS' keymapperDefaultBindings->setDefaultBinding(Common::kGuiKeymapName, "CLOS", "AC_BACK"); + // By default DPAD directions will be used for virtual mouse in GUI context + // If the user wants to remap them, they will be able to navigate to Global Options -> Keymaps and do so. + // In some devices (eg. Android TV) with only the remote control as input, it is impossible to navigate the launcher GUI, + // if the DPAD actions are mapped to "up", "down", "left", "right" directions. + // TODO If/when full key-based (ie. non-mouse) navigation of the ScummVM GUI is implemented, + // we can revert back to the core behavior of DPAD being mapped to "up", "down", "left", "right" directions. + keymapperDefaultBindings->addDefaultBinding(Common::kGlobalKeymapName, "VMOUSEUP", "JOY_LEFT_STICK_Y-"); + keymapperDefaultBindings->addDefaultBinding(Common::kGlobalKeymapName, "VMOUSEUP", "JOY_UP"); + keymapperDefaultBindings->addDefaultBinding(Common::kGlobalKeymapName, "VMOUSEDOWN", "JOY_LEFT_STICK_Y+"); + keymapperDefaultBindings->addDefaultBinding(Common::kGlobalKeymapName, "VMOUSEDOWN", "JOY_DOWN"); + keymapperDefaultBindings->addDefaultBinding(Common::kGlobalKeymapName, "VMOUSELEFT", "JOY_LEFT_STICK_X-"); + keymapperDefaultBindings->addDefaultBinding(Common::kGlobalKeymapName, "VMOUSELEFT", "JOY_LEFT"); + keymapperDefaultBindings->addDefaultBinding(Common::kGlobalKeymapName, "VMOUSERIGHT", "JOY_LEFT_STICK_X+"); + keymapperDefaultBindings->addDefaultBinding(Common::kGlobalKeymapName, "VMOUSERIGHT", "JOY_RIGHT"); + keymapperDefaultBindings->addDefaultBinding(Common::kGuiKeymapName, Common::kStandardActionInteract, "JOY_A"); + // TODO Needs JOY_CENTER to be defined + //keymapperDefaultBindings->addDefaultBinding(Common::kGuiKeymapName, Common::kStandardActionInteract, "JOY_CENTER"); + keymapperDefaultBindings->setDefaultBinding(Common::kGuiKeymapName, Common::kStandardActionMoveUp, nullptr); + keymapperDefaultBindings->setDefaultBinding(Common::kGuiKeymapName, Common::kStandardActionMoveDown, nullptr); + keymapperDefaultBindings->setDefaultBinding(Common::kGuiKeymapName, Common::kStandardActionMoveLeft, nullptr); + keymapperDefaultBindings->setDefaultBinding(Common::kGuiKeymapName, Common::kStandardActionMoveRight, nullptr); + return keymapperDefaultBindings; } diff --git a/backends/platform/android/events.cpp b/backends/platform/android/events.cpp index 038c5e33507..beab7fae4e9 100644 --- a/backends/platform/android/events.cpp +++ b/backends/platform/android/events.cpp @@ -76,6 +76,7 @@ enum { JE_BMB_UP = 19, JE_FMB_DOWN = 20, JE_FMB_UP = 21, + JE_TV_REMOTE = 22, JE_QUIT = 0x1000, JE_MENU = 0x1001 }; @@ -551,6 +552,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, case AKEYCODE_DPAD_LEFT: // fall through case AKEYCODE_DPAD_RIGHT: + // Treat as mouse movement if (arg1 != AKEY_EVENT_ACTION_DOWN) return; @@ -586,6 +588,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, return; case AKEYCODE_DPAD_CENTER: + // Treat as mouse click (left click) switch (arg1) { case AKEY_EVENT_ACTION_DOWN: e.type = Common::EVENT_LBUTTONDOWN; @@ -607,6 +610,49 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, return; } + case JE_TV_REMOTE: + switch (arg1) { + case AKEY_EVENT_ACTION_DOWN: + e.type = Common::EVENT_KEYDOWN; + break; + + case AKEY_EVENT_ACTION_UP: + e.type = Common::EVENT_KEYUP; + break; + + default: + LOGE("unhandled jaction on key: %d", arg1); + return; + } + + switch (arg2) { + case AKEYCODE_MEDIA_FAST_FORWARD: + // fall through + case AKEYCODE_MEDIA_REWIND: + // fall through + case AKEYCODE_MEDIA_PLAY_PAUSE: + // Treat as keyboard presses, since they have equivalent hardware keyboard keys + e.kbd.keycode = jkeymap[arg2]; + if (arg5 > 0) { + e.kbdRepeat = true; + } + break; + + // Unfortunately CHANNEL_UP or CHANNEL_DOWN do not trigger for the Fire TV Stick remote (3rd gen) + // despite the documentation (https://developer.amazon.com/docs/fire-tv/remote-input.html) + // so there's no way as of yet to test for them. + // TODO Maybe enable them anyway? Should we create hardware input keys for them in the main code? +// case AKEYCODE_CHANNEL_UP: +// // fall through +// case AKEYCODE_CHANNEL_DOWN: +// break; + + } + + pushEvent(e); + + return; + case JE_DOWN: // LOGD("JE_DOWN"); _touch_pt_down = dynamic_cast(_graphicsManager)->getMousePosition(); @@ -1161,6 +1207,27 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, e.joystick.button = Common::JOYSTICK_BUTTON_RIGHT_STICK; break; + case AKEYCODE_DPAD_UP: + e.joystick.button = Common::JOYSTICK_BUTTON_DPAD_UP; + break; + + case AKEYCODE_DPAD_DOWN: + e.joystick.button = Common::JOYSTICK_BUTTON_DPAD_DOWN; + break; + + case AKEYCODE_DPAD_LEFT: + e.joystick.button = Common::JOYSTICK_BUTTON_DPAD_LEFT; + break; + + case AKEYCODE_DPAD_RIGHT: + e.joystick.button = Common::JOYSTICK_BUTTON_DPAD_RIGHT; + break; + +// case AKEYCODE_DPAD_CENTER: +// // TODO This needs to be defined (backends/keymapper/hardware-input.cpp and common/events.h) +// e.joystick.button = Common::JOYSTICK_BUTTON_DPAD_CENTER; +// break; + default: LOGW("unmapped gamepad key: %d", arg2); return; diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVMEventsBase.java b/backends/platform/android/org/scummvm/scummvm/ScummVMEventsBase.java index d91cff529fd..669f1d24dae 100644 --- a/backends/platform/android/org/scummvm/scummvm/ScummVMEventsBase.java +++ b/backends/platform/android/org/scummvm/scummvm/ScummVMEventsBase.java @@ -48,6 +48,7 @@ public class ScummVMEventsBase implements public static final int JE_BMB_UP = 19; public static final int JE_FMB_DOWN = 20; public static final int JE_FMB_UP = 21; + public static final int JE_TV_REMOTE = 22; public static final int JE_QUIT = 0x1000; public static final int JE_MENU = 0x1001; @@ -222,11 +223,12 @@ public class ScummVMEventsBase implements // case KeyEvent.ACTION_DOWN: // actionStr = "KeyEvent.ACTION_DOWN"; // break; -// case KeyEvent.ACTION_MULTIPLE: -// actionStr = "KeyEvent.ACTION_MULTIPLE"; -// break; // default: -// actionStr = e.toString(); +// if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q && e.getAction() == KeyEvent.ACTION_MULTIPLE) { +// actionStr = "KeyEvent.ACTION_MULTIPLE"; +// } else { +// actionStr = e.toString(); +// } // } // Log.d(ScummVM.LOG_TAG, "SCUMMV-EVENTS-BASE - onKEY:::" + keyCode + " Action::" + actionStr); // Called @@ -369,17 +371,34 @@ public class ScummVMEventsBase implements case KeyEvent.KEYCODE_VOLUME_UP: // We ignore these so that they can be handled by Android. return false; + +// case KeyEvent.KEYCODE_CHANNEL_UP: +// case KeyEvent.KEYCODE_CHANNEL_DOWN: + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: + case KeyEvent.KEYCODE_MEDIA_REWIND: + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: + type = JE_TV_REMOTE; + break; + case KeyEvent.KEYCODE_DPAD_UP: case KeyEvent.KEYCODE_DPAD_DOWN: case KeyEvent.KEYCODE_DPAD_LEFT: case KeyEvent.KEYCODE_DPAD_RIGHT: case KeyEvent.KEYCODE_DPAD_CENTER: - if (e.getSource() == InputDevice.SOURCE_DPAD) { + if ((e.getSource() & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD) { + // When interpreted as JE_DPAD it will work as a mouse (translated in Android backend, events.cpp) + // This is a case for FireTV Stick remote control's DPAD + // The remote control itself is: InputDevice.SOURCE_DPAD | InputDevice.SOURCE_KEYBOARD + // since it also has "buttons" for fast-forward, play/pause toggle, and rewind. + // TODO Evaluate merging this case with setting the type as "JE_GAMEPAD" + // and delegating the key mapping to ScummVM's keymapper type = JE_DPAD; } else { - type = JE_KEY; + // When interpreted as JE_GAMEPAD it will be forwarded to ScummVM's keymapper + type = JE_GAMEPAD; } break; + case KeyEvent.KEYCODE_BUTTON_A: case KeyEvent.KEYCODE_BUTTON_B: case KeyEvent.KEYCODE_BUTTON_C: @@ -397,6 +416,7 @@ public class ScummVMEventsBase implements case KeyEvent.KEYCODE_BUTTON_MODE: type = JE_GAMEPAD; break; + case KeyEvent.KEYCODE_BUTTON_1: case KeyEvent.KEYCODE_BUTTON_2: case KeyEvent.KEYCODE_BUTTON_3: @@ -404,6 +424,7 @@ public class ScummVMEventsBase implements // These are oddly detected with SOURCE_KEYBOARD for joystick so don't bother checking the e.getSource() type = JE_JOYSTICK; break; + default: if (e.isSystem()) { type = JE_SYS_KEY; @@ -414,6 +435,7 @@ public class ScummVMEventsBase implements } //_scummvm.displayMessageOnOSD("GetKey: " + keyCode + " unic=" + eventUnicodeChar+ " arg3= " + (eventUnicodeChar& KeyCharacterMap.COMBINING_ACCENT_MASK) + " meta: " + e.getMetaState()); + //_scummvm.displayMessageOnOSD("GetKey: " + keyCode + " type=" + type + " source=" + e.getSource() + " action= " + action + " arg5= " + e.getRepeatCount()); //Log.d(ScummVM.LOG_TAG,"GetKey: " + keyCode + " unic=" + eventUnicodeChar+ " arg3= " + (eventUnicodeChar& KeyCharacterMap.COMBINING_ACCENT_MASK) + " meta: " + e.getMetaState()); // look in events.cpp for how this is handled