From e3618b86472de8ce57a5581afc0d28674ec46638 Mon Sep 17 00:00:00 2001 From: crueter Date: Wed, 11 Feb 2026 10:38:26 -0500 Subject: [PATCH] [frontend] Slow and Turbo modes Closes #3344 Adds slow and turbo modes with configurable speeds that can then be toggled by the user. Behavior is: - Standard/slow limit, toggle turbo = turbo - Turbo limit, toggle turbo = standard - Standard/turbo limit, toggle slow = slow - Slow limit, toggle slow = standard Enabling the turbo/slow mode enables the frame limiter unconditionally. Needs some work on Android, e.g. updating the frame limiter toggle when turbo/slow is selected, but that's for later since I have to go now This has some conflicts with VSync. For example when I set my refresh rate to 60hz and enable vsync, turbo mode does nothing. Not sure how to go about fixing this, @MaranBr probably knows better the proper solution. Signed-off-by: crueter --- .../java/org/yuzu/yuzu_emu/NativeLibrary.kt | 10 +++++ .../yuzu/yuzu_emu/dialogs/QuickSettings.kt | 32 ++++++++++++++ .../features/settings/model/ShortSetting.kt | 5 ++- .../settings/model/view/SettingsItem.kt | 20 +++++++++ .../settings/ui/SettingsFragmentPresenter.kt | 2 + .../yuzu_emu/fragments/EmulationFragment.kt | 22 ++++++++++ src/android/app/src/main/jni/native.cpp | 29 +++++++++++++ .../app/src/main/res/values/strings.xml | 4 ++ src/common/settings.h | 25 +++++++++++ src/core/core_timing.cpp | 2 +- src/core/hle/service/vi/conductor.cpp | 2 +- src/core/perf_stats.cpp | 2 +- src/qt_common/config/shared_translation.cpp | 12 +++++- src/qt_common/config/uisettings.h | 14 +++--- src/yuzu/main_window.cpp | 43 ++++++++++++++++--- 15 files changed, 206 insertions(+), 18 deletions(-) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt index 1f3d9a22a2..73d88e7891 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt @@ -203,6 +203,16 @@ object NativeLibrary { external fun getDebugKnobAt(index: Int): Boolean + /** + * Set the current speed limit to the configured turbo speed. + */ + external fun setTurboSpeedLimit(enabled: Boolean) + + /** + * Set the current speed limit to the configured turbo speed. + */ + external fun setSlowSpeedLimit(enabled: Boolean) + /** * Returns Vulkan driver version / API version / GPU model */ diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/QuickSettings.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/QuickSettings.kt index 992f8f2a16..be4b0c9953 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/QuickSettings.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/QuickSettings.kt @@ -11,6 +11,7 @@ import android.widget.RadioGroup import android.widget.TextView import androidx.drawerlayout.widget.DrawerLayout import com.google.android.material.color.MaterialColors +import com.google.android.material.materialswitch.MaterialSwitch import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.YuzuApplication import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting @@ -135,6 +136,37 @@ class QuickSettings(val emulationFragment: EmulationFragment) { container.addView(itemView) } + fun addCustomToggle( + name: Int, +// isChecked: Boolean, + + container: ViewGroup, + callback: (Boolean) -> Unit + ): MaterialSwitch? { + val inflater = LayoutInflater.from(emulationFragment.requireContext()) + val itemView = inflater.inflate(R.layout.item_quick_settings_menu, container, false) + + val switchContainer = itemView.findViewById(R.id.switch_container) + val titleView = itemView.findViewById(R.id.switch_title) + val switchView = itemView.findViewById(R.id.setting_switch) + + titleView.text = YuzuApplication.appContext.getString(name) + switchContainer.visibility = View.VISIBLE +// switchView.isChecked = isChecked + + switchView.setOnCheckedChangeListener { _, checked -> + callback(checked) + saveSettings() + } + + switchContainer.setOnClickListener { + switchView.toggle() + } + container.addView(itemView) + + return switchView + } + fun addSliderSetting( name: Int, container: ViewGroup, diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/ShortSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/ShortSetting.kt index 16eb4ffdd5..46fcebe914 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/ShortSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/ShortSetting.kt @@ -6,7 +6,10 @@ package org.yuzu.yuzu_emu.features.settings.model import org.yuzu.yuzu_emu.utils.NativeConfig enum class ShortSetting(override val key: String) : AbstractShortSetting { - RENDERER_SPEED_LIMIT("speed_limit"); + RENDERER_SPEED_LIMIT("speed_limit"), + RENDERER_TURBO_SPEED_LIMIT("turbo_speed_limit"), + RENDERER_SLOW_SPEED_LIMIT("slow_speed_limit"), + ; override fun getShort(needsGlobal: Boolean): Short = NativeConfig.getShort(key, needsGlobal) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt index 8bb618289e..cb6812e1b8 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt @@ -178,6 +178,26 @@ abstract class SettingsItem( units = "%" ) ) + put( + SliderSetting( + ShortSetting.RENDERER_TURBO_SPEED_LIMIT, + titleId = R.string.turbo_speed_limit, + descriptionId = R.string.turbo_speed_limit_description, + min = 1, + max = 400, + units = "%" + ) + ) + put( + SliderSetting( + ShortSetting.RENDERER_SLOW_SPEED_LIMIT, + titleId = R.string.slow_speed_limit, + descriptionId = R.string.slow_speed_limit_description, + min = 1, + max = 400, + units = "%" + ) + ) put( SingleChoiceSetting( IntSetting.CPU_BACKEND, diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index 8135b6043c..8007d28f38 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -227,6 +227,8 @@ class SettingsFragmentPresenter( add(StringSetting.DEVICE_NAME.key) add(BooleanSetting.RENDERER_USE_SPEED_LIMIT.key) add(ShortSetting.RENDERER_SPEED_LIMIT.key) + add(ShortSetting.RENDERER_TURBO_SPEED_LIMIT.key) + add(ShortSetting.RENDERER_SLOW_SPEED_LIMIT.key) add(BooleanSetting.USE_DOCKED_MODE.key) add(IntSetting.REGION_INDEX.key) add(IntSetting.LANGUAGE_INDEX.key) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt index 0c091fdeb9..5826c3e8de 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt @@ -55,6 +55,7 @@ import androidx.window.layout.WindowInfoTracker import androidx.window.layout.WindowLayoutInfo import com.google.android.material.color.MaterialColors import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.google.android.material.materialswitch.MaterialSwitch import com.google.android.material.textview.MaterialTextView import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers @@ -1070,6 +1071,27 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { units = "%", ) + lateinit var slowSpeed: MaterialSwitch + lateinit var turboSpeed: MaterialSwitch + + turboSpeed = quickSettings.addCustomToggle( + R.string.turbo_speed_limit, + container + ) { enabled -> + if (enabled) + slowSpeed.isChecked = false + NativeLibrary.setTurboSpeedLimit(enabled) + }!! + + slowSpeed = quickSettings.addCustomToggle( + R.string.slow_speed_limit, + container + ) { enabled -> + if (enabled) + turboSpeed.isChecked = false + NativeLibrary.setSlowSpeedLimit(enabled) + }!! + quickSettings.addBooleanSetting( R.string.use_docked_mode, container, diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index 9cb44bbd3a..484565975f 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -371,6 +371,9 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string // Create the render window. m_window = std::make_unique(m_native_window, m_vulkan_library); + // Set up speed limiter + Settings::values.current_speed_limit.SetValue(Settings::values.speed_limit.GetValue()); + // Initialize system. jauto android_keyboard = std::make_unique(); jauto android_webapplet = std::make_unique(); @@ -1233,6 +1236,32 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_getDebugKnobAt(JNIEnv* env, jobje return static_cast(Settings::getDebugKnobAt(static_cast(index))); } +void Java_org_yuzu_yuzu_1emu_NativeLibrary_setTurboSpeedLimit(JNIEnv *env, jobject jobj, jboolean enabled) { + Settings::values.use_speed_limit.SetValue(true); + + auto &cur = Settings::values.current_speed_limit; + auto &nxt = Settings::values.turbo_speed_limit.GetValue(); + auto &fallback = Settings::values.speed_limit.GetValue(); + + if (enabled && cur.GetValue() != nxt) + cur.SetValue(nxt); + else + cur.SetValue(fallback); +} + +void Java_org_yuzu_yuzu_1emu_NativeLibrary_setSlowSpeedLimit(JNIEnv *env, jobject jobj, jboolean enabled) { + Settings::values.use_speed_limit.SetValue(true); + + auto &cur = Settings::values.current_speed_limit; + auto &nxt = Settings::values.slow_speed_limit.GetValue(); + auto &fallback = Settings::values.speed_limit.GetValue(); + + if (enabled && cur.GetValue() != nxt) + cur.SetValue(nxt); + else + cur.SetValue(fallback); +} + void Java_org_yuzu_yuzu_1emu_NativeLibrary_run(JNIEnv* env, jobject jobj, jstring j_path, jint j_program_index, jboolean j_frontend_initiated) { diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 97aa054e8a..49940485d8 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -422,6 +422,10 @@ Limits emulation speed to a specified percentage of normal speed. Limit speed percent Specifies the percentage to limit emulation speed. 100% is the normal speed. Values higher or lower will increase or decrease the speed limit. + Turbo speed + When Turbo Mode is enabled, emulation will run at this speed. + Slow speed + When Slow Mode is enabled, emulation will run at this speed. CPU backend CPU accuracy %1$s%2$s diff --git a/src/common/settings.h b/src/common/settings.h index a609894027..c8c36937ba 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -214,6 +214,31 @@ struct Values { true, true, &use_speed_limit}; + + SwitchableSetting slow_speed_limit{linkage, + 50, + 0, + 9999, + "slow_speed_limit", + Category::Core, + Specialization::Countable | Specialization::Percentage, + true, + true}; + + // The currently used speed limit. + // TODO: should this be an enum? + SwitchableSetting current_speed_limit{linkage, 100, "current_speed_limit", Category::Core, Specialization::Default, false, true}; + + SwitchableSetting turbo_speed_limit{linkage, + 200, + 0, + 9999, + "turbo_speed_limit", + Category::Core, + Specialization::Countable | Specialization::Percentage, + true, + true}; + SwitchableSetting sync_core_speed{linkage, false, "sync_core_speed", Category::Core, Specialization::Default}; diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index b0fa7cd503..08b6f1c6c9 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -201,7 +201,7 @@ u64 CoreTiming::GetClockTicks() const { if (Settings::values.sync_core_speed.GetValue()) { const auto ticks = double(fres); - const auto speed_limit = double(Settings::values.speed_limit.GetValue())*0.01; + const auto speed_limit = double(Settings::values.current_speed_limit.GetValue())*0.01; return u64(ticks/speed_limit); } else { return fres; diff --git a/src/core/hle/service/vi/conductor.cpp b/src/core/hle/service/vi/conductor.cpp index a271041be6..3318e82567 100644 --- a/src/core/hle/service/vi/conductor.cpp +++ b/src/core/hle/service/vi/conductor.cpp @@ -95,7 +95,7 @@ s64 Conductor::GetNextTicks() const { if (settings.use_speed_limit.GetValue()) { // Scales the speed based on speed_limit setting on MC. SC is handled by // SpeedLimiter::DoSpeedLimiting. - speed_scale = 100.f / settings.speed_limit.GetValue(); + speed_scale = 100.f / settings.current_speed_limit.GetValue(); } else { // Run at unlocked framerate. speed_scale = 0.01f; diff --git a/src/core/perf_stats.cpp b/src/core/perf_stats.cpp index 35e76624f4..5564ec2528 100644 --- a/src/core/perf_stats.cpp +++ b/src/core/perf_stats.cpp @@ -143,7 +143,7 @@ void SpeedLimiter::DoSpeedLimiting(microseconds current_system_time_us) { auto now = Clock::now(); - const double sleep_scale = Settings::values.speed_limit.GetValue() / 100.0; + const double sleep_scale = Settings::values.current_speed_limit.GetValue() / 100.0; // Max lag caused by slow frames. Shouldn't be more than the length of a frame at the current // speed percent or it will clamp too much and prevent this from properly limiting to that diff --git a/src/qt_common/config/shared_translation.cpp b/src/qt_common/config/shared_translation.cpp index 5d4185b47d..cde73ac919 100644 --- a/src/qt_common/config/shared_translation.cpp +++ b/src/qt_common/config/shared_translation.cpp @@ -69,10 +69,10 @@ std::unique_ptr InitializeTranslations(QObject* parent) Settings, memory_layout_mode, tr("Memory Layout"), - tr("Increases the amount of emulated RAM from 4GB of the board to the " - "devkit 8/6GB.\nDoesn't affect performance/stability but may allow HD texture " + tr("Increases the amount of emulated RAM.\nDoesn't affect performance/stability but may allow HD texture " "mods to load.")); INSERT(Settings, use_speed_limit, QString(), QString()); + INSERT(Settings, current_speed_limit, QString(), QString()); INSERT(Settings, speed_limit, tr("Limit Speed Percent"), @@ -80,6 +80,14 @@ std::unique_ptr InitializeTranslations(QObject* parent) "faster or not.\n200% for a 30 FPS game is 60 FPS, and for a " "60 FPS game it will be 120 FPS.\nDisabling it means unlocking the framerate to the " "maximum your PC can reach.")); + + INSERT(Settings, turbo_speed_limit, tr("Turbo Speed"), + tr("When the Turbo Speed hotkey is pressed, the speed will be limited to this " + "percentage.")); + INSERT(Settings, slow_speed_limit, tr("Slow Speed"), + tr("When the Slow Speed hotkey is pressed, the speed will be limited to this " + "percentage.")); + INSERT(Settings, sync_core_speed, tr("Synchronize Core Speed"), diff --git a/src/qt_common/config/uisettings.h b/src/qt_common/config/uisettings.h index 3c75268377..b52c673305 100644 --- a/src/qt_common/config/uisettings.h +++ b/src/qt_common/config/uisettings.h @@ -249,7 +249,7 @@ void RestoreWindowState(std::unique_ptr& qtConfig); // This must be in alphabetical order according to action name as it must have the same order as // UISetting::values.shortcuts, which is alphabetically ordered. // clang-format off -const std::array default_hotkeys{{ +const std::array default_hotkeys{{ {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+M"), std::string("Home+Dpad_Right"), Qt::WindowShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("-"), std::string("Home+Dpad_Down"), Qt::ApplicationShortcut, true}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("="), std::string("Home+Dpad_Up"), Qt::ApplicationShortcut, true}}, @@ -265,11 +265,11 @@ const std::array default_hotkeys{{ {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F11"), std::string("Home+B"), Qt::WindowShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+O"), std::string(""), Qt::WidgetWithChildrenShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F2"), std::string("Home+A"), Qt::WidgetWithChildrenShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Browse Public Game Lobby")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+B"), std::string(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Create Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+N"), std::string(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Direct Connect to Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+C"), std::string(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Leave Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+L"), std::string(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Show Current Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+R"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Browse Public Game Lobby")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+B"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Create Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+N"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Direct Connect to Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+C"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Leave Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+L"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Show Current Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+R"), std::string(""), Qt::ApplicationShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F6"), std::string("R+Plus+Minus"), Qt::WindowShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F5"), std::string("L+Plus+Minus"), Qt::WindowShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Record")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F7"), std::string(""), Qt::ApplicationShortcut, false}}, @@ -277,6 +277,8 @@ const std::array default_hotkeys{{ {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Start/Stop")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F5"), std::string(""), Qt::ApplicationShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Filter Bar")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F"), std::string(""), Qt::WindowShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Framerate Limit")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+U"), std::string("Home+Y"), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Turbo Speed")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+Z"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Slow Speed")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+X"), std::string(""), Qt::ApplicationShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Mouse Panning")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F9"), std::string(""), Qt::ApplicationShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Renderdoc Capture")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string(""), std::string(""), Qt::ApplicationShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Status Bar")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+S"), std::string(""), Qt::WindowShortcut, false}}, diff --git a/src/yuzu/main_window.cpp b/src/yuzu/main_window.cpp index 2e5548c775..76d1a25338 100644 --- a/src/yuzu/main_window.cpp +++ b/src/yuzu/main_window.cpp @@ -1406,12 +1406,12 @@ void MainWindow::InitializeHotkeys() { LinkActionShortcut(ui->action_TAS_Record, QStringLiteral("TAS Record"), true); LinkActionShortcut(ui->action_TAS_Reset, QStringLiteral("TAS Reset"), true); LinkActionShortcut(ui->action_View_Lobby, - QStringLiteral("Multiplayer Browse Public Game Lobby")); - LinkActionShortcut(ui->action_Start_Room, QStringLiteral("Multiplayer Create Room")); + QStringLiteral("Browse Public Game Lobby")); + LinkActionShortcut(ui->action_Start_Room, QStringLiteral("Create Room")); LinkActionShortcut(ui->action_Connect_To_Room, - QStringLiteral("Multiplayer Direct Connect to Room")); - LinkActionShortcut(ui->action_Show_Room, QStringLiteral("Multiplayer Show Current Room")); - LinkActionShortcut(ui->action_Leave_Room, QStringLiteral("Multiplayer Leave Room")); + QStringLiteral("Direct Connect to Room")); + LinkActionShortcut(ui->action_Show_Room, QStringLiteral("Show Current Room")); + LinkActionShortcut(ui->action_Leave_Room, QStringLiteral("Leave Room")); LinkActionShortcut(ui->action_Configure, QStringLiteral("Configure")); LinkActionShortcut(ui->action_Configure_Current_Game, QStringLiteral("Configure Current Game")); @@ -1442,7 +1442,35 @@ void MainWindow::InitializeHotkeys() { connect_shortcut(QStringLiteral("Audio Volume Up"), &MainWindow::OnIncreaseVolume); connect_shortcut(QStringLiteral("Toggle Framerate Limit"), [] { Settings::values.use_speed_limit.SetValue(!Settings::values.use_speed_limit.GetValue()); + Settings::values.current_speed_limit.SetValue(Settings::values.speed_limit.GetValue()); }); + + connect_shortcut(QStringLiteral("Toggle Turbo Speed"), [] { + Settings::values.use_speed_limit.SetValue(true); + + auto &cur = Settings::values.current_speed_limit; + auto &nxt = Settings::values.turbo_speed_limit.GetValue(); + auto &fallback = Settings::values.speed_limit.GetValue(); + + if (cur.GetValue() == nxt) + cur.SetValue(fallback); + else + cur.SetValue(nxt); + }); + + connect_shortcut(QStringLiteral("Toggle Slow Speed"), [] { + Settings::values.use_speed_limit.SetValue(true); + + auto &cur = Settings::values.current_speed_limit; + auto &nxt = Settings::values.slow_speed_limit.GetValue(); + auto &fallback = Settings::values.speed_limit.GetValue(); + + if (cur.GetValue() == nxt) + cur.SetValue(fallback); + else + cur.SetValue(nxt); + }); + connect_shortcut(QStringLiteral("Toggle Renderdoc Capture"), [] { if (Settings::values.enable_renderdoc_hotkey) { QtCommon::system->GetRenderdocAPI().ToggleCapture(); @@ -2046,6 +2074,9 @@ void MainWindow::BootGame(const QString& filename, Service::AM::FrontendAppletPa game_list->SaveInterfaceLayout(); config->SaveAllValues(); + // Set up speed limiter + Settings::values.current_speed_limit.SetValue(Settings::values.speed_limit.GetValue()); + u64 title_id{0}; last_filename_booted = filename; @@ -4254,7 +4285,7 @@ void MainWindow::UpdateStatusBar() { if (Settings::values.use_speed_limit.GetValue()) { emu_speed_label->setText(tr("Speed: %1% / %2%") .arg(results.emulation_speed * 100.0, 0, 'f', 0) - .arg(Settings::values.speed_limit.GetValue())); + .arg(Settings::values.current_speed_limit.GetValue())); } else { emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0)); }