mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-01 12:32:48 +00:00
7dca7c237e
This excludes the second argument from template deduction. Otherwise, it is required to manually cast the second argument to the ConfigInfo type (because implicit conversions won't work). e.g. to set the value for a ConfigInfo<std::string> from a string literal, you'd need a ugly `std::string("yourstring")`.
468 lines
13 KiB
C++
468 lines
13 KiB
C++
// Copyright 2017 Dolphin Emulator Project
|
|
// Licensed under GPLv2+
|
|
// Refer to the license.txt file included.
|
|
|
|
#include "DolphinQt2/HotkeyScheduler.h"
|
|
|
|
#include <algorithm>
|
|
#include <thread>
|
|
|
|
#include <QCoreApplication>
|
|
|
|
#include "AudioCommon/AudioCommon.h"
|
|
#include "Common/Thread.h"
|
|
#include "Core/Config/GraphicsSettings.h"
|
|
#include "Core/ConfigManager.h"
|
|
#include "Core/Core.h"
|
|
#include "Core/HotkeyManager.h"
|
|
#include "Core/IOS/IOS.h"
|
|
#include "Core/IOS/USB/Bluetooth/BTBase.h"
|
|
#include "Core/State.h"
|
|
|
|
#include "DolphinQt2/MainWindow.h"
|
|
#include "DolphinQt2/Settings.h"
|
|
|
|
#include "InputCommon/ControllerInterface/ControllerInterface.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 HandleFrameskipHotkeys()
|
|
{
|
|
constexpr int MAX_FRAME_SKIP_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_SKIP_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()
|
|
{
|
|
while (!m_stop_requested.IsSet())
|
|
{
|
|
Common::SleepCurrentThread(1000 / 60);
|
|
|
|
if (!HotkeyManagerEmu::IsEnabled())
|
|
continue;
|
|
|
|
if (Core::GetState() == Core::State::Uninitialized || Core::GetState() == Core::State::Paused)
|
|
g_controller_interface.UpdateInput();
|
|
|
|
if (Core::GetState() != Core::State::Stopping)
|
|
{
|
|
HotkeyManagerEmu::GetStatus();
|
|
|
|
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();
|
|
|
|
// Pause and Unpause
|
|
if (IsHotkey(HK_PLAY_PAUSE))
|
|
emit TogglePauseHotkey();
|
|
|
|
// Stop
|
|
if (IsHotkey(HK_STOP))
|
|
emit StopHotkey();
|
|
|
|
// Frameskipping
|
|
HandleFrameskipHotkeys();
|
|
|
|
// Screenshot
|
|
if (IsHotkey(HK_SCREENSHOT))
|
|
emit ScreenShotHotkey();
|
|
|
|
// Exit
|
|
if (IsHotkey(HK_EXIT))
|
|
emit ExitHotkey();
|
|
|
|
auto& settings = Settings::Instance();
|
|
|
|
// Recording
|
|
if (IsHotkey(HK_START_RECORDING))
|
|
emit StartRecording();
|
|
|
|
if (IsHotkey(HK_EXPORT_RECORDING))
|
|
emit ExportRecording();
|
|
|
|
if (IsHotkey(HK_READ_ONLY_MODE))
|
|
emit ToggleReadOnlyMode();
|
|
|
|
// Volume
|
|
if (IsHotkey(HK_VOLUME_DOWN))
|
|
settings.DecreaseVolume(3);
|
|
|
|
if (IsHotkey(HK_VOLUME_UP))
|
|
settings.IncreaseVolume(3);
|
|
|
|
if (IsHotkey(HK_VOLUME_TOGGLE_MUTE))
|
|
AudioCommon::ToggleMuteVolume();
|
|
|
|
// 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::Device::BluetoothBase>(device)->UpdateSyncButtonState(
|
|
IsHotkey(HK_TRIGGER_SYNC_BUTTON, true));
|
|
}
|
|
|
|
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();
|
|
|
|
// 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);
|
|
}
|
|
|
|
const auto show_msg = [](OSDMessage message) {
|
|
if (g_renderer)
|
|
g_renderer->ShowOSDMessage(message);
|
|
};
|
|
|
|
// Graphics
|
|
const auto efb_scale = Config::Get(Config::GFX_EFB_SCALE);
|
|
|
|
if (IsHotkey(HK_INCREASE_IR))
|
|
{
|
|
show_msg(OSDMessage::IRChanged);
|
|
Config::SetCurrent(Config::GFX_EFB_SCALE, efb_scale + 1);
|
|
}
|
|
if (IsHotkey(HK_DECREASE_IR))
|
|
{
|
|
show_msg(OSDMessage::IRChanged);
|
|
if (efb_scale > EFB_SCALE_AUTO_INTEGRAL)
|
|
Config::SetCurrent(Config::GFX_EFB_SCALE, efb_scale - 1);
|
|
}
|
|
|
|
if (IsHotkey(HK_TOGGLE_CROP))
|
|
Config::SetCurrent(Config::GFX_CROP, !Config::Get(Config::GFX_CROP));
|
|
|
|
if (IsHotkey(HK_TOGGLE_AR))
|
|
{
|
|
show_msg(OSDMessage::ARToggled);
|
|
const auto aspect_ratio = (Config::Get(Config::GFX_ASPECT_RATIO) + 1) & 3;
|
|
Config::SetCurrent(Config::GFX_ASPECT_RATIO, aspect_ratio);
|
|
}
|
|
if (IsHotkey(HK_TOGGLE_EFBCOPIES))
|
|
{
|
|
show_msg(OSDMessage::EFBCopyToggled);
|
|
Config::SetCurrent(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM,
|
|
!Config::Get(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM));
|
|
}
|
|
|
|
if (IsHotkey(HK_TOGGLE_XFBCOPIES))
|
|
{
|
|
show_msg(OSDMessage::XFBChanged);
|
|
Config::SetCurrent(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM,
|
|
!Config::Get(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM));
|
|
}
|
|
if (IsHotkey(HK_TOGGLE_IMMEDIATE_XFB))
|
|
{
|
|
show_msg(OSDMessage::XFBChanged);
|
|
|
|
Config::SetCurrent(Config::GFX_HACK_IMMEDIATE_XFB,
|
|
!Config::Get(Config::GFX_HACK_IMMEDIATE_XFB));
|
|
}
|
|
if (IsHotkey(HK_TOGGLE_FOG))
|
|
{
|
|
show_msg(OSDMessage::FogToggled);
|
|
Config::SetCurrent(Config::GFX_DISABLE_FOG, !Config::Get(Config::GFX_DISABLE_FOG));
|
|
}
|
|
|
|
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));
|
|
|
|
if (IsHotkey(HK_DECREASE_EMULATION_SPEED))
|
|
{
|
|
show_msg(OSDMessage::SpeedChanged);
|
|
|
|
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;
|
|
}
|
|
|
|
if (IsHotkey(HK_INCREASE_EMULATION_SPEED))
|
|
{
|
|
show_msg(OSDMessage::SpeedChanged);
|
|
|
|
auto speed = SConfig::GetInstance().m_EmulationSpeed + 0.1;
|
|
speed = (speed >= 0.95 && speed <= 1.05) ? 1.0 : speed;
|
|
SConfig::GetInstance().m_EmulationSpeed = speed;
|
|
}
|
|
|
|
// 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) || IsHotkey(HK_TOGGLE_STEREO_TAB))
|
|
{
|
|
if (Config::Get(Config::GFX_STEREO_MODE) != static_cast<int>(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, IsHotkey(HK_TOGGLE_STEREO_SBS) ?
|
|
static_cast<int>(StereoMode::SBS) :
|
|
static_cast<int>(StereoMode::TAB));
|
|
}
|
|
else
|
|
{
|
|
Config::SetCurrent(Config::GFX_STEREO_MODE, static_cast<int>(StereoMode::Off));
|
|
}
|
|
}
|
|
|
|
if (IsHotkey(HK_TOGGLE_STEREO_ANAGLYPH))
|
|
{
|
|
if (Config::Get(Config::GFX_STEREO_MODE) != static_cast<int>(StereoMode::Anaglyph))
|
|
{
|
|
Config::SetCurrent(Config::GFX_STEREO_MODE, static_cast<int>(StereoMode::Anaglyph));
|
|
Config::SetCurrent(Config::GFX_ENHANCE_POST_SHADER, DUBOIS_ALGORITHM_SHADER);
|
|
}
|
|
else
|
|
{
|
|
Config::SetCurrent(Config::GFX_STEREO_MODE, static_cast<int>(StereoMode::Off));
|
|
Config::SetCurrent(Config::GFX_ENHANCE_POST_SHADER, "");
|
|
}
|
|
}
|
|
|
|
if (IsHotkey(HK_TOGGLE_STEREO_3DVISION))
|
|
{
|
|
if (Config::Get(Config::GFX_STEREO_MODE) != static_cast<int>(StereoMode::Nvidia3DVision))
|
|
{
|
|
if (Config::Get(Config::GFX_ENHANCE_POST_SHADER) == DUBOIS_ALGORITHM_SHADER)
|
|
Config::SetCurrent(Config::GFX_ENHANCE_POST_SHADER, "");
|
|
|
|
Config::SetCurrent(Config::GFX_STEREO_MODE, static_cast<int>(StereoMode::Nvidia3DVision));
|
|
}
|
|
else
|
|
{
|
|
Config::SetCurrent(Config::GFX_STEREO_MODE, static_cast<int>(StereoMode::Off));
|
|
}
|
|
}
|
|
}
|
|
|
|
const auto stereo_depth = Config::Get(Config::GFX_STEREO_DEPTH);
|
|
|
|
if (IsHotkey(HK_DECREASE_DEPTH, true))
|
|
Config::SetCurrent(Config::GFX_STEREO_DEPTH, std::min(stereo_depth - 1, 0));
|
|
|
|
if (IsHotkey(HK_INCREASE_DEPTH, true))
|
|
Config::SetCurrent(Config::GFX_STEREO_DEPTH, std::min(stereo_depth + 1, 100));
|
|
|
|
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, 500));
|
|
|
|
// Freelook
|
|
static float fl_speed = 1.0;
|
|
|
|
if (IsHotkey(HK_FREELOOK_DECREASE_SPEED, true))
|
|
fl_speed /= 1.1f;
|
|
|
|
if (IsHotkey(HK_FREELOOK_INCREASE_SPEED, true))
|
|
fl_speed *= 1.1f;
|
|
|
|
if (IsHotkey(HK_FREELOOK_RESET_SPEED, true))
|
|
fl_speed = 1.0;
|
|
|
|
if (IsHotkey(HK_FREELOOK_UP, true))
|
|
VertexShaderManager::TranslateView(0.0, 0.0, -fl_speed);
|
|
|
|
if (IsHotkey(HK_FREELOOK_DOWN, true))
|
|
VertexShaderManager::TranslateView(0.0, 0.0, fl_speed);
|
|
|
|
if (IsHotkey(HK_FREELOOK_LEFT, true))
|
|
VertexShaderManager::TranslateView(fl_speed, 0.0);
|
|
|
|
if (IsHotkey(HK_FREELOOK_RIGHT, true))
|
|
VertexShaderManager::TranslateView(-fl_speed, 0.0);
|
|
|
|
if (IsHotkey(HK_FREELOOK_ZOOM_IN, true))
|
|
VertexShaderManager::TranslateView(0.0, fl_speed);
|
|
|
|
if (IsHotkey(HK_FREELOOK_ZOOM_OUT, true))
|
|
VertexShaderManager::TranslateView(0.0, -fl_speed);
|
|
|
|
if (IsHotkey(HK_FREELOOK_RESET, true))
|
|
VertexShaderManager::ResetView();
|
|
|
|
// Savestates
|
|
for (u32 i = 0; i < State::NUM_STATES; i++)
|
|
{
|
|
if (IsHotkey(HK_LOAD_STATE_SLOT_1 + i))
|
|
State::Load(i + 1);
|
|
|
|
if (IsHotkey(HK_SAVE_STATE_SLOT_1 + i))
|
|
State::Save(i + 1);
|
|
|
|
if (IsHotkey(HK_LOAD_LAST_STATE_1 + i))
|
|
State::LoadLastSaved(i + 1);
|
|
|
|
if (IsHotkey(HK_SELECT_STATE_SLOT_1 + i))
|
|
emit SetStateSlotHotkey(i + 1);
|
|
}
|
|
|
|
if (IsHotkey(HK_SAVE_FIRST_STATE))
|
|
State::SaveFirstSaved();
|
|
|
|
if (IsHotkey(HK_UNDO_LOAD_STATE))
|
|
State::UndoLoadState();
|
|
|
|
if (IsHotkey(HK_UNDO_SAVE_STATE))
|
|
State::UndoSaveState();
|
|
}
|
|
}
|