diff --git a/backends/graphics/android/android-graphics.cpp b/backends/graphics/android/android-graphics.cpp index 410dd94f182..f2e22de5543 100644 --- a/backends/graphics/android/android-graphics.cpp +++ b/backends/graphics/android/android-graphics.cpp @@ -66,7 +66,8 @@ static void loadBuiltinTexture(JNI::BitmapResources resource, OpenGL::Surface *s // AndroidGraphicsManager // AndroidGraphicsManager::AndroidGraphicsManager() : - _touchcontrols(nullptr) { + _touchcontrols(nullptr), + _old_touch_mode(OSystem_Android::TOUCH_MODE_TOUCHPAD) { ENTER(); // Initialize our OpenGL ES context. @@ -76,8 +77,8 @@ AndroidGraphicsManager::AndroidGraphicsManager() : loadBuiltinTexture(JNI::BitmapResources::TOUCH_ARROWS_BITMAP, _touchcontrols); _touchcontrols->updateGLTexture(); - // In 2D we always fallback to standard 2D mode - JNI::setTouch3DMode(false); + // not in 3D, not in overlay + dynamic_cast(g_system)->applyTouchSettings(false, false); } AndroidGraphicsManager::~AndroidGraphicsManager() { @@ -150,23 +151,13 @@ void AndroidGraphicsManager::displayMessageOnOSD(const Common::U32String &msg) { JNI::displayMessageOnOSD(msg); } -bool AndroidGraphicsManager::showMouse(bool visible) { - bool last = OpenGL::OpenGLGraphicsManager::showMouse(visible); - - if (visible && last != visible) { - // We just displayed a mouse cursor, disable the 3D mode if user enabled it - JNI::setTouch3DMode(false); - } - - return last; -} - void AndroidGraphicsManager::showOverlay() { if (_overlayVisible) return; - _old_touch_3d_mode = JNI::getTouch3DMode(); - JNI::setTouch3DMode(false); + _old_touch_mode = JNI::getTouchMode(); + // not in 3D, in overlay + dynamic_cast(g_system)->applyTouchSettings(false, true); OpenGL::OpenGLGraphicsManager::showOverlay(); } @@ -175,7 +166,8 @@ void AndroidGraphicsManager::hideOverlay() { if (!_overlayVisible) return; - JNI::setTouch3DMode(_old_touch_3d_mode); + // Restore touch mode active before overlay was shown + JNI::setTouchMode(_old_touch_mode); OpenGL::OpenGLGraphicsManager::hideOverlay(); } diff --git a/backends/graphics/android/android-graphics.h b/backends/graphics/android/android-graphics.h index beb0a58ae58..74a3c6311e4 100644 --- a/backends/graphics/android/android-graphics.h +++ b/backends/graphics/android/android-graphics.h @@ -89,7 +89,6 @@ public: protected: void setSystemMousePosition(const int x, const int y) override {} - bool showMouse(bool visible) override; void showOverlay() override; void hideOverlay() override; @@ -103,7 +102,7 @@ protected: private: OpenGL::Surface *_touchcontrols; - bool _old_touch_3d_mode; + int _old_touch_mode; }; #endif diff --git a/backends/graphics3d/android/android-graphics3d.cpp b/backends/graphics3d/android/android-graphics3d.cpp index ea78e61b755..9203401ea51 100644 --- a/backends/graphics3d/android/android-graphics3d.cpp +++ b/backends/graphics3d/android/android-graphics3d.cpp @@ -93,7 +93,7 @@ AndroidGraphics3dManager::AndroidGraphics3dManager() : _mouse_dont_scale(false), _show_mouse(false), _touchcontrols_texture(nullptr), - _old_touch_3d_mode(false) { + _old_touch_mode(OSystem_Android::TOUCH_MODE_TOUCHPAD) { if (JNI::egl_bits_per_pixel == 16) { // We default to RGB565 and RGBA5551 which is closest to what we setup in Java side @@ -113,7 +113,9 @@ AndroidGraphics3dManager::AndroidGraphics3dManager() : _touchcontrols_texture = loadBuiltinTexture(JNI::BitmapResources::TOUCH_ARROWS_BITMAP); initSurface(); - JNI::setTouch3DMode(true); + + // in 3D, not in overlay + dynamic_cast(g_system)->applyTouchSettings(true, false); } AndroidGraphics3dManager::~AndroidGraphics3dManager() { @@ -124,8 +126,6 @@ AndroidGraphics3dManager::~AndroidGraphics3dManager() { glBindRenderbuffer(GL_RENDERBUFFER, 0); glUseProgram(0); - JNI::setTouch3DMode(false); - deinitSurface(); delete _frame_buffer; @@ -457,8 +457,9 @@ void AndroidGraphics3dManager::showOverlay() { return; } - _old_touch_3d_mode = JNI::getTouch3DMode(); - JNI::setTouch3DMode(false); + _old_touch_mode = JNI::getTouchMode(); + // in 3D, in overlay + dynamic_cast(g_system)->applyTouchSettings(true, true); _show_overlay = true; _force_redraw = true; @@ -504,7 +505,8 @@ void AndroidGraphics3dManager::hideOverlay() { _overlay_background->release(); - JNI::setTouch3DMode(_old_touch_3d_mode); + // Restore touch mode active before overlay was shown + JNI::setTouchMode(_old_touch_mode); warpMouse(_game_texture->width() / 2, _game_texture->height() / 2); diff --git a/backends/graphics3d/android/android-graphics3d.h b/backends/graphics3d/android/android-graphics3d.h index 0e1d3b942f1..846f0b1a5d3 100644 --- a/backends/graphics3d/android/android-graphics3d.h +++ b/backends/graphics3d/android/android-graphics3d.h @@ -183,7 +183,7 @@ private: // Touch controls layer GLESTexture *_touchcontrols_texture; - bool _old_touch_3d_mode; + int _old_touch_mode; }; #endif diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 007cb5c7b67..a8532969706 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -139,7 +139,7 @@ OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) : _eventScaleX(100), _eventScaleY(100), // TODO put these values in some option dlg? - _touchpad_mode(true), + _touch_mode(TOUCH_MODE_TOUCHPAD), _touchpad_scale(66), _dpad_scale(4), // _fingersDown(0), diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index 35a5a66cebc..4b83e05ebd0 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -121,6 +121,13 @@ private: Common::String getSystemProperty(const char *name) const; public: + enum { + TOUCH_MODE_TOUCHPAD = 0, + TOUCH_MODE_MOUSE = 1, + TOUCH_MODE_GAMEPAD = 2, + TOUCH_MODE_MAX = 3 + }; + OSystem_Android(int audio_sample_rate, int audio_buffer_size); virtual ~OSystem_Android(); @@ -136,6 +143,8 @@ public: void pushEvent(const Common::Event &event1, const Common::Event &event2); TouchControls &getTouchControls() { return _touchControls; } + void applyTouchSettings(bool _3dMode, bool overlayShown); + void setupTouchMode(int oldValue, int newValue); private: Common::Queue _event_queue; @@ -146,7 +155,7 @@ private: Common::Point _touch_pt_down, _touch_pt_scroll, _touch_pt_dt, _touch_pt_multi; int _eventScaleX; int _eventScaleY; - bool _touchpad_mode; + int _touch_mode; int _touchpad_scale; int _trackball_scale; int _dpad_scale; diff --git a/backends/platform/android/events.cpp b/backends/platform/android/events.cpp index b26f7fd8174..bd4351886cb 100644 --- a/backends/platform/android/events.cpp +++ b/backends/platform/android/events.cpp @@ -618,7 +618,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, // LOGD("JE_SCROLL"); e.type = Common::EVENT_MOUSEMOVE; - if (_touchpad_mode) { + if (_touch_mode == TOUCH_MODE_TOUCHPAD) { if (_touch_pt_scroll.x == -1 && _touch_pt_scroll.y == -1) { _touch_pt_scroll.x = arg3; _touch_pt_scroll.y = arg4; @@ -647,7 +647,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, e.type = Common::EVENT_MOUSEMOVE; - if (_touchpad_mode) { + if (_touch_mode == TOUCH_MODE_TOUCHPAD) { e.mouse = dynamic_cast(_graphicsManager)->getMousePosition(); } else { e.mouse.x = arg1; @@ -695,7 +695,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, _event_queue.push(_queuedEvent); } - if (!_touchpad_mode) { + if (_touch_mode != TOUCH_MODE_TOUCHPAD) { // In this case the mouse move is done in "direct mode" // ie. the cursor jumps to where the tap occured // so we don't have relMouse coordinates to set for the event @@ -722,7 +722,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, e.type = Common::EVENT_MOUSEMOVE; - if (_touchpad_mode) { + if (_touch_mode == TOUCH_MODE_TOUCHPAD) { e.mouse = dynamic_cast(_graphicsManager)->getMousePosition(); } else { e.mouse.x = arg1; @@ -753,7 +753,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, dptype = Common::EVENT_MOUSEMOVE; - if (_touchpad_mode) { + if (_touch_mode == TOUCH_MODE_TOUCHPAD) { e.mouse.x = (arg1 - _touch_pt_dt.x) * 100 / _touchpad_scale; e.mouse.y = (arg2 - _touch_pt_dt.y) * 100 / _touchpad_scale; e.mouse += _touch_pt_down; @@ -791,7 +791,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, e.type = Common::EVENT_MOUSEMOVE; - if (_touchpad_mode) { + if (_touch_mode == TOUCH_MODE_TOUCHPAD) { e.mouse = dynamic_cast(_graphicsManager)->getMousePosition(); } else { e.mouse.x = arg3; @@ -918,7 +918,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, multitype = Common::EVENT_MOUSEMOVE; // TODO TO TEST for non-touchpad mode too! - if (_touchpad_mode) { + if (_touch_mode == TOUCH_MODE_TOUCHPAD) { e.mouse.x = (arg3 - _touch_pt_multi.x) * 100 / _touchpad_scale; e.mouse.y = (arg4 - _touch_pt_multi.y) * 100 / _touchpad_scale; e.mouse += _touch_pt_down; // TODO maybe we need another reference point??? @@ -1309,4 +1309,15 @@ void OSystem_Android::pushEvent(const Common::Event &event1, const Common::Event _event_queue_lock->unlock(); } +void OSystem_Android::setupTouchMode(int oldValue, int newValue) { + _touch_mode = newValue; + + if (newValue == TOUCH_MODE_TOUCHPAD) { + // Make sure we have a proper touch point if we switch to touchpad mode with finger down + _touch_pt_down = dynamic_cast(_graphicsManager)->getMousePosition(); + _touch_pt_scroll.x = -1; + _touch_pt_scroll.y = -1; + } +} + #endif diff --git a/backends/platform/android/jni-android.cpp b/backends/platform/android/jni-android.cpp index 2140e881b68..de6472deda5 100644 --- a/backends/platform/android/jni-android.cpp +++ b/backends/platform/android/jni-android.cpp @@ -88,8 +88,8 @@ jmethodID JNI::_MID_setWindowCaption = 0; jmethodID JNI::_MID_showVirtualKeyboard = 0; jmethodID JNI::_MID_showKeyboardControl = 0; jmethodID JNI::_MID_getBitmapResource = 0; -jmethodID JNI::_MID_setTouch3DMode = 0; -jmethodID JNI::_MID_getTouch3DMode = 0; +jmethodID JNI::_MID_setTouchMode = 0; +jmethodID JNI::_MID_getTouchMode = 0; jmethodID JNI::_MID_showSAFRevokePermsControl = 0; jmethodID JNI::_MID_getSysArchives = 0; jmethodID JNI::_MID_getAllStorageLocations = 0; @@ -126,6 +126,8 @@ const JNINativeMethod JNI::_natives[] = { (void *)JNI::pushEvent }, { "updateTouch", "(IIII)V", (void *)JNI::updateTouch }, + { "setupTouchMode", "(II)V", + (void *)JNI::setupTouchMode }, { "setPause", "(Z)V", (void *)JNI::setPause }, { "getNativeVersionInfo", "()Ljava/lang/String;", @@ -455,10 +457,10 @@ Graphics::Surface *JNI::getBitmapResource(BitmapResources resource) { return ret; } -void JNI::setTouch3DMode(bool touch3DMode) { +void JNI::setTouchMode(int touchMode) { JNIEnv *env = JNI::getEnv(); - env->CallVoidMethod(_jobj, _MID_setTouch3DMode, touch3DMode); + env->CallVoidMethod(_jobj, _MID_setTouchMode, touchMode); if (env->ExceptionCheck()) { LOGE("Error trying to set touch controls mode"); @@ -468,10 +470,10 @@ void JNI::setTouch3DMode(bool touch3DMode) { } } -bool JNI::getTouch3DMode() { +int JNI::getTouchMode() { JNIEnv *env = JNI::getEnv(); - bool enabled = env->CallBooleanMethod(_jobj, _MID_getTouch3DMode); + int mode = env->CallIntMethod(_jobj, _MID_getTouchMode); if (env->ExceptionCheck()) { LOGE("Error trying to get touch controls status"); @@ -480,7 +482,7 @@ bool JNI::getTouch3DMode() { env->ExceptionClear(); } - return enabled; + return mode; } void JNI::showSAFRevokePermsControl(bool enable) { @@ -667,8 +669,8 @@ void JNI::create(JNIEnv *env, jobject self, jobject asset_manager, FIND_METHOD(, showVirtualKeyboard, "(Z)V"); FIND_METHOD(, showKeyboardControl, "(Z)V"); FIND_METHOD(, getBitmapResource, "(I)Landroid/graphics/Bitmap;"); - FIND_METHOD(, setTouch3DMode, "(Z)V"); - FIND_METHOD(, getTouch3DMode, "()Z"); + FIND_METHOD(, setTouchMode, "(I)V"); + FIND_METHOD(, getTouchMode, "()I"); FIND_METHOD(, getSysArchives, "()[Ljava/lang/String;"); FIND_METHOD(, getAllStorageLocations, "()[Ljava/lang/String;"); FIND_METHOD(, initSurface, "()Ljavax/microedition/khronos/egl/EGLSurface;"); @@ -822,6 +824,13 @@ void JNI::updateTouch(JNIEnv *env, jobject self, int action, int ptr, int x, int _system->getTouchControls().update((TouchControls::Action) action, ptr, x, y); } +void JNI::setupTouchMode(JNIEnv *env, jobject self, jint oldValue, jint newValue) { + if (!_system) + return; + + _system->setupTouchMode(oldValue, newValue); +} + void JNI::setPause(JNIEnv *env, jobject self, jboolean value) { if (!_system) return; diff --git a/backends/platform/android/jni-android.h b/backends/platform/android/jni-android.h index d3afb71f2e7..7b69e2a4211 100644 --- a/backends/platform/android/jni-android.h +++ b/backends/platform/android/jni-android.h @@ -77,8 +77,8 @@ public: static void showVirtualKeyboard(bool enable); static void showKeyboardControl(bool enable); static Graphics::Surface *getBitmapResource(BitmapResources resource); - static void setTouch3DMode(bool touch3DMode); - static bool getTouch3DMode(); + static void setTouchMode(int touchMode); + static int getTouchMode(); static void showSAFRevokePermsControl(bool enable); static void addSysArchivesToSearchSet(Common::SearchSet &s, int priority); @@ -126,8 +126,8 @@ private: static jmethodID _MID_showVirtualKeyboard; static jmethodID _MID_showKeyboardControl; static jmethodID _MID_getBitmapResource; - static jmethodID _MID_setTouch3DMode; - static jmethodID _MID_getTouch3DMode; + static jmethodID _MID_setTouchMode; + static jmethodID _MID_getTouchMode; static jmethodID _MID_showSAFRevokePermsControl; static jmethodID _MID_getSysArchives; static jmethodID _MID_getAllStorageLocations; @@ -164,6 +164,7 @@ private: static void pushEvent(JNIEnv *env, jobject self, int type, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6); static void updateTouch(JNIEnv *env, jobject self, int action, int ptr, int x, int y); + static void setupTouchMode(JNIEnv *env, jobject self, jint oldValue, jint newValue); static void setPause(JNIEnv *env, jobject self, jboolean value); static jstring getNativeVersionInfo(JNIEnv *env, jobject self); diff --git a/backends/platform/android/options.cpp b/backends/platform/android/options.cpp index aff4b02dec9..8edb0e6e094 100644 --- a/backends/platform/android/options.cpp +++ b/backends/platform/android/options.cpp @@ -39,8 +39,10 @@ #include "backends/platform/android/android.h" #include "backends/platform/android/jni-android.h" +#include "gui/gui-manager.h" #include "gui/ThemeEval.h" #include "gui/widget.h" +#include "gui/widgets/popup.h" #include "common/translation.h" @@ -60,17 +62,67 @@ private: void defineLayout(GUI::ThemeEval &layouts, const Common::String &layoutName, const Common::String &overlayedLayout) const override; GUI::CheckboxWidget *_onscreenCheckbox; - GUI::CheckboxWidget *_touchpadCheckbox; + GUI::StaticTextWidget *_preferredTouchModeDesc; + GUI::StaticTextWidget *_preferredTMMenusDesc; + GUI::PopUpWidget *_preferredTMMenusPopUp; + GUI::StaticTextWidget *_preferredTM2DGamesDesc; + GUI::PopUpWidget *_preferredTM2DGamesPopUp; + GUI::StaticTextWidget *_preferredTM3DGamesDesc; + GUI::PopUpWidget *_preferredTM3DGamesPopUp; GUI::CheckboxWidget *_onscreenSAFRevokeCheckbox; bool _enabled; + + + uint32 loadTouchMode(const Common::String &setting, bool acceptDefault, uint32 defaultValue); + void saveTouchMode(const Common::String &setting, uint32 touchMode); +}; + +enum { + kTouchModeDefault = -1, + kTouchModeTouchpad = 0, + kTouchModeMouse, + kTouchModeGamepad, }; AndroidOptionsWidget::AndroidOptionsWidget(GuiObject *boss, const Common::String &name, const Common::String &domain) : OptionsContainerWidget(boss, name, "AndroidOptionsDialog", false, domain), _enabled(true) { + + const bool inAppDomain = domain.equalsIgnoreCase(Common::ConfigManager::kApplicationDomain);; + _onscreenCheckbox = new GUI::CheckboxWidget(widgetsBoss(), "AndroidOptionsDialog.OnScreenControl", _("Show On-screen control")); - _touchpadCheckbox = new GUI::CheckboxWidget(widgetsBoss(), "AndroidOptionsDialog.TouchpadMode", _("Touchpad mouse mode")); - if (domain.equalsIgnoreCase(Common::ConfigManager::kApplicationDomain)) { + _preferredTouchModeDesc = new GUI::StaticTextWidget(widgetsBoss(), "AndroidOptionsDialog.PreferredTouchModeText", _("Choose the preferred touch mode:")); + if (inAppDomain) { + _preferredTMMenusDesc = new GUI::StaticTextWidget(widgetsBoss(), "AndroidOptionsDialog.TMMenusText", _("In menus")); + _preferredTMMenusPopUp = new GUI::PopUpWidget(widgetsBoss(), "AndroidOptionsDialog.TMMenus"); + _preferredTMMenusPopUp->appendEntry(_("Touchpad emulation"), kTouchModeTouchpad); + _preferredTMMenusPopUp->appendEntry(_("Direct mouse"), kTouchModeMouse); // TODO: Find a better name + _preferredTMMenusPopUp->appendEntry(_("Gamepad emulation"), kTouchModeGamepad); + } else { + _preferredTMMenusDesc = nullptr; + _preferredTMMenusPopUp = nullptr; + } + + _preferredTM2DGamesDesc = new GUI::StaticTextWidget(widgetsBoss(), "AndroidOptionsDialog.TM2DGamesText", _("In 2D games")); + _preferredTM2DGamesPopUp = new GUI::PopUpWidget(widgetsBoss(), "AndroidOptionsDialog.TM2DGames"); + _preferredTM3DGamesDesc = new GUI::StaticTextWidget(widgetsBoss(), "AndroidOptionsDialog.TM3DGamesText", _("In 3D games")); + _preferredTM3DGamesPopUp = new GUI::PopUpWidget(widgetsBoss(), "AndroidOptionsDialog.TM3DGames"); + + if (!inAppDomain) { + _preferredTM2DGamesPopUp->appendEntry(_(""), kTouchModeDefault); + _preferredTM3DGamesPopUp->appendEntry(_(""), kTouchModeDefault); + } + + _preferredTM2DGamesPopUp->appendEntry(_("Touchpad emulation"), kTouchModeTouchpad); + _preferredTM3DGamesPopUp->appendEntry(_("Touchpad emulation"), kTouchModeTouchpad); + + _preferredTM2DGamesPopUp->appendEntry(_("Direct mouse"), kTouchModeMouse); // TODO: Find a better name + _preferredTM3DGamesPopUp->appendEntry(_("Direct mouse"), kTouchModeMouse); + + _preferredTM2DGamesPopUp->appendEntry(_("Gamepad emulation"), kTouchModeGamepad); + _preferredTM3DGamesPopUp->appendEntry(_("Gamepad emulation"), kTouchModeGamepad); + + if (inAppDomain) { // Only show this checkbox in Options (via Options... in the launcher), and not at game domain level (via Edit Game...) // I18N: Show a button to revoke Storage Access Framework permissions for Android _onscreenSAFRevokeCheckbox = new GUI::CheckboxWidget(widgetsBoss(), "AndroidOptionsDialog.SAFRevokePermsControl", _("Show SAF revoke permissions overlay button")); @@ -81,37 +133,115 @@ AndroidOptionsWidget::~AndroidOptionsWidget() { } void AndroidOptionsWidget::defineLayout(GUI::ThemeEval &layouts, const Common::String &layoutName, const Common::String &overlayedLayout) const { + const bool inAppDomain = _domain.equalsIgnoreCase(Common::ConfigManager::kApplicationDomain);; + layouts.addDialog(layoutName, overlayedLayout) .addLayout(GUI::ThemeLayout::kLayoutVertical) .addPadding(0, 0, 0, 0) .addWidget("OnScreenControl", "Checkbox") - .addWidget("TouchpadMode", "Checkbox"); - if (_domain.equalsIgnoreCase(Common::ConfigManager::kApplicationDomain)) { + .addWidget("PreferredTouchModeText", "", -1, layouts.getVar("Globals.Line.Height")); + + if (inAppDomain) { + layouts.addLayout(GUI::ThemeLayout::kLayoutHorizontal) + .addPadding(0, 0, 0, 0) + .addWidget("TMMenusText", "OptionsLabel") + .addWidget("TMMenus", "PopUp") + .closeLayout(); + } + layouts.addLayout(GUI::ThemeLayout::kLayoutHorizontal) + .addPadding(0, 0, 0, 0) + .addWidget("TM2DGamesText", "OptionsLabel") + .addWidget("TM2DGames", "PopUp") + .closeLayout() + .addLayout(GUI::ThemeLayout::kLayoutHorizontal) + .addPadding(0, 0, 0, 0) + .addWidget("TM3DGamesText", "OptionsLabel") + .addWidget("TM3DGames", "PopUp") + .closeLayout(); + if (inAppDomain) { layouts.addWidget("SAFRevokePermsControl", "Checkbox"); } layouts.closeLayout() .closeDialog(); } +uint32 AndroidOptionsWidget::loadTouchMode(const Common::String &setting, bool acceptDefault, uint32 defaultValue) { + if (!acceptDefault || ConfMan.hasKey(setting, _domain)) { + Common::String preferredTouchMode = ConfMan.get(setting, _domain); + if (preferredTouchMode == "mouse") { + return kTouchModeMouse; + } else if (preferredTouchMode == "gamepad") { + return kTouchModeGamepad; + } else if (preferredTouchMode == "touchpad") { + return kTouchModeTouchpad; + } else { + return defaultValue; + } + } else { + return kTouchModeDefault; + } +} + void AndroidOptionsWidget::load() { + const bool inAppDomain = _domain.equalsIgnoreCase(Common::ConfigManager::kApplicationDomain); + _onscreenCheckbox->setState(ConfMan.getBool("onscreen_control", _domain)); - _touchpadCheckbox->setState(ConfMan.getBool("touchpad_mouse_mode", _domain)); - if (_domain.equalsIgnoreCase(Common::ConfigManager::kApplicationDomain)) { + + // When in application domain, we don't have default entry so we must have a value + if (inAppDomain) { + _preferredTMMenusPopUp->setSelectedTag(loadTouchMode("touch_mode_menus", !inAppDomain, kTouchModeMouse)); + } + _preferredTM2DGamesPopUp->setSelectedTag(loadTouchMode("touch_mode_2d_games", !inAppDomain, kTouchModeTouchpad)); + _preferredTM3DGamesPopUp->setSelectedTag(loadTouchMode("touch_mode_3d_games", !inAppDomain, kTouchModeGamepad)); + + if (inAppDomain) { _onscreenSAFRevokeCheckbox->setState(ConfMan.getBool("onscreen_saf_revoke_btn", _domain)); } } +void AndroidOptionsWidget::saveTouchMode(const Common::String &setting, uint32 touchMode) { + switch (touchMode) { + case kTouchModeTouchpad: + ConfMan.set(setting, "touchpad", _domain); + break; + case kTouchModeMouse: + ConfMan.set(setting, "mouse", _domain); + break; + case kTouchModeGamepad: + ConfMan.set(setting, "gamepad", _domain); + break; + default: + // default + ConfMan.removeKey(setting, _domain); + break; + } +} + bool AndroidOptionsWidget::save() { + const bool inAppDomain = _domain.equalsIgnoreCase(Common::ConfigManager::kApplicationDomain); + if (_enabled) { ConfMan.setBool("onscreen_control", _onscreenCheckbox->getState(), _domain); - ConfMan.setBool("touchpad_mouse_mode", _touchpadCheckbox->getState(), _domain); - if (_domain.equalsIgnoreCase(Common::ConfigManager::kApplicationDomain)) { + + if (inAppDomain) { + saveTouchMode("touch_mode_menus", _preferredTMMenusPopUp->getSelectedTag()); + } + saveTouchMode("touch_mode_2d_games", _preferredTM2DGamesPopUp->getSelectedTag()); + saveTouchMode("touch_mode_3d_games", _preferredTM3DGamesPopUp->getSelectedTag()); + + if (inAppDomain) { ConfMan.setBool("onscreen_saf_revoke_btn", _onscreenSAFRevokeCheckbox->getState(), _domain); } } else { ConfMan.removeKey("onscreen_control", _domain); - ConfMan.removeKey("touchpad_mouse_mode", _domain); - if (_domain.equalsIgnoreCase(Common::ConfigManager::kApplicationDomain)) { + + if (inAppDomain) { + ConfMan.removeKey("touch_mode_menus", _domain); + } + ConfMan.removeKey("touch_mode_2d_games", _domain); + ConfMan.removeKey("touch_mode_3d_games", _domain); + + if (inAppDomain) { ConfMan.removeKey("onscreen_saf_revoke_btn", _domain); } } @@ -121,16 +251,29 @@ bool AndroidOptionsWidget::save() { bool AndroidOptionsWidget::hasKeys() { return ConfMan.hasKey("onscreen_control", _domain) || - ConfMan.hasKey("touchpad_mouse_mode", _domain) || + (_domain.equalsIgnoreCase(Common::ConfigManager::kApplicationDomain) && ConfMan.hasKey("touch_mode_menus", _domain)) || + ConfMan.hasKey("touch_mode_2d_games", _domain) || + ConfMan.hasKey("touch_mode_3d_games", _domain) || (_domain.equalsIgnoreCase(Common::ConfigManager::kApplicationDomain) && ConfMan.hasKey("onscreen_saf_revoke_btn", _domain)); } void AndroidOptionsWidget::setEnabled(bool e) { + const bool inAppDomain = _domain.equalsIgnoreCase(Common::ConfigManager::kApplicationDomain); + _enabled = e; _onscreenCheckbox->setEnabled(e); - _touchpadCheckbox->setEnabled(e); - if (_domain.equalsIgnoreCase(Common::ConfigManager::kApplicationDomain)) { + + if (inAppDomain) { + _preferredTMMenusDesc->setEnabled(e); + _preferredTMMenusPopUp->setEnabled(e); + } + _preferredTM2DGamesDesc->setEnabled(e); + _preferredTM2DGamesPopUp->setEnabled(e); + _preferredTM3DGamesDesc->setEnabled(e); + _preferredTM3DGamesPopUp->setEnabled(e); + + if (inAppDomain) { _onscreenSAFRevokeCheckbox->setEnabled(e); } } @@ -142,12 +285,40 @@ GUI::OptionsContainerWidget *OSystem_Android::buildBackendOptionsWidget(GUI::Gui void OSystem_Android::registerDefaultSettings(const Common::String &target) const { ConfMan.registerDefault("onscreen_control", true); - ConfMan.registerDefault("touchpad_mouse_mode", true); + ConfMan.registerDefault("touch_mode_menus", "mouse"); + ConfMan.registerDefault("touch_mode_2d_games", "touchpad"); + ConfMan.registerDefault("touch_mode_3d_games", "gamepad"); ConfMan.registerDefault("onscreen_saf_revoke_btn", false); } +void OSystem_Android::applyTouchSettings(bool _3dMode, bool overlayShown) { + Common::String setting; + int defaultMode; + + if (overlayShown) { + setting = "touch_mode_menus"; + defaultMode = TOUCH_MODE_MOUSE; + } else if (_3dMode) { + setting = "touch_mode_3d_games"; + defaultMode = TOUCH_MODE_GAMEPAD; + } else { + setting = "touch_mode_2d_games"; + defaultMode = TOUCH_MODE_TOUCHPAD; + } + + Common::String preferredTouchMode = ConfMan.get(setting); + if (preferredTouchMode == "mouse") { + JNI::setTouchMode(TOUCH_MODE_MOUSE); + } else if (preferredTouchMode == "gamepad") { + JNI::setTouchMode(TOUCH_MODE_GAMEPAD); + } else if (preferredTouchMode == "touchpad") { + JNI::setTouchMode(TOUCH_MODE_TOUCHPAD); + } else { + JNI::setTouchMode(defaultMode); + } +} + void OSystem_Android::applyBackendSettings() { JNI::showKeyboardControl(ConfMan.getBool("onscreen_control")); JNI::showSAFRevokePermsControl(ConfMan.getBool("onscreen_saf_revoke_btn")); - _touchpad_mode = ConfMan.getBool("touchpad_mouse_mode"); } diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVM.java b/backends/platform/android/org/scummvm/scummvm/ScummVM.java index 1ff62d65f42..83b30c7f7cd 100644 --- a/backends/platform/android/org/scummvm/scummvm/ScummVM.java +++ b/backends/platform/android/org/scummvm/scummvm/ScummVM.java @@ -58,6 +58,7 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { final public native void pushEvent(int type, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6); // Update the 3D touch controls + final public native void setupTouchMode(int oldValue, int newValue); final public native void updateTouch(int action, int ptr, int x, int y); final public native String getNativeVersionInfo(); @@ -74,8 +75,8 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { abstract protected void showVirtualKeyboard(boolean enable); abstract protected void showKeyboardControl(boolean enable); abstract protected Bitmap getBitmapResource(int resource); - abstract protected void setTouch3DMode(boolean touch3DMode); - abstract protected boolean getTouch3DMode(); + abstract protected void setTouchMode(int touchMode); + abstract protected int getTouchMode(); abstract protected void showSAFRevokePermsControl(boolean enable); abstract protected String[] getSysArchives(); abstract protected String[] getAllStorageLocations(); diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java b/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java index 18b537643ee..9e21ba67058 100644 --- a/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java +++ b/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java @@ -118,7 +118,7 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis FrameLayout _videoLayout = null; private EditableSurfaceView _main_surface = null; - private ImageView _toggleGamepadBtnIcon = null; + private ImageView _toggleTouchModeBtnIcon = null; private ImageView _toggleKeyboardBtnIcon = null; private ImageView _openMenuBtnIcon = null; private ImageView _revokeSafPermissionsBtnIcon = null; @@ -570,14 +570,33 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis // --------------------------------------------------------------------------------------------------------------------------- // - public final View.OnClickListener gamepadBtnOnClickListener = new View.OnClickListener() { + protected void setupTouchModeBtn(final int touchMode) { + int resId; + + switch(touchMode) { + case ScummVMEventsBase.TOUCH_MODE_TOUCHPAD: + resId = R.drawable.ic_action_touchpad; + break; + case ScummVMEventsBase.TOUCH_MODE_MOUSE: + resId = R.drawable.ic_action_mouse; + break; + case ScummVMEventsBase.TOUCH_MODE_GAMEPAD: + resId = R.drawable.ic_action_gamepad; + break; + default: + throw new IllegalArgumentException("Invalid touchMode"); + } + + _toggleTouchModeBtnIcon.setImageResource(resId); + } + + public final View.OnClickListener touchModeBtnOnClickListener = new View.OnClickListener() { @Override public void onClick(View v) { runOnUiThread(new Runnable() { public void run() { - boolean touch3DMode = !_events.getTouch3DMode(); - _events.setTouch3DMode(touch3DMode); - _toggleGamepadBtnIcon.setImageResource(touch3DMode ? R.drawable.ic_action_mouse : R.drawable.ic_action_gamepad); + int newTouchMode = _events.nextTouchMode(); + setupTouchModeBtn(newTouchMode); } }); } @@ -739,21 +758,21 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis } @Override - protected void setTouch3DMode(final boolean touch3DMode) { - if (_events.getTouch3DMode() == touch3DMode) { + protected void setTouchMode(final int touchMode) { + if (_events.getTouchMode() == touchMode) { return; } runOnUiThread(new Runnable() { public void run() { - _events.setTouch3DMode(touch3DMode); - _toggleGamepadBtnIcon.setImageResource(touch3DMode ? R.drawable.ic_action_mouse : R.drawable.ic_action_gamepad); + _events.setTouchMode(touchMode); + setupTouchModeBtn(touchMode); } }); } @Override - protected boolean getTouch3DMode() { - return _events.getTouch3DMode(); + protected int getTouchMode() { + return _events.getTouchMode(); } @Override @@ -1009,10 +1028,9 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis _videoLayout.addView(buttonLayout, buttonLayoutParams); _videoLayout.bringChildToFront(buttonLayout); - _toggleGamepadBtnIcon = new ImageView(this); - _toggleGamepadBtnIcon.setImageResource(R.drawable.ic_action_gamepad); - buttonLayout.addView(_toggleGamepadBtnIcon, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT)); - buttonLayout.bringChildToFront(_toggleGamepadBtnIcon); + _toggleTouchModeBtnIcon = new ImageView(this); + buttonLayout.addView(_toggleTouchModeBtnIcon, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT)); + buttonLayout.bringChildToFront(_toggleTouchModeBtnIcon); _toggleKeyboardBtnIcon = new ImageView(this); _toggleKeyboardBtnIcon.setImageResource(R.drawable.ic_action_keyboard); @@ -1121,9 +1139,11 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis _events = new ScummVMEventsBase(this, _scummvm, _mouseHelper); } + setupTouchModeBtn(_events.getTouchMode()); + // On screen button listener //findViewById(R.id.show_keyboard).setOnClickListener(keyboardBtnOnClickListener); - _toggleGamepadBtnIcon.setOnClickListener(gamepadBtnOnClickListener); + _toggleTouchModeBtnIcon.setOnClickListener(touchModeBtnOnClickListener); _toggleKeyboardBtnIcon.setOnClickListener(keyboardBtnOnClickListener); _openMenuBtnIcon.setOnClickListener(menuBtnOnClickListener); _revokeSafPermissionsBtnIcon.setOnClickListener(revokeSafPermissionsBtnOnClickListener); @@ -1391,8 +1411,8 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis _openMenuBtnIcon.setVisibility(show ? View.VISIBLE : View.GONE); } - if (_toggleGamepadBtnIcon != null ) { - _toggleGamepadBtnIcon.setVisibility(show ? View.VISIBLE : View.GONE); + if (_toggleTouchModeBtnIcon != null ) { + _toggleTouchModeBtnIcon.setVisibility(show ? View.VISIBLE : View.GONE); } } diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVMEventsBase.java b/backends/platform/android/org/scummvm/scummvm/ScummVMEventsBase.java index d1dba19c3af..ffbe79496a1 100644 --- a/backends/platform/android/org/scummvm/scummvm/ScummVMEventsBase.java +++ b/backends/platform/android/org/scummvm/scummvm/ScummVMEventsBase.java @@ -55,6 +55,11 @@ public class ScummVMEventsBase implements public static final int JACTION_UP = 2; public static final int JACTION_CANCEL = 3; + public static final int TOUCH_MODE_TOUCHPAD = 0; + public static final int TOUCH_MODE_MOUSE = 1; + public static final int TOUCH_MODE_GAMEPAD = 2; + public static final int TOUCH_MODE_MAX = 3; + final protected Context _context; final protected ScummVM _scummvm; final protected GestureDetector _gd; @@ -62,7 +67,7 @@ public class ScummVMEventsBase implements final protected MouseHelper _mouseHelper; final protected MultitouchHelper _multitouchHelper; - protected boolean _touch3DMode; + protected int _touchMode; // Custom handler code (to avoid mem leaks, see warning "This Handler Class Should Be Static Or Leaks Might Occur”) based on: // https://stackoverflow.com/a/27826094 @@ -142,15 +147,36 @@ public class ScummVMEventsBase implements } } - final public boolean getTouch3DMode() { - return _touch3DMode; + final public int getTouchMode() { + return _touchMode; } - final public void setTouch3DMode(boolean touch3DMode) { - if (_touch3DMode != touch3DMode && !touch3DMode) { + final public void setTouchMode(int touchMode) { + assert (touchMode >= 0) && (touchMode < TOUCH_MODE_MAX); + + if (_touchMode == touchMode) { + return; + } + + if (_touchMode == TOUCH_MODE_GAMEPAD) { + // We were in gamepad mode and we leave it _scummvm.updateTouch(JACTION_CANCEL, 0, 0, 0); } - _touch3DMode = touch3DMode; + int oldTouchMode = _touchMode; + _touchMode = touchMode; + _scummvm.setupTouchMode(oldTouchMode, _touchMode); + } + + final public int nextTouchMode() { + if (_touchMode == TOUCH_MODE_GAMEPAD) { + // We leave gamepad mode + _scummvm.updateTouch(JACTION_CANCEL, 0, 0, 0); + } + int oldTouchMode = _touchMode; + _touchMode = (_touchMode + 1) % TOUCH_MODE_MAX; + _scummvm.setupTouchMode(oldTouchMode, _touchMode); + + return _touchMode; } public void clearEventHandler() { @@ -477,7 +503,7 @@ public class ScummVMEventsBase implements } } - if (_touch3DMode) { + if (_touchMode == TOUCH_MODE_GAMEPAD) { switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_POINTER_DOWN: { @@ -528,7 +554,7 @@ public class ScummVMEventsBase implements @Override final public boolean onDown(MotionEvent e) { // Log.d(ScummVM.LOG_TAG, "SCUMMV-EVENTS-BASE - onDOWN MotionEvent"); - if (!_touch3DMode) { + if (_touchMode != TOUCH_MODE_GAMEPAD) { _scummvm.pushEvent(JE_DOWN, (int)e.getX(), (int)e.getY(), 0, 0, 0, 0); } return true; @@ -553,7 +579,7 @@ public class ScummVMEventsBase implements final public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { // Log.d(ScummVM.LOG_TAG, "onScroll"); - if (!_touch3DMode) { + if (_touchMode != TOUCH_MODE_GAMEPAD) { // typical use: // - move mouse cursor around (most traditional point and click games) // - mouse look (eg. Myst 3) @@ -570,7 +596,7 @@ public class ScummVMEventsBase implements @Override final public boolean onSingleTapUp(MotionEvent e) { // Log.d(ScummVM.LOG_TAG, "onSingleTapUp"); - if (!_touch3DMode) { + if (_touchMode != TOUCH_MODE_GAMEPAD) { _scummvm.pushEvent(JE_TAP, (int)e.getX(), (int)e.getY(), (int)(e.getEventTime() - e.getDownTime()), 0, 0, 0); } @@ -598,7 +624,7 @@ public class ScummVMEventsBase implements // } else { // Log.d(ScummVM.LOG_TAG, "onDoubleTapEvent UNKNOWN!!!!"); // } - if (!_touch3DMode) { + if (_touchMode != TOUCH_MODE_GAMEPAD) { _scummvm.pushEvent(JE_DOUBLE_TAP, (int)e.getX(), (int)e.getY(), e.getAction(), 0, 0, 0); } return true; diff --git a/dists/android/res/drawable/ic_action_touchpad.xml b/dists/android/res/drawable/ic_action_touchpad.xml new file mode 100644 index 00000000000..3959ccb6f8e --- /dev/null +++ b/dists/android/res/drawable/ic_action_touchpad.xml @@ -0,0 +1,17 @@ + + + +