duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

hotkeys.cpp (32672B)


      1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
      2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
      3 
      4 #include "achievements.h"
      5 #include "cpu_code_cache.h"
      6 #include "cpu_core.h"
      7 #include "cpu_pgxp.h"
      8 #include "fullscreen_ui.h"
      9 #include "gpu.h"
     10 #include "host.h"
     11 #include "imgui_overlays.h"
     12 #include "settings.h"
     13 #include "spu.h"
     14 #include "system.h"
     15 #include "texture_replacements.h"
     16 
     17 #include "util/gpu_device.h"
     18 #include "util/input_manager.h"
     19 #include "util/postprocessing.h"
     20 
     21 #include "common/error.h"
     22 #include "common/file_system.h"
     23 #include "common/timer.h"
     24 
     25 #include "IconsFontAwesome5.h"
     26 #include "IconsEmoji.h"
     27 
     28 #include <cmath>
     29 
     30 void Settings::SetDefaultHotkeyConfig(SettingsInterface& si)
     31 {
     32   si.ClearSection("Hotkeys");
     33 
     34 #ifndef __ANDROID__
     35   si.SetStringValue("Hotkeys", "FastForward", "Keyboard/Tab");
     36   si.SetStringValue("Hotkeys", "TogglePause", "Keyboard/Space");
     37   si.SetStringValue("Hotkeys", "Screenshot", "Keyboard/F10");
     38   si.SetStringValue("Hotkeys", "ToggleFullscreen", "Keyboard/F11");
     39 
     40   si.SetStringValue("Hotkeys", "OpenPauseMenu", "Keyboard/Escape");
     41   si.SetStringValue("Hotkeys", "LoadSelectedSaveState", "Keyboard/F1");
     42   si.SetStringValue("Hotkeys", "SaveSelectedSaveState", "Keyboard/F2");
     43   si.SetStringValue("Hotkeys", "SelectPreviousSaveStateSlot", "Keyboard/F3");
     44   si.SetStringValue("Hotkeys", "SelectNextSaveStateSlot", "Keyboard/F4");
     45 #endif
     46 }
     47 
     48 static void HotkeyModifyResolutionScale(s32 increment)
     49 {
     50   const u32 new_resolution_scale = std::clamp<u32>(
     51     static_cast<u32>(static_cast<s32>(g_settings.gpu_resolution_scale) + increment), 1, GPU::MAX_RESOLUTION_SCALE);
     52   if (new_resolution_scale == g_settings.gpu_resolution_scale)
     53     return;
     54 
     55   const Settings old_settings = g_settings;
     56   g_settings.gpu_resolution_scale = Truncate8(new_resolution_scale);
     57 
     58   if (System::IsValid())
     59   {
     60     g_gpu->RestoreDeviceContext();
     61     g_gpu->UpdateSettings(old_settings);
     62     System::ClearMemorySaveStates();
     63   }
     64 }
     65 
     66 static void HotkeyLoadStateSlot(bool global, s32 slot)
     67 {
     68   if (!System::IsValid())
     69     return;
     70 
     71   if (!global && System::GetGameSerial().empty())
     72   {
     73     Host::AddKeyedOSDMessage("LoadState", TRANSLATE_STR("OSDMessage", "Cannot load state for game without serial."),
     74                              Host::OSD_ERROR_DURATION);
     75     return;
     76   }
     77 
     78   std::string path(global ? System::GetGlobalSaveStateFileName(slot) :
     79                             System::GetGameSaveStateFileName(System::GetGameSerial(), slot));
     80   if (!FileSystem::FileExists(path.c_str()))
     81   {
     82     Host::AddKeyedOSDMessage("LoadState",
     83                              fmt::format(TRANSLATE_FS("OSDMessage", "No save state found in slot {}."), slot),
     84                              Host::OSD_INFO_DURATION);
     85     return;
     86   }
     87 
     88   Error error;
     89   if (!System::LoadState(path.c_str(), &error, true))
     90   {
     91     Host::AddKeyedOSDMessage(
     92       "LoadState",
     93       fmt::format(TRANSLATE_FS("OSDMessage", "Failed to load state from slot {0}:\n{1}"), slot, error.GetDescription()),
     94       Host::OSD_ERROR_DURATION);
     95   }
     96 }
     97 
     98 static void HotkeySaveStateSlot(bool global, s32 slot)
     99 {
    100   if (!System::IsValid())
    101     return;
    102 
    103   if (!global && System::GetGameSerial().empty())
    104   {
    105     Host::AddKeyedOSDMessage("SaveState", TRANSLATE_STR("OSDMessage", "Cannot save state for game without serial."),
    106                              Host::OSD_ERROR_DURATION);
    107     return;
    108   }
    109 
    110   std::string path(global ? System::GetGlobalSaveStateFileName(slot) :
    111                             System::GetGameSaveStateFileName(System::GetGameSerial(), slot));
    112   Error error;
    113   if (!System::SaveState(path.c_str(), &error, g_settings.create_save_state_backups))
    114   {
    115     Host::AddIconOSDMessage(
    116       "SaveState", ICON_FA_EXCLAMATION_TRIANGLE,
    117       fmt::format(TRANSLATE_FS("OSDMessage", "Failed to save state to slot {0}:\n{1}"), slot, error.GetDescription()),
    118       Host::OSD_ERROR_DURATION);
    119   }
    120 }
    121 
    122 static void HotkeyToggleOSD()
    123 {
    124   g_settings.display_show_fps ^= Host::GetBoolSettingValue("Display", "ShowFPS", false);
    125   g_settings.display_show_speed ^= Host::GetBoolSettingValue("Display", "ShowSpeed", false);
    126   g_settings.display_show_gpu_stats ^= Host::GetBoolSettingValue("Display", "ShowGPUStatistics", false);
    127   g_settings.display_show_resolution ^= Host::GetBoolSettingValue("Display", "ShowResolution", false);
    128   g_settings.display_show_latency_stats ^= Host::GetBoolSettingValue("Display", "ShowLatencyStatistics", false);
    129   g_settings.display_show_cpu_usage ^= Host::GetBoolSettingValue("Display", "ShowCPU", false);
    130   g_settings.display_show_gpu_usage ^= Host::GetBoolSettingValue("Display", "ShowGPU", false);
    131   g_settings.display_show_frame_times ^= Host::GetBoolSettingValue("Display", "ShowFrameTimes", false);
    132   g_settings.display_show_status_indicators ^= Host::GetBoolSettingValue("Display", "ShowStatusIndicators", true);
    133   g_settings.display_show_inputs ^= Host::GetBoolSettingValue("Display", "ShowInputs", false);
    134   g_settings.display_show_enhancements ^= Host::GetBoolSettingValue("Display", "ShowEnhancements", false);
    135 }
    136 
    137 #ifndef __ANDROID__
    138 
    139 static bool CanPause()
    140 {
    141   static constexpr const float PAUSE_INTERVAL = 3.0f;
    142   static Common::Timer::Value s_last_pause_time = 0;
    143 
    144   if (!Achievements::IsHardcoreModeActive() || System::IsPaused())
    145     return true;
    146 
    147   const Common::Timer::Value time = Common::Timer::GetCurrentValue();
    148   const float delta = static_cast<float>(Common::Timer::ConvertValueToSeconds(time - s_last_pause_time));
    149   if (delta < PAUSE_INTERVAL)
    150   {
    151     Host::AddIconOSDMessage("PauseCooldown", ICON_FA_CLOCK,
    152                             TRANSLATE_PLURAL_STR("Hotkeys", "You cannot pause until another %n second(s) have passed.",
    153                                                  "", static_cast<int>(std::ceil(PAUSE_INTERVAL - delta))),
    154                             Host::OSD_QUICK_DURATION);
    155     return false;
    156   }
    157 
    158   Host::RemoveKeyedOSDMessage("PauseCooldown");
    159   s_last_pause_time = time;
    160 
    161   return true;
    162 }
    163 
    164 #endif
    165 
    166 BEGIN_HOTKEY_LIST(g_common_hotkeys)
    167 #ifndef __ANDROID__
    168 DEFINE_HOTKEY("OpenPauseMenu", TRANSLATE_NOOP("Hotkeys", "General"), TRANSLATE_NOOP("Hotkeys", "Open Pause Menu"),
    169               [](s32 pressed) {
    170                 if (!pressed && CanPause())
    171                   FullscreenUI::OpenPauseMenu();
    172               })
    173 #endif
    174 
    175 DEFINE_HOTKEY("FastForward", TRANSLATE_NOOP("Hotkeys", "General"), TRANSLATE_NOOP("Hotkeys", "Fast Forward"),
    176               [](s32 pressed) {
    177                 if (pressed < 0)
    178                   return;
    179                 System::SetFastForwardEnabled(pressed > 0);
    180               })
    181 
    182 DEFINE_HOTKEY("ToggleFastForward", TRANSLATE_NOOP("Hotkeys", "General"),
    183               TRANSLATE_NOOP("Hotkeys", "Toggle Fast Forward"), [](s32 pressed) {
    184                 if (!pressed)
    185                   System::SetFastForwardEnabled(!System::IsFastForwardEnabled());
    186               })
    187 
    188 DEFINE_HOTKEY("Turbo", TRANSLATE_NOOP("Hotkeys", "General"), TRANSLATE_NOOP("Hotkeys", "Turbo"), [](s32 pressed) {
    189   if (pressed < 0)
    190     return;
    191   System::SetTurboEnabled(pressed > 0);
    192 })
    193 
    194 DEFINE_HOTKEY("ToggleTurbo", TRANSLATE_NOOP("Hotkeys", "General"), TRANSLATE_NOOP("Hotkeys", "Toggle Turbo"),
    195               [](s32 pressed) {
    196                 if (!pressed)
    197                   System::SetTurboEnabled(!System::IsTurboEnabled());
    198               })
    199 
    200 #ifndef __ANDROID__
    201 DEFINE_HOTKEY("ToggleFullscreen", TRANSLATE_NOOP("Hotkeys", "General"), TRANSLATE_NOOP("Hotkeys", "Toggle Fullscreen"),
    202               [](s32 pressed) {
    203                 if (!pressed)
    204                   Host::SetFullscreen(!Host::IsFullscreen());
    205               })
    206 
    207 DEFINE_HOTKEY("TogglePause", TRANSLATE_NOOP("Hotkeys", "General"), TRANSLATE_NOOP("Hotkeys", "Toggle Pause"),
    208               [](s32 pressed) {
    209                 if (!pressed && CanPause())
    210                   System::PauseSystem(!System::IsPaused());
    211               })
    212 
    213 DEFINE_HOTKEY("PowerOff", TRANSLATE_NOOP("Hotkeys", "General"), TRANSLATE_NOOP("Hotkeys", "Power Off System"),
    214               [](s32 pressed) {
    215                 if (!pressed && CanPause())
    216                   Host::RequestSystemShutdown(true, g_settings.save_state_on_exit);
    217               })
    218 #endif
    219 
    220 DEFINE_HOTKEY("Screenshot", TRANSLATE_NOOP("Hotkeys", "General"), TRANSLATE_NOOP("Hotkeys", "Save Screenshot"),
    221               [](s32 pressed) {
    222                 if (!pressed)
    223                   System::SaveScreenshot();
    224               })
    225 
    226 #ifndef __ANDROID__
    227 DEFINE_HOTKEY("ToggleMediaCapture", TRANSLATE_NOOP("Hotkeys", "General"),
    228               TRANSLATE_NOOP("Hotkeys", "Toggle Media Capture"), [](s32 pressed) {
    229                 if (!pressed)
    230                 {
    231                   if (System::GetMediaCapture())
    232                     System::StopMediaCapture();
    233                   else
    234                     System::StartMediaCapture();
    235                 }
    236               })
    237 
    238 DEFINE_HOTKEY("OpenAchievements", TRANSLATE_NOOP("Hotkeys", "General"),
    239               TRANSLATE_NOOP("Hotkeys", "Open Achievement List"), [](s32 pressed) {
    240                 if (!pressed && CanPause())
    241                   FullscreenUI::OpenAchievementsWindow();
    242               })
    243 
    244 DEFINE_HOTKEY("OpenLeaderboards", TRANSLATE_NOOP("Hotkeys", "General"),
    245               TRANSLATE_NOOP("Hotkeys", "Open Leaderboard List"), [](s32 pressed) {
    246                 if (!pressed && CanPause())
    247                   FullscreenUI::OpenLeaderboardsWindow();
    248               })
    249 #endif
    250 
    251 DEFINE_HOTKEY("Reset", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Reset System"), [](s32 pressed) {
    252   if (!pressed)
    253     Host::RunOnCPUThread(System::ResetSystem);
    254 })
    255 
    256 DEFINE_HOTKEY("ChangeDisc", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Change Disc"),
    257               [](s32 pressed) {
    258                 if (!pressed && System::IsValid() && System::HasMediaSubImages())
    259                 {
    260                   const u32 current = System::GetMediaSubImageIndex();
    261                   const u32 next = (current + 1) % System::GetMediaSubImageCount();
    262                   if (current != next)
    263                     Host::RunOnCPUThread([next]() { System::SwitchMediaSubImage(next); });
    264                 }
    265               })
    266 
    267 DEFINE_HOTKEY("SwapMemoryCards", TRANSLATE_NOOP("Hotkeys", "System"),
    268               TRANSLATE_NOOP("Hotkeys", "Swap Memory Card Slots"), [](s32 pressed) {
    269                 if (!pressed)
    270                   System::SwapMemoryCards();
    271               })
    272 
    273 #ifndef __ANDROID__
    274 DEFINE_HOTKEY("FrameStep", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Frame Step"),
    275               [](s32 pressed) {
    276                 if (!pressed)
    277                   System::DoFrameStep();
    278               })
    279 #endif
    280 
    281 DEFINE_HOTKEY("Rewind", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Rewind"), [](s32 pressed) {
    282   if (pressed < 0)
    283     return;
    284   System::SetRewindState(pressed > 0);
    285 })
    286 
    287 #ifndef __ANDROID__
    288 DEFINE_HOTKEY("ToggleCheats", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Toggle Cheats"),
    289               [](s32 pressed) {
    290                 if (!pressed)
    291                   System::DoToggleCheats();
    292               })
    293 #else
    294 DEFINE_HOTKEY("TogglePatchCodes", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Toggle Patch Codes"),
    295               [](s32 pressed) {
    296                 if (!pressed)
    297                   System::DoToggleCheats();
    298               })
    299 #endif
    300 
    301 DEFINE_HOTKEY("ToggleOverclocking", TRANSLATE_NOOP("Hotkeys", "System"),
    302               TRANSLATE_NOOP("Hotkeys", "Toggle Clock Speed Control (Overclocking)"), [](s32 pressed) {
    303                 if (!pressed && System::IsValid())
    304                 {
    305                   g_settings.cpu_overclock_enable = !g_settings.cpu_overclock_enable;
    306                   g_settings.UpdateOverclockActive();
    307                   System::UpdateOverclock();
    308 
    309                   if (g_settings.cpu_overclock_enable)
    310                   {
    311                     const u32 percent = g_settings.GetCPUOverclockPercent();
    312                     const double clock_speed =
    313                       ((static_cast<double>(System::MASTER_CLOCK) * static_cast<double>(percent)) / 100.0) / 1000000.0;
    314                     Host::AddIconOSDMessage(
    315                       "ToggleOverclocking", ICON_FA_TACHOMETER_ALT,
    316                       fmt::format(TRANSLATE_FS("OSDMessage", "CPU clock speed control enabled ({:.3f} MHz)."),
    317                                   clock_speed),
    318                       Host::OSD_QUICK_DURATION);
    319                   }
    320                   else
    321                   {
    322                     Host::AddIconOSDMessage(
    323                       "ToggleOverclocking", ICON_FA_TACHOMETER_ALT,
    324                       fmt::format(TRANSLATE_FS("OSDMessage", "CPU clock speed control disabled ({:.3f} MHz)."),
    325                                   static_cast<double>(System::MASTER_CLOCK) / 1000000.0),
    326                       Host::OSD_QUICK_DURATION);
    327                   }
    328                 }
    329               })
    330 
    331 DEFINE_HOTKEY("IncreaseEmulationSpeed", TRANSLATE_NOOP("Hotkeys", "System"),
    332               TRANSLATE_NOOP("Hotkeys", "Increase Emulation Speed"), [](s32 pressed) {
    333                 if (!pressed && System::IsValid())
    334                 {
    335                   g_settings.emulation_speed += 0.1f;
    336                   System::UpdateSpeedLimiterState();
    337                   Host::AddIconOSDMessage(
    338                     "EmulationSpeedChange", ICON_FA_TACHOMETER_ALT,
    339                     fmt::format(TRANSLATE_FS("OSDMessage", "Emulation speed set to {}%."),
    340                                 static_cast<u32>(std::lround(g_settings.emulation_speed * 100.0f))),
    341                     Host::OSD_QUICK_DURATION);
    342                 }
    343               })
    344 
    345 DEFINE_HOTKEY("DecreaseEmulationSpeed", TRANSLATE_NOOP("Hotkeys", "System"),
    346               TRANSLATE_NOOP("Hotkeys", "Decrease Emulation Speed"), [](s32 pressed) {
    347                 if (!pressed && System::IsValid())
    348                 {
    349                   g_settings.emulation_speed = std::max(g_settings.emulation_speed - 0.1f, 0.1f);
    350                   System::UpdateSpeedLimiterState();
    351                   Host::AddIconOSDMessage(
    352                     "EmulationSpeedChange", ICON_FA_TACHOMETER_ALT,
    353                     fmt::format(TRANSLATE_FS("OSDMessage", "Emulation speed set to {}%."),
    354                                 static_cast<u32>(std::lround(g_settings.emulation_speed * 100.0f))),
    355                     Host::OSD_QUICK_DURATION);
    356                 }
    357               })
    358 
    359 DEFINE_HOTKEY("ResetEmulationSpeed", TRANSLATE_NOOP("Hotkeys", "System"),
    360               TRANSLATE_NOOP("Hotkeys", "Reset Emulation Speed"), [](s32 pressed) {
    361                 if (!pressed && System::IsValid())
    362                 {
    363                   g_settings.emulation_speed = Host::GetFloatSettingValue("Main", "EmulationSpeed", 1.0f);
    364                   System::UpdateSpeedLimiterState();
    365                   Host::AddIconOSDMessage(
    366                     "EmulationSpeedChange", ICON_FA_TACHOMETER_ALT,
    367                     fmt::format(TRANSLATE_FS("OSDMessage", "Emulation speed set to {}%."),
    368                                 static_cast<u32>(std::lround(g_settings.emulation_speed * 100.0f))),
    369                     Host::OSD_QUICK_DURATION);
    370                 }
    371               })
    372 
    373 DEFINE_HOTKEY("ToggleSoftwareRendering", TRANSLATE_NOOP("Hotkeys", "Graphics"),
    374               TRANSLATE_NOOP("Hotkeys", "Toggle Software Rendering"), [](s32 pressed) {
    375                 if (!pressed && System::IsValid())
    376                   System::ToggleSoftwareRendering();
    377               })
    378 
    379 DEFINE_HOTKEY("TogglePGXP", TRANSLATE_NOOP("Hotkeys", "Graphics"), TRANSLATE_NOOP("Hotkeys", "Toggle PGXP"),
    380               [](s32 pressed) {
    381                 if (!pressed && System::IsValid())
    382                 {
    383                   Settings old_settings = g_settings;
    384                   g_settings.gpu_pgxp_enable = !g_settings.gpu_pgxp_enable;
    385                   g_gpu->RestoreDeviceContext();
    386                   g_gpu->UpdateSettings(old_settings);
    387                   System::ClearMemorySaveStates();
    388                   Host::AddKeyedOSDMessage("TogglePGXP",
    389                                            g_settings.gpu_pgxp_enable ?
    390                                              TRANSLATE_STR("OSDMessage", "PGXP is now enabled.") :
    391                                              TRANSLATE_STR("OSDMessage", "PGXP is now disabled."),
    392                                            5.0f);
    393 
    394                   if (g_settings.gpu_pgxp_enable)
    395                     CPU::PGXP::Initialize();
    396                   else
    397                     CPU::PGXP::Shutdown();
    398 
    399                   // we need to recompile all blocks if pgxp is toggled on/off
    400                   CPU::CodeCache::Reset();
    401 
    402                   // need to swap interpreters
    403                   System::InterruptExecution();
    404                 }
    405               })
    406 
    407 DEFINE_HOTKEY("IncreaseResolutionScale", TRANSLATE_NOOP("Hotkeys", "Graphics"),
    408               TRANSLATE_NOOP("Hotkeys", "Increase Resolution Scale"), [](s32 pressed) {
    409                 if (!pressed && System::IsValid())
    410                   HotkeyModifyResolutionScale(1);
    411               })
    412 
    413 DEFINE_HOTKEY("DecreaseResolutionScale", TRANSLATE_NOOP("Hotkeys", "Graphics"),
    414               TRANSLATE_NOOP("Hotkeys", "Decrease Resolution Scale"), [](s32 pressed) {
    415                 if (!pressed && System::IsValid())
    416                   HotkeyModifyResolutionScale(-1);
    417               })
    418 
    419 DEFINE_HOTKEY("TogglePostProcessing", TRANSLATE_NOOP("Hotkeys", "Graphics"),
    420               TRANSLATE_NOOP("Hotkeys", "Toggle Post-Processing"), [](s32 pressed) {
    421                 if (!pressed && System::IsValid())
    422                   PostProcessing::DisplayChain.Toggle();
    423               })
    424 
    425 DEFINE_HOTKEY("ToggleInternalPostProcessing", TRANSLATE_NOOP("Hotkeys", "Graphics"),
    426               TRANSLATE_NOOP("Hotkeys", "Toggle Internal Post-Processing"), [](s32 pressed) {
    427                 if (!pressed && System::IsValid())
    428                   PostProcessing::InternalChain.Toggle();
    429               })
    430 
    431 DEFINE_HOTKEY("ReloadPostProcessingShaders", TRANSLATE_NOOP("Hotkeys", "Graphics"),
    432               TRANSLATE_NOOP("Hotkeys", "Reload Post Processing Shaders"), [](s32 pressed) {
    433                 if (!pressed && System::IsValid())
    434                   PostProcessing::ReloadShaders();
    435               })
    436 
    437 DEFINE_HOTKEY("ReloadTextureReplacements", TRANSLATE_NOOP("Hotkeys", "Graphics"),
    438               TRANSLATE_NOOP("Hotkeys", "Reload Texture Replacements"), [](s32 pressed) {
    439                 if (!pressed && System::IsValid())
    440                 {
    441                   Host::AddKeyedOSDMessage("ReloadTextureReplacements",
    442                                            TRANSLATE_STR("OSDMessage", "Texture replacements reloaded."), 10.0f);
    443                   TextureReplacements::Reload();
    444                 }
    445               })
    446 
    447 DEFINE_HOTKEY("ToggleWidescreen", TRANSLATE_NOOP("Hotkeys", "Graphics"), TRANSLATE_NOOP("Hotkeys", "Toggle Widescreen"),
    448               [](s32 pressed) {
    449                 if (!pressed)
    450                   System::ToggleWidescreen();
    451               })
    452 
    453 DEFINE_HOTKEY("TogglePGXPDepth", TRANSLATE_NOOP("Hotkeys", "Graphics"),
    454               TRANSLATE_NOOP("Hotkeys", "Toggle PGXP Depth Buffer"), [](s32 pressed) {
    455                 if (!pressed && System::IsValid())
    456                 {
    457                   if (!g_settings.gpu_pgxp_enable)
    458                     return;
    459 
    460                   const Settings old_settings = g_settings;
    461                   g_settings.gpu_pgxp_depth_buffer = !g_settings.gpu_pgxp_depth_buffer;
    462 
    463                   g_gpu->RestoreDeviceContext();
    464                   g_gpu->UpdateSettings(old_settings);
    465                   System::ClearMemorySaveStates();
    466                   Host::AddKeyedOSDMessage("TogglePGXPDepth",
    467                                            g_settings.gpu_pgxp_depth_buffer ?
    468                                              TRANSLATE_STR("OSDMessage", "PGXP Depth Buffer is now enabled.") :
    469                                              TRANSLATE_STR("OSDMessage", "PGXP Depth Buffer is now disabled."),
    470                                            5.0f);
    471                 }
    472               })
    473 
    474 DEFINE_HOTKEY("TogglePGXPCPU", TRANSLATE_NOOP("Hotkeys", "Graphics"), TRANSLATE_NOOP("Hotkeys", "Toggle PGXP CPU Mode"),
    475               [](s32 pressed) {
    476                 if (pressed && System::IsValid())
    477                 {
    478                   if (!g_settings.gpu_pgxp_enable)
    479                     return;
    480 
    481                   const Settings old_settings = g_settings;
    482                   g_settings.gpu_pgxp_cpu = !g_settings.gpu_pgxp_cpu;
    483 
    484                   g_gpu->RestoreDeviceContext();
    485                   g_gpu->UpdateSettings(old_settings);
    486                   System::ClearMemorySaveStates();
    487                   Host::AddKeyedOSDMessage("TogglePGXPCPU",
    488                                            g_settings.gpu_pgxp_cpu ?
    489                                              TRANSLATE_STR("OSDMessage", "PGXP CPU mode is now enabled.") :
    490                                              TRANSLATE_STR("OSDMessage", "PGXP CPU mode is now disabled."),
    491                                            5.0f);
    492 
    493                   CPU::PGXP::Shutdown();
    494                   CPU::PGXP::Initialize();
    495 
    496                   // we need to recompile all blocks if pgxp is toggled on/off
    497                   CPU::CodeCache::Reset();
    498 
    499                   // need to swap interpreters
    500                   System::InterruptExecution();
    501                 }
    502               })
    503 
    504 DEFINE_HOTKEY("ToggleOSD", TRANSLATE_NOOP("Hotkeys", "Graphics"), TRANSLATE_NOOP("Hotkeys", "Toggle On-Screen Display"),
    505               [](s32 pressed) {
    506                 if (!pressed)
    507                   HotkeyToggleOSD();
    508               })
    509 
    510 DEFINE_HOTKEY("RotateClockwise", TRANSLATE_NOOP("Hotkeys", "Graphics"),
    511               TRANSLATE_NOOP("Hotkeys", "Rotate Display Clockwise"), [](s32 pressed) {
    512                 if (!pressed)
    513                 {
    514                   g_settings.display_rotation = static_cast<DisplayRotation>(
    515                     (static_cast<u8>(g_settings.display_rotation) + 1) % static_cast<u8>(DisplayRotation::Count));
    516                 }
    517               })
    518 
    519 DEFINE_HOTKEY("RotateCounterclockwise", TRANSLATE_NOOP("Hotkeys", "Graphics"),
    520               TRANSLATE_NOOP("Hotkeys", "Rotate Display Counterclockwise"), [](s32 pressed) {
    521                 if (!pressed)
    522                 {
    523                   g_settings.display_rotation =
    524                     (g_settings.display_rotation > static_cast<DisplayRotation>(0)) ?
    525                       static_cast<DisplayRotation>((static_cast<u8>(g_settings.display_rotation) - 1) %
    526                                                    static_cast<u8>(DisplayRotation::Count)) :
    527                       static_cast<DisplayRotation>(static_cast<u8>(DisplayRotation::Count) - 1);
    528                 }
    529               })
    530 
    531 DEFINE_HOTKEY("AudioMute", TRANSLATE_NOOP("Hotkeys", "Audio"), TRANSLATE_NOOP("Hotkeys", "Toggle Mute"),
    532               [](s32 pressed) {
    533                 if (!pressed && System::IsValid())
    534                 {
    535                   g_settings.audio_output_muted = !g_settings.audio_output_muted;
    536                   const s32 volume = System::GetAudioOutputVolume();
    537                   SPU::GetOutputStream()->SetOutputVolume(volume);
    538                   if (g_settings.audio_output_muted)
    539                   {
    540                     Host::AddIconOSDMessage("AudioControlHotkey", ICON_EMOJI_MUTED_SPEAKER,
    541                                             TRANSLATE_STR("OSDMessage", "Volume: Muted"), 5.0f);
    542                   }
    543                   else
    544                   {
    545                     Host::AddIconOSDMessage("AudioControlHotkey", ICON_EMOJI_MEDIUM_VOLUME_SPEAKER,
    546                                             fmt::format(TRANSLATE_FS("OSDMessage", "Volume: {}%"), volume), 5.0f);
    547                   }
    548                 }
    549               })
    550 DEFINE_HOTKEY("AudioCDAudioMute", TRANSLATE_NOOP("Hotkeys", "Audio"), TRANSLATE_NOOP("Hotkeys", "Toggle CD Audio Mute"),
    551               [](s32 pressed) {
    552                 if (!pressed && System::IsValid())
    553                 {
    554                   g_settings.cdrom_mute_cd_audio = !g_settings.cdrom_mute_cd_audio;
    555                   Host::AddIconOSDMessage(
    556                     "AudioControlHotkey", g_settings.cdrom_mute_cd_audio ? ICON_EMOJI_MUTED_SPEAKER : ICON_EMOJI_MEDIUM_VOLUME_SPEAKER,
    557                     g_settings.cdrom_mute_cd_audio ? TRANSLATE_STR("OSDMessage", "CD Audio Muted.") :
    558                                                      TRANSLATE_STR("OSDMessage", "CD Audio Unmuted."),
    559                     2.0f);
    560                 }
    561               })
    562 DEFINE_HOTKEY("AudioVolumeUp", TRANSLATE_NOOP("Hotkeys", "Audio"), TRANSLATE_NOOP("Hotkeys", "Volume Up"),
    563               [](s32 pressed) {
    564                 if (!pressed && System::IsValid())
    565                 {
    566                   g_settings.audio_output_muted = false;
    567 
    568                   const s32 volume = std::min<s32>(System::GetAudioOutputVolume() + 10, 200);
    569                   g_settings.audio_output_volume = volume;
    570                   g_settings.audio_fast_forward_volume = volume;
    571                   SPU::GetOutputStream()->SetOutputVolume(volume);
    572                   Host::AddIconOSDMessage("AudioControlHotkey", ICON_EMOJI_HIGH_VOLUME_SPEAKER,
    573                                           fmt::format(TRANSLATE_FS("OSDMessage", "Volume: {}%"), volume), 5.0f);
    574                 }
    575               })
    576 DEFINE_HOTKEY("AudioVolumeDown", TRANSLATE_NOOP("Hotkeys", "Audio"), TRANSLATE_NOOP("Hotkeys", "Volume Down"),
    577               [](s32 pressed) {
    578                 if (!pressed && System::IsValid())
    579                 {
    580                   g_settings.audio_output_muted = false;
    581 
    582                   const s32 volume = std::max<s32>(System::GetAudioOutputVolume() - 10, 0);
    583                   g_settings.audio_output_volume = volume;
    584                   g_settings.audio_fast_forward_volume = volume;
    585                   SPU::GetOutputStream()->SetOutputVolume(volume);
    586                   Host::AddIconOSDMessage("AudioControlHotkey", ICON_EMOJI_MEDIUM_VOLUME_SPEAKER,
    587                                           fmt::format(TRANSLATE_FS("OSDMessage", "Volume: {}%"), volume), 5.0f);
    588                 }
    589               })
    590 
    591 // NOTE: All save/load state hotkeys are deferred, because it can trigger setting reapply, which reloads bindings.
    592 DEFINE_HOTKEY("LoadSelectedSaveState", TRANSLATE_NOOP("Hotkeys", "Save States"),
    593               TRANSLATE_NOOP("Hotkeys", "Load From Selected Slot"), [](s32 pressed) {
    594                 if (!pressed)
    595                   Host::RunOnCPUThread(SaveStateSelectorUI::LoadCurrentSlot);
    596               })
    597 DEFINE_HOTKEY("SaveSelectedSaveState", TRANSLATE_NOOP("Hotkeys", "Save States"),
    598               TRANSLATE_NOOP("Hotkeys", "Save To Selected Slot"), [](s32 pressed) {
    599                 if (!pressed)
    600                   Host::RunOnCPUThread(SaveStateSelectorUI::SaveCurrentSlot);
    601               })
    602 DEFINE_HOTKEY("SelectPreviousSaveStateSlot", TRANSLATE_NOOP("Hotkeys", "Save States"),
    603               TRANSLATE_NOOP("Hotkeys", "Select Previous Save Slot"), [](s32 pressed) {
    604                 if (!pressed)
    605                   Host::RunOnCPUThread([]() { SaveStateSelectorUI::SelectPreviousSlot(true); });
    606               })
    607 DEFINE_HOTKEY("SelectNextSaveStateSlot", TRANSLATE_NOOP("Hotkeys", "Save States"),
    608               TRANSLATE_NOOP("Hotkeys", "Select Next Save Slot"), [](s32 pressed) {
    609                 if (!pressed)
    610                   Host::RunOnCPUThread([]() { SaveStateSelectorUI::SelectNextSlot(true); });
    611               })
    612 DEFINE_HOTKEY("SaveStateAndSelectNextSlot", TRANSLATE_NOOP("Hotkeys", "Save States"),
    613               TRANSLATE_NOOP("Hotkeys", "Save State and Select Next Slot"), [](s32 pressed) {
    614                 if (!pressed && System::IsValid())
    615                 {
    616                   SaveStateSelectorUI::SaveCurrentSlot();
    617                   SaveStateSelectorUI::SelectNextSlot(false);
    618                 }
    619               })
    620 
    621 DEFINE_HOTKEY("UndoLoadState", TRANSLATE_NOOP("Hotkeys", "Save States"), TRANSLATE_NOOP("Hotkeys", "Undo Load State"),
    622               [](s32 pressed) {
    623                 if (!pressed)
    624                   Host::RunOnCPUThread(System::UndoLoadState);
    625               })
    626 
    627 #define MAKE_LOAD_STATE_HOTKEY(global, slot, name)                                                                     \
    628   DEFINE_HOTKEY(global ? "LoadGameState" #slot : "LoadGlobalState" #slot, TRANSLATE_NOOP("Hotkeys", "Save States"),    \
    629                 name, [](s32 pressed) {                                                                                \
    630                   if (!pressed)                                                                                        \
    631                     Host::RunOnCPUThread([]() { HotkeyLoadStateSlot(global, slot); });                                 \
    632                 })
    633 #define MAKE_SAVE_STATE_HOTKEY(global, slot, name)                                                                     \
    634   DEFINE_HOTKEY(global ? "SaveGameState" #slot : "SaveGlobalState" #slot, TRANSLATE_NOOP("Hotkeys", "Save States"),    \
    635                 name, [](s32 pressed) {                                                                                \
    636                   if (!pressed)                                                                                        \
    637                     Host::RunOnCPUThread([]() { HotkeySaveStateSlot(global, slot); });                                 \
    638                 })
    639 
    640 // clang-format off
    641 MAKE_LOAD_STATE_HOTKEY(false, 1, TRANSLATE_NOOP("Hotkeys", "Load Game State 1"))
    642 MAKE_SAVE_STATE_HOTKEY(false, 1, TRANSLATE_NOOP("Hotkeys", "Save Game State 1"))
    643 MAKE_LOAD_STATE_HOTKEY(false, 2, TRANSLATE_NOOP("Hotkeys", "Load Game State 2"))
    644 MAKE_SAVE_STATE_HOTKEY(false, 2, TRANSLATE_NOOP("Hotkeys", "Save Game State 2"))
    645 MAKE_LOAD_STATE_HOTKEY(false, 3, TRANSLATE_NOOP("Hotkeys", "Load Game State 3"))
    646 MAKE_SAVE_STATE_HOTKEY(false, 3, TRANSLATE_NOOP("Hotkeys", "Save Game State 3"))
    647 MAKE_LOAD_STATE_HOTKEY(false, 4, TRANSLATE_NOOP("Hotkeys", "Load Game State 4"))
    648 MAKE_SAVE_STATE_HOTKEY(false, 4, TRANSLATE_NOOP("Hotkeys", "Save Game State 4"))
    649 MAKE_LOAD_STATE_HOTKEY(false, 5, TRANSLATE_NOOP("Hotkeys", "Load Game State 5"))
    650 MAKE_SAVE_STATE_HOTKEY(false, 5, TRANSLATE_NOOP("Hotkeys", "Save Game State 5"))
    651 MAKE_LOAD_STATE_HOTKEY(false, 6, TRANSLATE_NOOP("Hotkeys", "Load Game State 6"))
    652 MAKE_SAVE_STATE_HOTKEY(false, 6, TRANSLATE_NOOP("Hotkeys", "Save Game State 6"))
    653 MAKE_LOAD_STATE_HOTKEY(false, 7, TRANSLATE_NOOP("Hotkeys", "Load Game State 7"))
    654 MAKE_SAVE_STATE_HOTKEY(false, 7, TRANSLATE_NOOP("Hotkeys", "Save Game State 7"))
    655 MAKE_LOAD_STATE_HOTKEY(false, 8, TRANSLATE_NOOP("Hotkeys", "Load Game State 8"))
    656 MAKE_SAVE_STATE_HOTKEY(false, 8, TRANSLATE_NOOP("Hotkeys", "Save Game State 8"))
    657 MAKE_LOAD_STATE_HOTKEY(false, 9, TRANSLATE_NOOP("Hotkeys", "Load Game State 9"))
    658 MAKE_SAVE_STATE_HOTKEY(false, 9, TRANSLATE_NOOP("Hotkeys", "Save Game State 9"))
    659 MAKE_LOAD_STATE_HOTKEY(false, 10, TRANSLATE_NOOP("Hotkeys", "Load Game State 10"))
    660 MAKE_SAVE_STATE_HOTKEY(false, 10, TRANSLATE_NOOP("Hotkeys", "Save Game State 10"))
    661 
    662 MAKE_LOAD_STATE_HOTKEY(true, 1, TRANSLATE_NOOP("Hotkeys", "Load Global State 1"))
    663 MAKE_SAVE_STATE_HOTKEY(true, 1, TRANSLATE_NOOP("Hotkeys", "Save Global State 1"))
    664 MAKE_LOAD_STATE_HOTKEY(true, 2, TRANSLATE_NOOP("Hotkeys", "Load Global State 2"))
    665 MAKE_SAVE_STATE_HOTKEY(true, 2, TRANSLATE_NOOP("Hotkeys", "Save Global State 2"))
    666 MAKE_LOAD_STATE_HOTKEY(true, 3, TRANSLATE_NOOP("Hotkeys", "Load Global State 3"))
    667 MAKE_SAVE_STATE_HOTKEY(true, 3, TRANSLATE_NOOP("Hotkeys", "Save Global State 3"))
    668 MAKE_LOAD_STATE_HOTKEY(true, 4, TRANSLATE_NOOP("Hotkeys", "Load Global State 4"))
    669 MAKE_SAVE_STATE_HOTKEY(true, 4, TRANSLATE_NOOP("Hotkeys", "Save Global State 4"))
    670 MAKE_LOAD_STATE_HOTKEY(true, 5, TRANSLATE_NOOP("Hotkeys", "Load Global State 5"))
    671 MAKE_SAVE_STATE_HOTKEY(true, 5, TRANSLATE_NOOP("Hotkeys", "Save Global State 5"))
    672 MAKE_LOAD_STATE_HOTKEY(true, 6, TRANSLATE_NOOP("Hotkeys", "Load Global State 6"))
    673 MAKE_SAVE_STATE_HOTKEY(true, 6, TRANSLATE_NOOP("Hotkeys", "Save Global State 6"))
    674 MAKE_LOAD_STATE_HOTKEY(true, 7, TRANSLATE_NOOP("Hotkeys", "Load Global State 7"))
    675 MAKE_SAVE_STATE_HOTKEY(true, 7, TRANSLATE_NOOP("Hotkeys", "Save Global State 7"))
    676 MAKE_LOAD_STATE_HOTKEY(true, 8, TRANSLATE_NOOP("Hotkeys", "Load Global State 8"))
    677 MAKE_SAVE_STATE_HOTKEY(true, 8, TRANSLATE_NOOP("Hotkeys", "Save Global State 8"))
    678 MAKE_LOAD_STATE_HOTKEY(true, 9, TRANSLATE_NOOP("Hotkeys", "Load Global State 9"))
    679 MAKE_SAVE_STATE_HOTKEY(true, 9, TRANSLATE_NOOP("Hotkeys", "Save Global State 9"))
    680 MAKE_LOAD_STATE_HOTKEY(true, 10, TRANSLATE_NOOP("Hotkeys", "Load Global State 10"))
    681 MAKE_SAVE_STATE_HOTKEY(true, 10, TRANSLATE_NOOP("Hotkeys", "Save Global State 10"))
    682 // clang-format on
    683 
    684 #undef MAKE_SAVE_STATE_HOTKEY
    685 #undef MAKE_LOAD_STATE_HOTKEY
    686 
    687 END_HOTKEY_LIST()