HotkeyScheduler.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730
  1. // Copyright 2017 Dolphin Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "DolphinQt/HotkeyScheduler.h"
  4. #include <algorithm>
  5. #include <cmath>
  6. #include <thread>
  7. #include <fmt/format.h>
  8. #include <QApplication>
  9. #include <QCoreApplication>
  10. #include "AudioCommon/AudioCommon.h"
  11. #include "Common/Config/Config.h"
  12. #include "Common/Thread.h"
  13. #include "Core/AchievementManager.h"
  14. #include "Core/Config/AchievementSettings.h"
  15. #include "Core/Config/FreeLookSettings.h"
  16. #include "Core/Config/GraphicsSettings.h"
  17. #include "Core/Config/MainSettings.h"
  18. #include "Core/Config/UISettings.h"
  19. #include "Core/Core.h"
  20. #include "Core/FreeLookManager.h"
  21. #include "Core/Host.h"
  22. #include "Core/HotkeyManager.h"
  23. #include "Core/IOS/IOS.h"
  24. #include "Core/IOS/USB/Bluetooth/BTBase.h"
  25. #include "Core/IOS/USB/Bluetooth/BTReal.h"
  26. #include "Core/State.h"
  27. #include "Core/System.h"
  28. #include "Core/WiiUtils.h"
  29. #ifdef HAS_LIBMGBA
  30. #include "DolphinQt/GBAWidget.h"
  31. #endif
  32. #include "DolphinQt/QtUtils/QueueOnObject.h"
  33. #include "DolphinQt/Settings.h"
  34. #include "InputCommon/ControlReference/ControlReference.h"
  35. #include "InputCommon/ControllerInterface/ControllerInterface.h"
  36. #include "VideoCommon/OnScreenDisplay.h"
  37. #include "VideoCommon/VertexShaderManager.h"
  38. #include "VideoCommon/VideoConfig.h"
  39. constexpr const char* DUBOIS_ALGORITHM_SHADER = "dubois";
  40. HotkeyScheduler::HotkeyScheduler() : m_stop_requested(false)
  41. {
  42. HotkeyManagerEmu::Enable(true);
  43. }
  44. HotkeyScheduler::~HotkeyScheduler()
  45. {
  46. Stop();
  47. }
  48. void HotkeyScheduler::Start()
  49. {
  50. m_stop_requested.Set(false);
  51. m_thread = std::thread(&HotkeyScheduler::Run, this);
  52. }
  53. void HotkeyScheduler::Stop()
  54. {
  55. m_stop_requested.Set(true);
  56. if (m_thread.joinable())
  57. m_thread.join();
  58. }
  59. static bool IsHotkey(int id, bool held = false)
  60. {
  61. return HotkeyManagerEmu::IsPressed(id, held);
  62. }
  63. static void HandleFrameStepHotkeys()
  64. {
  65. constexpr int MAX_FRAME_STEP_DELAY = 60;
  66. constexpr int FRAME_STEP_DELAY = 30;
  67. static int frame_step_count = 0;
  68. static int frame_step_delay = 1;
  69. static int frame_step_delay_count = 0;
  70. static bool frame_step_hold = false;
  71. if (IsHotkey(HK_FRAME_ADVANCE_INCREASE_SPEED))
  72. {
  73. frame_step_delay = std::max(frame_step_delay - 1, 0);
  74. return;
  75. }
  76. if (IsHotkey(HK_FRAME_ADVANCE_DECREASE_SPEED))
  77. {
  78. frame_step_delay = std::min(frame_step_delay + 1, MAX_FRAME_STEP_DELAY);
  79. return;
  80. }
  81. if (IsHotkey(HK_FRAME_ADVANCE_RESET_SPEED))
  82. {
  83. frame_step_delay = 1;
  84. return;
  85. }
  86. if (IsHotkey(HK_FRAME_ADVANCE, true))
  87. {
  88. if (frame_step_delay_count < frame_step_delay && frame_step_hold)
  89. frame_step_delay_count++;
  90. if ((frame_step_count == 0 || frame_step_count == FRAME_STEP_DELAY) && !frame_step_hold)
  91. {
  92. if (frame_step_count > 0)
  93. Settings::Instance().SetIsContinuouslyFrameStepping(true);
  94. Core::QueueHostJob([](auto& system) { Core::DoFrameStep(system); });
  95. frame_step_hold = true;
  96. }
  97. if (frame_step_count < FRAME_STEP_DELAY)
  98. {
  99. frame_step_count++;
  100. frame_step_hold = false;
  101. }
  102. if (frame_step_count == FRAME_STEP_DELAY && frame_step_hold &&
  103. frame_step_delay_count >= frame_step_delay)
  104. {
  105. frame_step_hold = false;
  106. frame_step_delay_count = 0;
  107. }
  108. return;
  109. }
  110. else if (frame_step_count > 0)
  111. {
  112. // Reset frame advance
  113. frame_step_count = 0;
  114. frame_step_hold = false;
  115. frame_step_delay_count = 0;
  116. Settings::Instance().SetIsContinuouslyFrameStepping(false);
  117. emit Settings::Instance().EmulationStateChanged(Core::GetState(Core::System::GetInstance()));
  118. }
  119. }
  120. void HotkeyScheduler::Run()
  121. {
  122. Common::SetCurrentThreadName("HotkeyScheduler");
  123. while (!m_stop_requested.IsSet())
  124. {
  125. Common::SleepCurrentThread(5);
  126. g_controller_interface.SetCurrentInputChannel(ciface::InputChannel::FreeLook);
  127. g_controller_interface.UpdateInput();
  128. FreeLook::UpdateInput();
  129. g_controller_interface.SetCurrentInputChannel(ciface::InputChannel::Host);
  130. g_controller_interface.UpdateInput();
  131. if (!HotkeyManagerEmu::IsEnabled())
  132. continue;
  133. Core::System& system = Core::System::GetInstance();
  134. if (Core::GetState(system) != Core::State::Stopping)
  135. {
  136. // Obey window focus (config permitting) before checking hotkeys.
  137. Core::UpdateInputGate(Config::Get(Config::MAIN_FOCUSED_HOTKEYS));
  138. HotkeyManagerEmu::GetStatus(false);
  139. // Everything else on the host thread (controller config dialog) should always get input.
  140. ControlReference::SetInputGate(true);
  141. HotkeyManagerEmu::GetStatus(true);
  142. // Open
  143. if (IsHotkey(HK_OPEN))
  144. emit Open();
  145. // Refresh Game List
  146. if (IsHotkey(HK_REFRESH_LIST))
  147. emit RefreshGameListHotkey();
  148. // Recording
  149. if (IsHotkey(HK_START_RECORDING))
  150. emit StartRecording();
  151. // Exit
  152. if (IsHotkey(HK_EXIT))
  153. emit ExitHotkey();
  154. #ifdef USE_RETRO_ACHIEVEMENTS
  155. if (IsHotkey(HK_OPEN_ACHIEVEMENTS))
  156. emit OpenAchievements();
  157. #endif // USE_RETRO_ACHIEVEMENTS
  158. if (Core::IsUninitialized(system))
  159. {
  160. // Only check for Play Recording hotkey when no game is running
  161. if (IsHotkey(HK_PLAY_RECORDING))
  162. emit PlayRecording();
  163. continue;
  164. }
  165. // Disc
  166. if (IsHotkey(HK_EJECT_DISC))
  167. emit EjectDisc();
  168. if (IsHotkey(HK_CHANGE_DISC))
  169. emit ChangeDisc();
  170. // Fullscreen
  171. if (IsHotkey(HK_FULLSCREEN))
  172. {
  173. emit FullScreenHotkey();
  174. // Prevent fullscreen from getting toggled too often
  175. Common::SleepCurrentThread(100);
  176. }
  177. // Pause and Unpause
  178. if (IsHotkey(HK_PLAY_PAUSE))
  179. emit TogglePauseHotkey();
  180. // Stop
  181. if (IsHotkey(HK_STOP))
  182. emit StopHotkey();
  183. // Reset
  184. if (IsHotkey(HK_RESET))
  185. emit ResetHotkey();
  186. // Frame advance
  187. HandleFrameStepHotkeys();
  188. // Screenshot
  189. if (IsHotkey(HK_SCREENSHOT))
  190. emit ScreenShotHotkey();
  191. // Unlock Cursor
  192. if (IsHotkey(HK_UNLOCK_CURSOR))
  193. emit UnlockCursor();
  194. if (IsHotkey(HK_CENTER_MOUSE, true))
  195. g_controller_interface.SetMouseCenteringRequested(true);
  196. auto& settings = Settings::Instance();
  197. // Toggle Chat
  198. if (IsHotkey(HK_ACTIVATE_CHAT))
  199. emit ActivateChat();
  200. if (IsHotkey(HK_REQUEST_GOLF_CONTROL))
  201. emit RequestGolfControl();
  202. if (IsHotkey(HK_EXPORT_RECORDING))
  203. emit ExportRecording();
  204. if (IsHotkey(HK_READ_ONLY_MODE))
  205. emit ToggleReadOnlyMode();
  206. // Wiimote
  207. if (auto bt = WiiUtils::GetBluetoothRealDevice())
  208. bt->UpdateSyncButtonState(IsHotkey(HK_TRIGGER_SYNC_BUTTON, true));
  209. if (Config::IsDebuggingEnabled())
  210. {
  211. CheckDebuggingHotkeys();
  212. }
  213. // TODO: HK_MBP_ADD
  214. if (Core::System::GetInstance().IsWii())
  215. {
  216. if (IsHotkey(HK_WIIMOTE1_CONNECT))
  217. emit ConnectWiiRemote(0);
  218. if (IsHotkey(HK_WIIMOTE2_CONNECT))
  219. emit ConnectWiiRemote(1);
  220. if (IsHotkey(HK_WIIMOTE3_CONNECT))
  221. emit ConnectWiiRemote(2);
  222. if (IsHotkey(HK_WIIMOTE4_CONNECT))
  223. emit ConnectWiiRemote(3);
  224. if (IsHotkey(HK_BALANCEBOARD_CONNECT))
  225. emit ConnectWiiRemote(4);
  226. if (IsHotkey(HK_TOGGLE_SD_CARD))
  227. Settings::Instance().SetSDCardInserted(!Settings::Instance().IsSDCardInserted());
  228. if (IsHotkey(HK_TOGGLE_USB_KEYBOARD))
  229. {
  230. Settings::Instance().SetUSBKeyboardConnected(
  231. !Settings::Instance().IsUSBKeyboardConnected());
  232. }
  233. }
  234. if (IsHotkey(HK_PREV_WIIMOTE_PROFILE_1))
  235. m_profile_cycler.PreviousWiimoteProfile(0);
  236. else if (IsHotkey(HK_NEXT_WIIMOTE_PROFILE_1))
  237. m_profile_cycler.NextWiimoteProfile(0);
  238. if (IsHotkey(HK_PREV_WIIMOTE_PROFILE_2))
  239. m_profile_cycler.PreviousWiimoteProfile(1);
  240. else if (IsHotkey(HK_NEXT_WIIMOTE_PROFILE_2))
  241. m_profile_cycler.NextWiimoteProfile(1);
  242. if (IsHotkey(HK_PREV_WIIMOTE_PROFILE_3))
  243. m_profile_cycler.PreviousWiimoteProfile(2);
  244. else if (IsHotkey(HK_NEXT_WIIMOTE_PROFILE_3))
  245. m_profile_cycler.NextWiimoteProfile(2);
  246. if (IsHotkey(HK_PREV_WIIMOTE_PROFILE_4))
  247. m_profile_cycler.PreviousWiimoteProfile(3);
  248. else if (IsHotkey(HK_NEXT_WIIMOTE_PROFILE_4))
  249. m_profile_cycler.NextWiimoteProfile(3);
  250. if (IsHotkey(HK_PREV_GAME_WIIMOTE_PROFILE_1))
  251. m_profile_cycler.PreviousWiimoteProfileForGame(0);
  252. else if (IsHotkey(HK_NEXT_GAME_WIIMOTE_PROFILE_1))
  253. m_profile_cycler.NextWiimoteProfileForGame(0);
  254. if (IsHotkey(HK_PREV_GAME_WIIMOTE_PROFILE_2))
  255. m_profile_cycler.PreviousWiimoteProfileForGame(1);
  256. else if (IsHotkey(HK_NEXT_GAME_WIIMOTE_PROFILE_2))
  257. m_profile_cycler.NextWiimoteProfileForGame(1);
  258. if (IsHotkey(HK_PREV_GAME_WIIMOTE_PROFILE_3))
  259. m_profile_cycler.PreviousWiimoteProfileForGame(2);
  260. else if (IsHotkey(HK_NEXT_GAME_WIIMOTE_PROFILE_3))
  261. m_profile_cycler.NextWiimoteProfileForGame(2);
  262. if (IsHotkey(HK_PREV_GAME_WIIMOTE_PROFILE_4))
  263. m_profile_cycler.PreviousWiimoteProfileForGame(3);
  264. else if (IsHotkey(HK_NEXT_GAME_WIIMOTE_PROFILE_4))
  265. m_profile_cycler.NextWiimoteProfileForGame(3);
  266. auto ShowVolume = []() {
  267. OSD::AddMessage(std::string("Volume: ") +
  268. (Config::Get(Config::MAIN_AUDIO_MUTED) ?
  269. "Muted" :
  270. std::to_string(Config::Get(Config::MAIN_AUDIO_VOLUME)) + "%"));
  271. };
  272. // Volume
  273. if (IsHotkey(HK_VOLUME_DOWN))
  274. {
  275. settings.DecreaseVolume(3);
  276. ShowVolume();
  277. }
  278. if (IsHotkey(HK_VOLUME_UP))
  279. {
  280. settings.IncreaseVolume(3);
  281. ShowVolume();
  282. }
  283. if (IsHotkey(HK_VOLUME_TOGGLE_MUTE))
  284. {
  285. AudioCommon::ToggleMuteVolume(system);
  286. ShowVolume();
  287. }
  288. // Graphics
  289. const auto efb_scale = Config::Get(Config::GFX_EFB_SCALE);
  290. const auto ShowEFBScale = [](int new_efb_scale) {
  291. switch (new_efb_scale)
  292. {
  293. case EFB_SCALE_AUTO_INTEGRAL:
  294. OSD::AddMessage("Internal Resolution: Auto (integral)");
  295. break;
  296. case 1:
  297. OSD::AddMessage("Internal Resolution: Native");
  298. break;
  299. default:
  300. OSD::AddMessage(fmt::format("Internal Resolution: {}x", new_efb_scale));
  301. break;
  302. }
  303. };
  304. if (IsHotkey(HK_INCREASE_IR))
  305. {
  306. Config::SetCurrent(Config::GFX_EFB_SCALE, efb_scale + 1);
  307. ShowEFBScale(efb_scale + 1);
  308. }
  309. if (IsHotkey(HK_DECREASE_IR))
  310. {
  311. if (efb_scale > EFB_SCALE_AUTO_INTEGRAL)
  312. {
  313. Config::SetCurrent(Config::GFX_EFB_SCALE, efb_scale - 1);
  314. ShowEFBScale(efb_scale - 1);
  315. }
  316. }
  317. if (IsHotkey(HK_TOGGLE_CROP))
  318. Config::SetCurrent(Config::GFX_CROP, !Config::Get(Config::GFX_CROP));
  319. if (IsHotkey(HK_TOGGLE_AR))
  320. {
  321. const int aspect_ratio = (static_cast<int>(Config::Get(Config::GFX_ASPECT_RATIO)) + 1) & 3;
  322. Config::SetCurrent(Config::GFX_ASPECT_RATIO, static_cast<AspectMode>(aspect_ratio));
  323. switch (static_cast<AspectMode>(aspect_ratio))
  324. {
  325. case AspectMode::Stretch:
  326. OSD::AddMessage("Stretch");
  327. break;
  328. case AspectMode::ForceStandard:
  329. OSD::AddMessage("Force 4:3");
  330. break;
  331. case AspectMode::ForceWide:
  332. OSD::AddMessage("Force 16:9");
  333. break;
  334. case AspectMode::Custom:
  335. OSD::AddMessage("Custom");
  336. break;
  337. case AspectMode::CustomStretch:
  338. OSD::AddMessage("Custom (Stretch)");
  339. break;
  340. case AspectMode::Raw:
  341. OSD::AddMessage("Raw (Square Pixels)");
  342. break;
  343. case AspectMode::Auto:
  344. default:
  345. OSD::AddMessage("Auto");
  346. break;
  347. }
  348. }
  349. if (IsHotkey(HK_TOGGLE_SKIP_EFB_ACCESS))
  350. {
  351. const bool new_value = !Config::Get(Config::GFX_HACK_EFB_ACCESS_ENABLE);
  352. Config::SetCurrent(Config::GFX_HACK_EFB_ACCESS_ENABLE, new_value);
  353. OSD::AddMessage(fmt::format("{} EFB Access from CPU", new_value ? "Skip" : "Don't skip"));
  354. }
  355. if (IsHotkey(HK_TOGGLE_EFBCOPIES))
  356. {
  357. const bool new_value = !Config::Get(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM);
  358. Config::SetCurrent(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM, new_value);
  359. OSD::AddMessage(fmt::format("Copy EFB: {}", new_value ? "to Texture" : "to RAM"));
  360. }
  361. auto ShowXFBCopies = []() {
  362. OSD::AddMessage(fmt::format(
  363. "Copy XFB: {}{}", Config::Get(Config::GFX_HACK_IMMEDIATE_XFB) ? " (Immediate)" : "",
  364. Config::Get(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM) ? "to Texture" : "to RAM"));
  365. };
  366. if (IsHotkey(HK_TOGGLE_XFBCOPIES))
  367. {
  368. Config::SetCurrent(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM,
  369. !Config::Get(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM));
  370. ShowXFBCopies();
  371. }
  372. if (IsHotkey(HK_TOGGLE_IMMEDIATE_XFB))
  373. {
  374. Config::SetCurrent(Config::GFX_HACK_IMMEDIATE_XFB,
  375. !Config::Get(Config::GFX_HACK_IMMEDIATE_XFB));
  376. ShowXFBCopies();
  377. }
  378. if (IsHotkey(HK_TOGGLE_FOG))
  379. {
  380. const bool new_value = !Config::Get(Config::GFX_DISABLE_FOG);
  381. Config::SetCurrent(Config::GFX_DISABLE_FOG, new_value);
  382. OSD::AddMessage(fmt::format("Fog: {}", new_value ? "Enabled" : "Disabled"));
  383. }
  384. if (IsHotkey(HK_TOGGLE_DUMPTEXTURES))
  385. {
  386. const bool enable_dumping = !Config::Get(Config::GFX_DUMP_TEXTURES);
  387. Config::SetCurrent(Config::GFX_DUMP_TEXTURES, enable_dumping);
  388. OSD::AddMessage(
  389. fmt::format("Texture Dumping {}",
  390. enable_dumping ? "enabled. This will reduce performance." : "disabled."),
  391. OSD::Duration::NORMAL);
  392. }
  393. if (IsHotkey(HK_TOGGLE_TEXTURES))
  394. Config::SetCurrent(Config::GFX_HIRES_TEXTURES, !Config::Get(Config::GFX_HIRES_TEXTURES));
  395. Core::SetIsThrottlerTempDisabled(IsHotkey(HK_TOGGLE_THROTTLE, true));
  396. if (IsHotkey(HK_TOGGLE_THROTTLE, true) && !Config::Get(Config::MAIN_AUDIO_MUTED) &&
  397. Config::Get(Config::MAIN_AUDIO_MUTE_ON_DISABLED_SPEED_LIMIT))
  398. {
  399. Config::SetCurrent(Config::MAIN_AUDIO_MUTED, true);
  400. AudioCommon::UpdateSoundStream(system);
  401. }
  402. else if (!IsHotkey(HK_TOGGLE_THROTTLE, true) && Config::Get(Config::MAIN_AUDIO_MUTED) &&
  403. Config::GetActiveLayerForConfig(Config::MAIN_AUDIO_MUTED) ==
  404. Config::LayerType::CurrentRun)
  405. {
  406. Config::DeleteKey(Config::LayerType::CurrentRun, Config::MAIN_AUDIO_MUTED);
  407. AudioCommon::UpdateSoundStream(system);
  408. }
  409. auto ShowEmulationSpeed = []() {
  410. const float emulation_speed = Config::Get(Config::MAIN_EMULATION_SPEED);
  411. if (!AchievementManager::GetInstance().IsHardcoreModeActive() ||
  412. Config::Get(Config::MAIN_EMULATION_SPEED) >= 1.0f ||
  413. Config::Get(Config::MAIN_EMULATION_SPEED) <= 0.0f)
  414. {
  415. OSD::AddMessage(emulation_speed <= 0 ? "Speed Limit: Unlimited" :
  416. fmt::format("Speed Limit: {}%",
  417. std::lround(emulation_speed * 100.f)));
  418. }
  419. };
  420. if (IsHotkey(HK_DECREASE_EMULATION_SPEED))
  421. {
  422. auto speed = Config::Get(Config::MAIN_EMULATION_SPEED) - 0.1;
  423. if (speed > 0)
  424. {
  425. speed = (speed >= 0.95 && speed <= 1.05) ? 1.0 : speed;
  426. Config::SetCurrent(Config::MAIN_EMULATION_SPEED, speed);
  427. }
  428. ShowEmulationSpeed();
  429. }
  430. if (IsHotkey(HK_INCREASE_EMULATION_SPEED))
  431. {
  432. auto speed = Config::Get(Config::MAIN_EMULATION_SPEED) + 0.1;
  433. speed = (speed >= 0.95 && speed <= 1.05) ? 1.0 : speed;
  434. Config::SetCurrent(Config::MAIN_EMULATION_SPEED, speed);
  435. ShowEmulationSpeed();
  436. }
  437. // USB Device Emulation
  438. if (IsHotkey(HK_SKYLANDERS_PORTAL))
  439. emit SkylandersPortalHotkey();
  440. if (IsHotkey(HK_INFINITY_BASE))
  441. emit InfinityBaseHotkey();
  442. // Slot Saving / Loading
  443. if (IsHotkey(HK_SAVE_STATE_SLOT_SELECTED))
  444. emit StateSaveSlotHotkey();
  445. if (IsHotkey(HK_LOAD_STATE_SLOT_SELECTED))
  446. emit StateLoadSlotHotkey();
  447. if (IsHotkey(HK_INCREMENT_SELECTED_STATE_SLOT))
  448. emit IncrementSelectedStateSlotHotkey();
  449. if (IsHotkey(HK_DECREMENT_SELECTED_STATE_SLOT))
  450. emit DecrementSelectedStateSlotHotkey();
  451. // Stereoscopy
  452. if (IsHotkey(HK_TOGGLE_STEREO_SBS))
  453. {
  454. if (Config::Get(Config::GFX_STEREO_MODE) != StereoMode::SBS)
  455. {
  456. // Disable post-processing shader, as stereoscopy itself is currently a shader
  457. if (Config::Get(Config::GFX_ENHANCE_POST_SHADER) == DUBOIS_ALGORITHM_SHADER)
  458. Config::SetCurrent(Config::GFX_ENHANCE_POST_SHADER, "");
  459. Config::SetCurrent(Config::GFX_STEREO_MODE, StereoMode::SBS);
  460. }
  461. else
  462. {
  463. Config::SetCurrent(Config::GFX_STEREO_MODE, StereoMode::Off);
  464. }
  465. }
  466. if (IsHotkey(HK_TOGGLE_STEREO_TAB))
  467. {
  468. if (Config::Get(Config::GFX_STEREO_MODE) != StereoMode::TAB)
  469. {
  470. // Disable post-processing shader, as stereoscopy itself is currently a shader
  471. if (Config::Get(Config::GFX_ENHANCE_POST_SHADER) == DUBOIS_ALGORITHM_SHADER)
  472. Config::SetCurrent(Config::GFX_ENHANCE_POST_SHADER, "");
  473. Config::SetCurrent(Config::GFX_STEREO_MODE, StereoMode::TAB);
  474. }
  475. else
  476. {
  477. Config::SetCurrent(Config::GFX_STEREO_MODE, StereoMode::Off);
  478. }
  479. }
  480. if (IsHotkey(HK_TOGGLE_STEREO_ANAGLYPH))
  481. {
  482. if (Config::Get(Config::GFX_STEREO_MODE) != StereoMode::Anaglyph)
  483. {
  484. Config::SetCurrent(Config::GFX_STEREO_MODE, StereoMode::Anaglyph);
  485. Config::SetCurrent(Config::GFX_ENHANCE_POST_SHADER, DUBOIS_ALGORITHM_SHADER);
  486. }
  487. else
  488. {
  489. Config::SetCurrent(Config::GFX_STEREO_MODE, StereoMode::Off);
  490. Config::SetCurrent(Config::GFX_ENHANCE_POST_SHADER, "");
  491. }
  492. }
  493. CheckGBAHotkeys();
  494. }
  495. const auto stereo_depth = Config::Get(Config::GFX_STEREO_DEPTH);
  496. if (IsHotkey(HK_DECREASE_DEPTH, true))
  497. Config::SetCurrent(Config::GFX_STEREO_DEPTH, std::max(stereo_depth - 1, 0));
  498. if (IsHotkey(HK_INCREASE_DEPTH, true))
  499. Config::SetCurrent(Config::GFX_STEREO_DEPTH,
  500. std::min(stereo_depth + 1, Config::GFX_STEREO_DEPTH_MAXIMUM));
  501. const auto stereo_convergence = Config::Get(Config::GFX_STEREO_CONVERGENCE);
  502. if (IsHotkey(HK_DECREASE_CONVERGENCE, true))
  503. Config::SetCurrent(Config::GFX_STEREO_CONVERGENCE, std::max(stereo_convergence - 5, 0));
  504. if (IsHotkey(HK_INCREASE_CONVERGENCE, true))
  505. Config::SetCurrent(Config::GFX_STEREO_CONVERGENCE,
  506. std::min(stereo_convergence + 5, Config::GFX_STEREO_CONVERGENCE_MAXIMUM));
  507. // Free Look
  508. if (IsHotkey(HK_FREELOOK_TOGGLE))
  509. {
  510. const bool new_value = !Config::Get(Config::FREE_LOOK_ENABLED);
  511. Config::SetCurrent(Config::FREE_LOOK_ENABLED, new_value);
  512. const bool hardcore = AchievementManager::GetInstance().IsHardcoreModeActive();
  513. if (hardcore)
  514. OSD::AddMessage("Free Look is Disabled in Hardcore Mode");
  515. else
  516. OSD::AddMessage(fmt::format("Free Look: {}", new_value ? "Enabled" : "Disabled"));
  517. }
  518. // Savestates
  519. for (u32 i = 0; i < State::NUM_STATES; i++)
  520. {
  521. if (IsHotkey(HK_LOAD_STATE_SLOT_1 + i))
  522. emit StateLoadSlot(i + 1);
  523. if (IsHotkey(HK_SAVE_STATE_SLOT_1 + i))
  524. emit StateSaveSlot(i + 1);
  525. if (IsHotkey(HK_LOAD_LAST_STATE_1 + i))
  526. emit StateLoadLastSaved(i + 1);
  527. if (IsHotkey(HK_SELECT_STATE_SLOT_1 + i))
  528. emit SetStateSlotHotkey(i + 1);
  529. }
  530. if (IsHotkey(HK_SAVE_FIRST_STATE))
  531. emit StateSaveOldest();
  532. if (IsHotkey(HK_UNDO_LOAD_STATE))
  533. emit StateLoadUndo();
  534. if (IsHotkey(HK_UNDO_SAVE_STATE))
  535. emit StateSaveUndo();
  536. if (IsHotkey(HK_LOAD_STATE_FILE))
  537. emit StateLoadFile();
  538. if (IsHotkey(HK_SAVE_STATE_FILE))
  539. emit StateSaveFile();
  540. }
  541. }
  542. void HotkeyScheduler::CheckDebuggingHotkeys()
  543. {
  544. if (IsHotkey(HK_STEP))
  545. emit Step();
  546. if (IsHotkey(HK_STEP_OVER))
  547. emit StepOver();
  548. if (IsHotkey(HK_STEP_OUT))
  549. emit StepOut();
  550. if (IsHotkey(HK_SKIP))
  551. emit Skip();
  552. if (IsHotkey(HK_SHOW_PC))
  553. emit ShowPC();
  554. if (IsHotkey(HK_SET_PC))
  555. emit Skip();
  556. if (IsHotkey(HK_BP_TOGGLE))
  557. emit ToggleBreakpoint();
  558. if (IsHotkey(HK_BP_ADD))
  559. emit AddBreakpoint();
  560. }
  561. void HotkeyScheduler::CheckGBAHotkeys()
  562. {
  563. #ifdef HAS_LIBMGBA
  564. GBAWidget* gba_widget = qobject_cast<GBAWidget*>(QApplication::activeWindow());
  565. if (!gba_widget)
  566. return;
  567. if (IsHotkey(HK_GBA_LOAD))
  568. QueueOnObject(gba_widget, [gba_widget] { gba_widget->LoadROM(); });
  569. if (IsHotkey(HK_GBA_UNLOAD))
  570. QueueOnObject(gba_widget, [gba_widget] { gba_widget->UnloadROM(); });
  571. if (IsHotkey(HK_GBA_RESET))
  572. QueueOnObject(gba_widget, [gba_widget] { gba_widget->ResetCore(); });
  573. if (IsHotkey(HK_GBA_VOLUME_DOWN))
  574. QueueOnObject(gba_widget, [gba_widget] { gba_widget->VolumeDown(); });
  575. if (IsHotkey(HK_GBA_VOLUME_UP))
  576. QueueOnObject(gba_widget, [gba_widget] { gba_widget->VolumeUp(); });
  577. if (IsHotkey(HK_GBA_TOGGLE_MUTE))
  578. QueueOnObject(gba_widget, [gba_widget] { gba_widget->ToggleMute(); });
  579. if (IsHotkey(HK_GBA_1X))
  580. QueueOnObject(gba_widget, [gba_widget] { gba_widget->Resize(1); });
  581. if (IsHotkey(HK_GBA_2X))
  582. QueueOnObject(gba_widget, [gba_widget] { gba_widget->Resize(2); });
  583. if (IsHotkey(HK_GBA_3X))
  584. QueueOnObject(gba_widget, [gba_widget] { gba_widget->Resize(3); });
  585. if (IsHotkey(HK_GBA_4X))
  586. QueueOnObject(gba_widget, [gba_widget] { gba_widget->Resize(4); });
  587. #endif
  588. }