dolphin/Source/Core/DolphinQt/HotkeyScheduler.cpp
Léo Lam 522cb6b137
IOS: Use less ambiguous names for classes
Some of the device names can be ambiguous and require fully or partly
qualifying the name (e.g. IOS::HLE::FS::) in a somewhat verbose way.

Additionally, insufficiently qualified names are prone to breaking.
Consider the example of IOS::HLE::FS:: (namespace) and
IOS::HLE::Device::FS (class). If we use FS::Foo in a file that doesn't
know about the class, everything will work fine. However, as soon as
Device::FS is declared via a header include or even just forward
declared, that code will cease to compile because FS:: now resolves
to Device::FS if FS::Foo was used in the Device namespace.

It also leads to having to write IOS::ES:: to access ES types and
utilities even for code that is already under the IOS namespace.

The fix for this is simple: rename the device classes and give them
a "device" suffix in their names if the existing ones may be ambiguous.
This makes it clear whether we're referring to the device class or to
something else.

This is not any longer to type, considering it lets us get rid of the
Device namespace, which is now wholly unnecessary.

There are no functional changes in this commit.

A future commit will fix unnecessarily qualified names.
2021-02-12 21:40:31 +01:00

609 lines
17 KiB
C++

// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinQt/HotkeyScheduler.h"
#include <algorithm>
#include <cmath>
#include <thread>
#include <QCoreApplication>
#include "AudioCommon/AudioCommon.h"
#include "Common/Config/Config.h"
#include "Common/Thread.h"
#include "Core/Config/FreeLookSettings.h"
#include "Core/Config/GraphicsSettings.h"
#include "Core/Config/UISettings.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/FreeLookManager.h"
#include "Core/Host.h"
#include "Core/HotkeyManager.h"
#include "Core/IOS/IOS.h"
#include "Core/IOS/USB/Bluetooth/BTBase.h"
#include "Core/State.h"
#include "DolphinQt/Settings.h"
#include "InputCommon/ControlReference/ControlReference.h"
#include "InputCommon/ControllerInterface/ControllerInterface.h"
#include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/VertexShaderManager.h"
#include "VideoCommon/VideoConfig.h"
constexpr const char* DUBOIS_ALGORITHM_SHADER = "dubois";
HotkeyScheduler::HotkeyScheduler() : m_stop_requested(false)
{
HotkeyManagerEmu::Initialize();
HotkeyManagerEmu::LoadConfig();
HotkeyManagerEmu::Enable(true);
}
HotkeyScheduler::~HotkeyScheduler()
{
Stop();
}
void HotkeyScheduler::Start()
{
m_stop_requested.Set(false);
m_thread = std::thread(&HotkeyScheduler::Run, this);
}
void HotkeyScheduler::Stop()
{
m_stop_requested.Set(true);
if (m_thread.joinable())
m_thread.join();
}
static bool IsHotkey(int id, bool held = false)
{
return HotkeyManagerEmu::IsPressed(id, held);
}
static void HandleFrameStepHotkeys()
{
constexpr int MAX_FRAME_STEP_DELAY = 60;
constexpr int FRAME_STEP_DELAY = 30;
static int frame_step_count = 0;
static int frame_step_delay = 1;
static int frame_step_delay_count = 0;
static bool frame_step_hold = false;
if (IsHotkey(HK_FRAME_ADVANCE_INCREASE_SPEED))
{
frame_step_delay = std::min(frame_step_delay + 1, MAX_FRAME_STEP_DELAY);
return;
}
if (IsHotkey(HK_FRAME_ADVANCE_DECREASE_SPEED))
{
frame_step_delay = std::max(frame_step_delay - 1, 0);
return;
}
if (IsHotkey(HK_FRAME_ADVANCE_RESET_SPEED))
{
frame_step_delay = 1;
return;
}
if (IsHotkey(HK_FRAME_ADVANCE, true))
{
if (frame_step_delay_count < frame_step_delay && frame_step_hold)
frame_step_delay_count++;
if ((frame_step_count == 0 || frame_step_count == FRAME_STEP_DELAY) && !frame_step_hold)
{
Core::DoFrameStep();
frame_step_hold = true;
}
if (frame_step_count < FRAME_STEP_DELAY)
{
frame_step_count++;
frame_step_hold = false;
}
if (frame_step_count == FRAME_STEP_DELAY && frame_step_hold &&
frame_step_delay_count >= frame_step_delay)
{
frame_step_hold = false;
frame_step_delay_count = 0;
}
return;
}
else if (frame_step_count > 0)
{
// Reset frame advance
frame_step_count = 0;
frame_step_hold = false;
frame_step_delay_count = 0;
}
}
void HotkeyScheduler::Run()
{
Common::SetCurrentThreadName("HotkeyScheduler");
while (!m_stop_requested.IsSet())
{
Common::SleepCurrentThread(1000 / 60);
if (Core::GetState() == Core::State::Uninitialized || Core::GetState() == Core::State::Paused)
g_controller_interface.UpdateInput();
if (!HotkeyManagerEmu::IsEnabled())
continue;
if (Core::GetState() != Core::State::Stopping)
{
// Obey window focus (config permitting) before checking hotkeys.
Core::UpdateInputGate(Config::Get(Config::MAIN_FOCUSED_HOTKEYS));
HotkeyManagerEmu::GetStatus();
// Everything else on the host thread (controller config dialog) should always get input.
ControlReference::SetInputGate(true);
if (!Core::IsRunningAndStarted())
continue;
if (IsHotkey(HK_OPEN))
emit Open();
// Disc
if (IsHotkey(HK_EJECT_DISC))
emit EjectDisc();
if (IsHotkey(HK_CHANGE_DISC))
emit ChangeDisc();
// Fullscreen
if (IsHotkey(HK_FULLSCREEN))
{
emit FullScreenHotkey();
// Prevent fullscreen from getting toggled too often
Common::SleepCurrentThread(100);
}
// Refresh Game List
if (IsHotkey(HK_REFRESH_LIST))
emit RefreshGameListHotkey();
// Pause and Unpause
if (IsHotkey(HK_PLAY_PAUSE))
emit TogglePauseHotkey();
// Stop
if (IsHotkey(HK_STOP))
emit StopHotkey();
// Reset
if (IsHotkey(HK_RESET))
emit ResetHotkey();
// Frame advance
HandleFrameStepHotkeys();
// Screenshot
if (IsHotkey(HK_SCREENSHOT))
emit ScreenShotHotkey();
// Exit
if (IsHotkey(HK_EXIT))
emit ExitHotkey();
auto& settings = Settings::Instance();
// Toggle Chat
if (IsHotkey(HK_ACTIVATE_CHAT))
emit ActivateChat();
if (IsHotkey(HK_REQUEST_GOLF_CONTROL))
emit RequestGolfControl();
// Recording
if (IsHotkey(HK_START_RECORDING))
emit StartRecording();
if (IsHotkey(HK_EXPORT_RECORDING))
emit ExportRecording();
if (IsHotkey(HK_READ_ONLY_MODE))
emit ToggleReadOnlyMode();
// Wiimote
if (SConfig::GetInstance().m_bt_passthrough_enabled)
{
const auto ios = IOS::HLE::GetIOS();
auto device = ios ? ios->GetDeviceByName("/dev/usb/oh1/57e/305") : nullptr;
if (device != nullptr)
std::static_pointer_cast<IOS::HLE::BluetoothBaseDevice>(device)->UpdateSyncButtonState(
IsHotkey(HK_TRIGGER_SYNC_BUTTON, true));
}
if (SConfig::GetInstance().bEnableDebugging)
{
CheckDebuggingHotkeys();
}
// TODO: HK_MBP_ADD
if (SConfig::GetInstance().bWii)
{
int wiimote_id = -1;
if (IsHotkey(HK_WIIMOTE1_CONNECT))
wiimote_id = 0;
if (IsHotkey(HK_WIIMOTE2_CONNECT))
wiimote_id = 1;
if (IsHotkey(HK_WIIMOTE3_CONNECT))
wiimote_id = 2;
if (IsHotkey(HK_WIIMOTE4_CONNECT))
wiimote_id = 3;
if (IsHotkey(HK_BALANCEBOARD_CONNECT))
wiimote_id = 4;
if (wiimote_id > -1)
emit ConnectWiiRemote(wiimote_id);
if (IsHotkey(HK_TOGGLE_SD_CARD))
Settings::Instance().SetSDCardInserted(!Settings::Instance().IsSDCardInserted());
if (IsHotkey(HK_TOGGLE_USB_KEYBOARD))
{
Settings::Instance().SetUSBKeyboardConnected(
!Settings::Instance().IsUSBKeyboardConnected());
}
}
if (IsHotkey(HK_PREV_WIIMOTE_PROFILE_1))
m_profile_cycler.PreviousWiimoteProfile(0);
else if (IsHotkey(HK_NEXT_WIIMOTE_PROFILE_1))
m_profile_cycler.NextWiimoteProfile(0);
if (IsHotkey(HK_PREV_WIIMOTE_PROFILE_2))
m_profile_cycler.PreviousWiimoteProfile(1);
else if (IsHotkey(HK_NEXT_WIIMOTE_PROFILE_2))
m_profile_cycler.NextWiimoteProfile(1);
if (IsHotkey(HK_PREV_WIIMOTE_PROFILE_3))
m_profile_cycler.PreviousWiimoteProfile(2);
else if (IsHotkey(HK_NEXT_WIIMOTE_PROFILE_3))
m_profile_cycler.NextWiimoteProfile(2);
if (IsHotkey(HK_PREV_WIIMOTE_PROFILE_4))
m_profile_cycler.PreviousWiimoteProfile(3);
else if (IsHotkey(HK_NEXT_WIIMOTE_PROFILE_4))
m_profile_cycler.NextWiimoteProfile(3);
if (IsHotkey(HK_PREV_GAME_WIIMOTE_PROFILE_1))
m_profile_cycler.PreviousWiimoteProfileForGame(0);
else if (IsHotkey(HK_NEXT_GAME_WIIMOTE_PROFILE_1))
m_profile_cycler.NextWiimoteProfileForGame(0);
if (IsHotkey(HK_PREV_GAME_WIIMOTE_PROFILE_2))
m_profile_cycler.PreviousWiimoteProfileForGame(1);
else if (IsHotkey(HK_NEXT_GAME_WIIMOTE_PROFILE_2))
m_profile_cycler.NextWiimoteProfileForGame(1);
if (IsHotkey(HK_PREV_GAME_WIIMOTE_PROFILE_3))
m_profile_cycler.PreviousWiimoteProfileForGame(2);
else if (IsHotkey(HK_NEXT_GAME_WIIMOTE_PROFILE_3))
m_profile_cycler.NextWiimoteProfileForGame(2);
if (IsHotkey(HK_PREV_GAME_WIIMOTE_PROFILE_4))
m_profile_cycler.PreviousWiimoteProfileForGame(3);
else if (IsHotkey(HK_NEXT_GAME_WIIMOTE_PROFILE_4))
m_profile_cycler.NextWiimoteProfileForGame(3);
auto ShowVolume = []() {
OSD::AddMessage(std::string("Volume: ") +
(SConfig::GetInstance().m_IsMuted ?
"Muted" :
std::to_string(SConfig::GetInstance().m_Volume) + "%"));
};
// Volume
if (IsHotkey(HK_VOLUME_DOWN))
{
settings.DecreaseVolume(3);
ShowVolume();
}
if (IsHotkey(HK_VOLUME_UP))
{
settings.IncreaseVolume(3);
ShowVolume();
}
if (IsHotkey(HK_VOLUME_TOGGLE_MUTE))
{
AudioCommon::ToggleMuteVolume();
ShowVolume();
}
// Graphics
const auto efb_scale = Config::Get(Config::GFX_EFB_SCALE);
auto ShowEFBScale = []() {
switch (Config::Get(Config::GFX_EFB_SCALE))
{
case EFB_SCALE_AUTO_INTEGRAL:
OSD::AddMessage("Internal Resolution: Auto (integral)");
break;
case 1:
OSD::AddMessage("Internal Resolution: Native");
break;
default:
OSD::AddMessage(StringFromFormat("Internal Resolution: %dx", g_Config.iEFBScale));
break;
}
};
if (IsHotkey(HK_INCREASE_IR))
{
Config::SetCurrent(Config::GFX_EFB_SCALE, efb_scale + 1);
ShowEFBScale();
}
if (IsHotkey(HK_DECREASE_IR))
{
if (efb_scale > EFB_SCALE_AUTO_INTEGRAL)
{
Config::SetCurrent(Config::GFX_EFB_SCALE, efb_scale - 1);
ShowEFBScale();
}
}
if (IsHotkey(HK_TOGGLE_CROP))
Config::SetCurrent(Config::GFX_CROP, !Config::Get(Config::GFX_CROP));
if (IsHotkey(HK_TOGGLE_AR))
{
const int aspect_ratio = (static_cast<int>(Config::Get(Config::GFX_ASPECT_RATIO)) + 1) & 3;
Config::SetCurrent(Config::GFX_ASPECT_RATIO, static_cast<AspectMode>(aspect_ratio));
switch (static_cast<AspectMode>(aspect_ratio))
{
case AspectMode::Stretch:
OSD::AddMessage("Stretch");
break;
case AspectMode::Analog:
OSD::AddMessage("Force 4:3");
break;
case AspectMode::AnalogWide:
OSD::AddMessage("Force 16:9");
break;
case AspectMode::Auto:
default:
OSD::AddMessage("Auto");
break;
}
}
if (IsHotkey(HK_TOGGLE_SKIP_EFB_ACCESS))
{
const bool new_value = !Config::Get(Config::GFX_HACK_EFB_ACCESS_ENABLE);
Config::SetCurrent(Config::GFX_HACK_EFB_ACCESS_ENABLE, new_value);
OSD::AddMessage(
StringFromFormat("%s EFB Access from CPU", new_value ? "Skip" : "Don't skip"));
}
if (IsHotkey(HK_TOGGLE_EFBCOPIES))
{
const bool new_value = !Config::Get(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM);
Config::SetCurrent(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM, new_value);
OSD::AddMessage(StringFromFormat("Copy EFB: %s", new_value ? "to Texture" : "to RAM"));
}
auto ShowXFBCopies = []() {
OSD::AddMessage(StringFromFormat(
"Copy XFB: %s%s", Config::Get(Config::GFX_HACK_IMMEDIATE_XFB) ? " (Immediate)" : "",
Config::Get(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM) ? "to Texture" : "to RAM"));
};
if (IsHotkey(HK_TOGGLE_XFBCOPIES))
{
Config::SetCurrent(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM,
!Config::Get(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM));
ShowXFBCopies();
}
if (IsHotkey(HK_TOGGLE_IMMEDIATE_XFB))
{
Config::SetCurrent(Config::GFX_HACK_IMMEDIATE_XFB,
!Config::Get(Config::GFX_HACK_IMMEDIATE_XFB));
ShowXFBCopies();
}
if (IsHotkey(HK_TOGGLE_FOG))
{
const bool new_value = !Config::Get(Config::GFX_DISABLE_FOG);
Config::SetCurrent(Config::GFX_DISABLE_FOG, new_value);
OSD::AddMessage(StringFromFormat("Fog: %s", new_value ? "Enabled" : "Disabled"));
}
if (IsHotkey(HK_TOGGLE_DUMPTEXTURES))
Config::SetCurrent(Config::GFX_DUMP_TEXTURES, !Config::Get(Config::GFX_DUMP_TEXTURES));
if (IsHotkey(HK_TOGGLE_TEXTURES))
Config::SetCurrent(Config::GFX_HIRES_TEXTURES, !Config::Get(Config::GFX_HIRES_TEXTURES));
Core::SetIsThrottlerTempDisabled(IsHotkey(HK_TOGGLE_THROTTLE, true));
auto ShowEmulationSpeed = []() {
OSD::AddMessage(
SConfig::GetInstance().m_EmulationSpeed <= 0 ?
"Speed Limit: Unlimited" :
StringFromFormat("Speed Limit: %li%%",
std::lround(SConfig::GetInstance().m_EmulationSpeed * 100.f)));
};
if (IsHotkey(HK_DECREASE_EMULATION_SPEED))
{
auto speed = SConfig::GetInstance().m_EmulationSpeed - 0.1;
speed = (speed <= 0 || (speed >= 0.95 && speed <= 1.05)) ? 1.0 : speed;
SConfig::GetInstance().m_EmulationSpeed = speed;
ShowEmulationSpeed();
}
if (IsHotkey(HK_INCREASE_EMULATION_SPEED))
{
auto speed = SConfig::GetInstance().m_EmulationSpeed + 0.1;
speed = (speed >= 0.95 && speed <= 1.05) ? 1.0 : speed;
SConfig::GetInstance().m_EmulationSpeed = speed;
ShowEmulationSpeed();
}
// Slot Saving / Loading
if (IsHotkey(HK_SAVE_STATE_SLOT_SELECTED))
emit StateSaveSlotHotkey();
if (IsHotkey(HK_LOAD_STATE_SLOT_SELECTED))
emit StateLoadSlotHotkey();
// Stereoscopy
if (IsHotkey(HK_TOGGLE_STEREO_SBS))
{
if (Config::Get(Config::GFX_STEREO_MODE) != StereoMode::SBS)
{
// Disable post-processing shader, as stereoscopy itself is currently a shader
if (Config::Get(Config::GFX_ENHANCE_POST_SHADER) == DUBOIS_ALGORITHM_SHADER)
Config::SetCurrent(Config::GFX_ENHANCE_POST_SHADER, "");
Config::SetCurrent(Config::GFX_STEREO_MODE, StereoMode::SBS);
}
else
{
Config::SetCurrent(Config::GFX_STEREO_MODE, StereoMode::Off);
}
}
if (IsHotkey(HK_TOGGLE_STEREO_TAB))
{
if (Config::Get(Config::GFX_STEREO_MODE) != StereoMode::TAB)
{
// Disable post-processing shader, as stereoscopy itself is currently a shader
if (Config::Get(Config::GFX_ENHANCE_POST_SHADER) == DUBOIS_ALGORITHM_SHADER)
Config::SetCurrent(Config::GFX_ENHANCE_POST_SHADER, "");
Config::SetCurrent(Config::GFX_STEREO_MODE, StereoMode::TAB);
}
else
{
Config::SetCurrent(Config::GFX_STEREO_MODE, StereoMode::Off);
}
}
if (IsHotkey(HK_TOGGLE_STEREO_ANAGLYPH))
{
if (Config::Get(Config::GFX_STEREO_MODE) != StereoMode::Anaglyph)
{
Config::SetCurrent(Config::GFX_STEREO_MODE, StereoMode::Anaglyph);
Config::SetCurrent(Config::GFX_ENHANCE_POST_SHADER, DUBOIS_ALGORITHM_SHADER);
}
else
{
Config::SetCurrent(Config::GFX_STEREO_MODE, StereoMode::Off);
Config::SetCurrent(Config::GFX_ENHANCE_POST_SHADER, "");
}
}
}
const auto stereo_depth = Config::Get(Config::GFX_STEREO_DEPTH);
if (IsHotkey(HK_DECREASE_DEPTH, true))
Config::SetCurrent(Config::GFX_STEREO_DEPTH, std::max(stereo_depth - 1, 0));
if (IsHotkey(HK_INCREASE_DEPTH, true))
Config::SetCurrent(Config::GFX_STEREO_DEPTH,
std::min(stereo_depth + 1, Config::GFX_STEREO_DEPTH_MAXIMUM));
const auto stereo_convergence = Config::Get(Config::GFX_STEREO_CONVERGENCE);
if (IsHotkey(HK_DECREASE_CONVERGENCE, true))
Config::SetCurrent(Config::GFX_STEREO_CONVERGENCE, std::max(stereo_convergence - 5, 0));
if (IsHotkey(HK_INCREASE_CONVERGENCE, true))
Config::SetCurrent(Config::GFX_STEREO_CONVERGENCE,
std::min(stereo_convergence + 5, Config::GFX_STEREO_CONVERGENCE_MAXIMUM));
// Free Look
if (IsHotkey(HK_FREELOOK_TOGGLE))
{
const bool new_value = !Config::Get(Config::FREE_LOOK_ENABLED);
Config::SetCurrent(Config::FREE_LOOK_ENABLED, new_value);
OSD::AddMessage(StringFromFormat("Free Look: %s", new_value ? "Enabled" : "Disabled"));
}
FreeLook::UpdateInput();
// Savestates
for (u32 i = 0; i < State::NUM_STATES; i++)
{
if (IsHotkey(HK_LOAD_STATE_SLOT_1 + i))
emit StateLoadSlot(i + 1);
if (IsHotkey(HK_SAVE_STATE_SLOT_1 + i))
emit StateSaveSlot(i + 1);
if (IsHotkey(HK_LOAD_LAST_STATE_1 + i))
emit StateLoadLastSaved(i + 1);
if (IsHotkey(HK_SELECT_STATE_SLOT_1 + i))
emit SetStateSlotHotkey(i + 1);
}
if (IsHotkey(HK_SAVE_FIRST_STATE))
emit StateSaveOldest();
if (IsHotkey(HK_UNDO_LOAD_STATE))
emit StateLoadUndo();
if (IsHotkey(HK_UNDO_SAVE_STATE))
emit StateSaveUndo();
if (IsHotkey(HK_LOAD_STATE_FILE))
emit StateLoadFile();
if (IsHotkey(HK_SAVE_STATE_FILE))
emit StateSaveFile();
}
}
void HotkeyScheduler::CheckDebuggingHotkeys()
{
if (IsHotkey(HK_STEP))
emit Step();
if (IsHotkey(HK_STEP_OVER))
emit StepOver();
if (IsHotkey(HK_STEP_OUT))
emit StepOut();
if (IsHotkey(HK_SKIP))
emit Skip();
if (IsHotkey(HK_SHOW_PC))
emit ShowPC();
if (IsHotkey(HK_SET_PC))
emit Skip();
if (IsHotkey(HK_BP_TOGGLE))
emit ToggleBreakpoint();
if (IsHotkey(HK_BP_ADD))
emit AddBreakpoint();
}