From 823746314afea6f757b5a66db2904d17ae074616 Mon Sep 17 00:00:00 2001 From: Kleidis <167202775+kleidis@users.noreply.github.com> Date: Wed, 13 Nov 2024 19:15:45 +0100 Subject: [PATCH] android: Add turbo mode hotkey --- .../java/org/citra/citra_emu/NativeLibrary.kt | 11 ++++ .../citra_emu/activities/EmulationActivity.kt | 4 ++ .../citra_emu/features/hotkeys/Hotkey.kt | 1 + .../features/hotkeys/HotkeyFunctions.kt | 57 +++++++++++++++++++ .../features/hotkeys/HotkeyUtility.kt | 1 + .../features/settings/model/IntSetting.kt | 3 + .../features/settings/model/Settings.kt | 5 +- .../model/view/InputBindingSetting.kt | 1 + .../settings/ui/SettingsFragmentPresenter.kt | 12 ++++ src/android/app/src/main/jni/config.cpp | 4 +- src/android/app/src/main/jni/native.cpp | 15 +++++ .../app/src/main/res/values/strings.xml | 5 +- .../configuration/configure_hotkeys.cpp | 5 +- 13 files changed, 117 insertions(+), 7 deletions(-) create mode 100644 src/android/app/src/main/java/org/citra/citra_emu/features/hotkeys/HotkeyFunctions.kt diff --git a/src/android/app/src/main/java/org/citra/citra_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/citra/citra_emu/NativeLibrary.kt index 40dbc94c9..786b64aa6 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/NativeLibrary.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/NativeLibrary.kt @@ -180,6 +180,17 @@ object NativeLibrary { external fun downloadTitleFromNus(title: Long): InstallStatus + + /** + * Turbo speed. + */ + external fun toggleTurboSpeed(enabled: Boolean) + + external fun getTurboSpeedSlider(): Int + + external fun setTurboSpeedSlider(value: Int) + + private var coreErrorAlertResult = false private val coreErrorAlertLock = Object() diff --git a/src/android/app/src/main/java/org/citra/citra_emu/activities/EmulationActivity.kt b/src/android/app/src/main/java/org/citra/citra_emu/activities/EmulationActivity.kt index 8d9bf24e3..c7b6efa0f 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/activities/EmulationActivity.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/activities/EmulationActivity.kt @@ -33,6 +33,7 @@ import org.citra.citra_emu.contracts.OpenFileResultContract import org.citra.citra_emu.databinding.ActivityEmulationBinding import org.citra.citra_emu.display.ScreenAdjustmentUtil import org.citra.citra_emu.features.hotkeys.HotkeyUtility +import org.citra.citra_emu.features.hotkeys.HotkeyFunctions import org.citra.citra_emu.features.settings.model.BooleanSetting import org.citra.citra_emu.features.settings.model.IntSetting import org.citra.citra_emu.features.settings.model.SettingsViewModel @@ -55,6 +56,7 @@ class EmulationActivity : AppCompatActivity() { private lateinit var binding: ActivityEmulationBinding private lateinit var screenAdjustmentUtil: ScreenAdjustmentUtil + private lateinit var hotkeyFunctions: HotkeyFunctions private lateinit var hotkeyUtility: HotkeyUtility private val emulationFragment: EmulationFragment @@ -76,6 +78,7 @@ class EmulationActivity : AppCompatActivity() { binding = ActivityEmulationBinding.inflate(layoutInflater) screenAdjustmentUtil = ScreenAdjustmentUtil(this, windowManager, settingsViewModel.settings) hotkeyUtility = HotkeyUtility(screenAdjustmentUtil, this) + hotkeyUtility = HotkeyUtility(screenAdjustmentUtil, hotkeyFunctions) setContentView(binding.root) val navHostFragment = @@ -138,6 +141,7 @@ class EmulationActivity : AppCompatActivity() { } override fun onDestroy() { + hotkeyFunctions.resetTurboSpeed() EmulationLifecycleUtil.clear() isEmulationRunning = false instance = null diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/hotkeys/Hotkey.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/hotkeys/Hotkey.kt index db99abf67..1fc905cb3 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/hotkeys/Hotkey.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/hotkeys/Hotkey.kt @@ -11,4 +11,5 @@ enum class Hotkey(val button: Int) { PAUSE_OR_RESUME(10004), QUICKSAVE(10005), QUICKLOAD(10006); + TURBO_SPEED(10007); } diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/hotkeys/HotkeyFunctions.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/hotkeys/HotkeyFunctions.kt new file mode 100644 index 000000000..251f86db5 --- /dev/null +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/hotkeys/HotkeyFunctions.kt @@ -0,0 +1,57 @@ +// Copyright Lime3DS Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +package org.citra.citra_emu.features.hotkeys + +import android.widget.Toast +import org.citra.citra_emu.CitraApplication +import org.citra.citra_emu.NativeLibrary +import org.citra.citra_emu.features.settings.model.IntSetting +import org.citra.citra_emu.features.settings.model.Settings +import org.citra.citra_emu.features.settings.utils.SettingsFile + + +class HotkeyFunctions ( + private val settings: Settings +) { + private var normalSpeed = IntSetting.FRAME_LIMIT.int + var isTurboSpeedEnabled = false + + // Turbo Speed + fun setTurboSpeed(enabled: Boolean) { + isTurboSpeedEnabled = enabled + toggleTurboSpeed() + } + + fun toggleTurboSpeed() { + if (isTurboSpeedEnabled) { + normalSpeed = IntSetting.FRAME_LIMIT.int + NativeLibrary.toggleTurboSpeed(true) + NativeLibrary.setTurboSpeedSlider(IntSetting.TURBO_SPEED.int) + IntSetting.FRAME_LIMIT.int = IntSetting.TURBO_SPEED.int + } else { + NativeLibrary.toggleTurboSpeed(false) + NativeLibrary.setTurboSpeedSlider(normalSpeed) + IntSetting.FRAME_LIMIT.int = normalSpeed + } + + settings.saveSetting(IntSetting.FRAME_LIMIT, SettingsFile.FILE_NAME_CONFIG) + NativeLibrary.reloadSettings() + + val context = CitraApplication.appContext + Toast.makeText(context + , "Changed Emulation Speed to: ${IntSetting.FRAME_LIMIT.int}%", Toast.LENGTH_SHORT).show() + } + + fun resetTurboSpeed() { + if (isTurboSpeedEnabled) { + isTurboSpeedEnabled = false + NativeLibrary.toggleTurboSpeed(false) + IntSetting.FRAME_LIMIT.int = normalSpeed + + settings.saveSetting(IntSetting.FRAME_LIMIT, SettingsFile.FILE_NAME_CONFIG) + NativeLibrary.reloadSettings() + } + } +} \ No newline at end of file diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/hotkeys/HotkeyUtility.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/hotkeys/HotkeyUtility.kt index 25f6a493b..42b180ec5 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/hotkeys/HotkeyUtility.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/hotkeys/HotkeyUtility.kt @@ -22,6 +22,7 @@ class HotkeyUtility(private val screenAdjustmentUtil: ScreenAdjustmentUtil, priv Hotkey.CYCLE_LAYOUT.button -> screenAdjustmentUtil.cycleLayouts() Hotkey.CLOSE_GAME.button -> EmulationLifecycleUtil.closeGame() Hotkey.PAUSE_OR_RESUME.button -> EmulationLifecycleUtil.pauseOrResume() + Hotkey.TURBO_SPEED.button -> hotkeyFunctions.setTurboSpeed(!hotkeyFunctions.isTurboSpeedEnabled) Hotkey.QUICKSAVE.button -> { NativeLibrary.saveState(NativeLibrary.QUICKSAVE_SLOT) Toast.makeText(context, diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/IntSetting.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/IntSetting.kt index 0f1ca8d43..a077c8c05 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/IntSetting.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/IntSetting.kt @@ -65,6 +65,8 @@ enum class IntSetting( USE_ARTIC_BASE_CONTROLLER("use_artic_base_controller", Settings.SECTION_CONTROLS, 0), ORIENTATION_OPTION("screen_orientation", Settings.SECTION_LAYOUT, 2), DISABLE_RIGHT_EYE_RENDER("disable_right_eye_render", Settings.SECTION_RENDERER, 0); + TURBO_SPEED("turbo_speed", Settings.SECTION_CORE, 200); + override var int: Int = defaultValue override val valueAsString: String @@ -94,6 +96,7 @@ enum class IntSetting( AUDIO_INPUT_TYPE, USE_ARTIC_BASE_CONTROLLER, SHADERS_ACCURATE_MUL, + FRAME_LIMIT ) fun from(key: String): IntSetting? = IntSetting.values().firstOrNull { it.key == key } diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/Settings.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/Settings.kt index 5ea358989..f11df55f9 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/Settings.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/Settings.kt @@ -139,6 +139,7 @@ class Settings { const val HOTKEY_PAUSE_OR_RESUME = "hotkey_pause_or_resume_game" const val HOTKEY_QUICKSAVE = "hotkey_quickload" const val HOTKEY_QUICKlOAD = "hotkey_quickpause" + const val HOTKEY_TURBO_SPEED = "hotkey_turbo_speed" val buttonKeys = listOf( KEY_BUTTON_A, @@ -204,7 +205,8 @@ class Settings { HOTKEY_CLOSE_GAME, HOTKEY_PAUSE_OR_RESUME, HOTKEY_QUICKSAVE, - HOTKEY_QUICKlOAD + HOTKEY_QUICKlOAD, + HOTKEY_TURBO_SPEED ) val hotkeyTitles = listOf( R.string.emulation_swap_screens, @@ -213,6 +215,7 @@ class Settings { R.string.emulation_toggle_pause, R.string.emulation_quicksave, R.string.emulation_quickload, + R.string.emulation_toggle_turbo_speed ) const val PREF_FIRST_APP_LAUNCH = "FirstApplicationLaunch" diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/InputBindingSetting.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/InputBindingSetting.kt index 8ecd60684..5a722c07c 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/InputBindingSetting.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/InputBindingSetting.kt @@ -133,6 +133,7 @@ class InputBindingSetting( Settings.HOTKEY_PAUSE_OR_RESUME -> Hotkey.PAUSE_OR_RESUME.button Settings.HOTKEY_QUICKSAVE -> Hotkey.QUICKSAVE.button Settings.HOTKEY_QUICKlOAD -> Hotkey.QUICKLOAD.button + Settings.HOTKEY_TURBO_SPEED -> Hotkey.TURBO_SPEED.button else -> -1 } diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsFragmentPresenter.kt index 31401567f..c8962461d 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -236,6 +236,18 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) IntSetting.FRAME_LIMIT.defaultValue.toFloat() ) ) + add( + SliderSetting( + IntSetting.TURBO_SPEED, + R.string.turbo_speed, + R.string.turbo_speed_description, + 100, + 400, + "%", + IntSetting.TURBO_SPEED.key, + IntSetting.TURBO_SPEED.defaultValue.toFloat() + ) + ) } } diff --git a/src/android/app/src/main/jni/config.cpp b/src/android/app/src/main/jni/config.cpp index 19e422324..6ad3a6cd1 100644 --- a/src/android/app/src/main/jni/config.cpp +++ b/src/android/app/src/main/jni/config.cpp @@ -149,8 +149,8 @@ void Config::ReadValues() { ReadSetting("Renderer", Settings::values.use_vsync_new); ReadSetting("Renderer", Settings::values.texture_filter); ReadSetting("Renderer", Settings::values.texture_sampling); - - // Work around to map Android setting for enabling the frame limiter to the format Citra expects + ReadSetting("Renderer", Settings::values.turbo_speed); + // Workaround to map Android setting for enabling the frame limiter to the format Citra expects if (sdl2_config->GetBoolean("Renderer", "use_frame_limit", true)) { ReadSetting("Renderer", Settings::values.frame_limit); } else { diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index d4263c18a..d60663cfe 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -745,4 +745,19 @@ void Java_org_citra_citra_1emu_NativeLibrary_logDeviceInfo([[maybe_unused]] JNIE LOG_INFO(Frontend, "Host OS: Android API level {}", android_get_device_api_level()); } +void JNICALL Java_io_github_lime3ds_android_NativeLibrary_toggleTurboSpeed( + [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject obj, jboolean enabled) { + Settings::values.turbo_speed = enabled ? true : false; +} + +jint JNICALL Java_io_github_lime3ds_android_NativeLibrary_getTurboSpeedSlider( + [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject obj) { + return static_cast(Settings::values.turbo_speed); +} + +void JNICALL Java_io_github_lime3ds_android_NativeLibrary_setTurboSpeedSlider( + [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject obj, jint value) { + Settings::values.turbo_speed = value; +} + } // extern "C" diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 5495a2a23..56d00cc38 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -238,9 +238,12 @@ Enable asynchronous GPU emulation Uses a separate thread to emulate the GPU asynchronously. When enabled, performance will be improved. Limit Speed - When enabled, emulation speed will be limited to a specified percentage of normal speed. + When enabled, emulation speed will be limited to a specified percentage of normal speed. If disabled, emulation speed will be uncapped and the turbo speed hotkey will not work. Limit Speed Percent Specifies the percentage to limit emulation speed. With the default of 100% emulation will be limited to normal speed. Values higher or lower will increase or decrease the speed limit. + Turbo Speed + Turbo Speed + Value used for the turbo hotkey Internal Resolution Specifies the resolution used to render at. A high resolution will improve visual quality a lot but is also quite heavy on performance and might cause glitches in certain applications. Native (400x240) diff --git a/src/citra_qt/configuration/configure_hotkeys.cpp b/src/citra_qt/configuration/configure_hotkeys.cpp index 78cc9038b..0364d643a 100644 --- a/src/citra_qt/configuration/configure_hotkeys.cpp +++ b/src/citra_qt/configuration/configure_hotkeys.cpp @@ -102,12 +102,11 @@ void ConfigureHotkeys::Configure(QModelIndex index) { // to the same action. Which cuases problems resetting the frame limit.to the inititla value. const QString current_action = model->data(model->index(index.row(), 0, index.parent())).toString(); - const bool is_turbo = current_action == tr("Toggle Custom Emulation Speed"); + const bool is_turbo = current_action == tr("Toggle Turbo Mode"); const bool is_per_game = current_action == tr("Toggle Per-Game Speed"); if (is_turbo || is_per_game) { - QString other_action = - is_turbo ? tr("Toggle Per-Game Speed") : tr("Toggle Custom Emulation Speed"); + QString other_action = is_turbo ? tr("Toggle Per-Game Speed") : tr("Toggle Turbo Mode"); QKeySequence other_sequence; for (int r = 0; r < model->rowCount(); ++r) {