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()