From 151ae38a568a518458e57ac0c72d6b15172f0462 Mon Sep 17 00:00:00 2001 From: spycrab Date: Tue, 6 Jun 2017 13:49:49 +0200 Subject: [PATCH] Qt: Implement hotkeys (+ configuration) --- Source/Core/DolphinQt2/CMakeLists.txt | 8 + .../DolphinQt2/Config/Mapping/Hotkey3D.cpp | 42 ++ .../Core/DolphinQt2/Config/Mapping/Hotkey3D.h | 25 ++ .../Config/Mapping/HotkeyGeneral.cpp | 47 +++ .../DolphinQt2/Config/Mapping/HotkeyGeneral.h | 25 ++ .../Config/Mapping/HotkeyGraphics.cpp | 48 +++ .../Config/Mapping/HotkeyGraphics.h | 25 ++ .../Config/Mapping/HotkeyStates.cpp | 42 ++ .../DolphinQt2/Config/Mapping/HotkeyStates.h | 25 ++ .../DolphinQt2/Config/Mapping/HotkeyTAS.cpp | 42 ++ .../DolphinQt2/Config/Mapping/HotkeyTAS.h | 25 ++ .../DolphinQt2/Config/Mapping/HotkeyWii.cpp | 39 ++ .../DolphinQt2/Config/Mapping/HotkeyWii.h | 25 ++ .../Config/Mapping/MappingWindow.cpp | 18 + .../DolphinQt2/Config/Mapping/MappingWindow.h | 4 +- Source/Core/DolphinQt2/DolphinQt2.vcxproj | 12 + Source/Core/DolphinQt2/HotkeyScheduler.cpp | 363 ++++++++++++++++++ Source/Core/DolphinQt2/HotkeyScheduler.h | 37 ++ Source/Core/DolphinQt2/MainWindow.cpp | 54 ++- Source/Core/DolphinQt2/MainWindow.h | 6 + Source/Core/DolphinQt2/MenuBar.cpp | 8 +- Source/Core/DolphinQt2/MenuBar.h | 4 + .../DolphinQt2/QtUtils/FocusEventFilter.cpp | 19 + .../DolphinQt2/QtUtils/FocusEventFilter.h | 18 + 24 files changed, 958 insertions(+), 3 deletions(-) create mode 100644 Source/Core/DolphinQt2/Config/Mapping/Hotkey3D.cpp create mode 100644 Source/Core/DolphinQt2/Config/Mapping/Hotkey3D.h create mode 100644 Source/Core/DolphinQt2/Config/Mapping/HotkeyGeneral.cpp create mode 100644 Source/Core/DolphinQt2/Config/Mapping/HotkeyGeneral.h create mode 100644 Source/Core/DolphinQt2/Config/Mapping/HotkeyGraphics.cpp create mode 100644 Source/Core/DolphinQt2/Config/Mapping/HotkeyGraphics.h create mode 100644 Source/Core/DolphinQt2/Config/Mapping/HotkeyStates.cpp create mode 100644 Source/Core/DolphinQt2/Config/Mapping/HotkeyStates.h create mode 100644 Source/Core/DolphinQt2/Config/Mapping/HotkeyTAS.cpp create mode 100644 Source/Core/DolphinQt2/Config/Mapping/HotkeyTAS.h create mode 100644 Source/Core/DolphinQt2/Config/Mapping/HotkeyWii.cpp create mode 100644 Source/Core/DolphinQt2/Config/Mapping/HotkeyWii.h create mode 100644 Source/Core/DolphinQt2/HotkeyScheduler.cpp create mode 100644 Source/Core/DolphinQt2/HotkeyScheduler.h create mode 100644 Source/Core/DolphinQt2/QtUtils/FocusEventFilter.cpp create mode 100644 Source/Core/DolphinQt2/QtUtils/FocusEventFilter.h diff --git a/Source/Core/DolphinQt2/CMakeLists.txt b/Source/Core/DolphinQt2/CMakeLists.txt index 42a42bfaa8..e5ff552b6c 100644 --- a/Source/Core/DolphinQt2/CMakeLists.txt +++ b/Source/Core/DolphinQt2/CMakeLists.txt @@ -9,6 +9,7 @@ set(CMAKE_AUTOMOC ON) set(SRCS AboutDialog.cpp + HotkeyScheduler.cpp Host.cpp InDevelopmentWarning.cpp Main.cpp @@ -24,6 +25,12 @@ set(SRCS Config/Mapping/GCKeyboardEmu.cpp Config/Mapping/GCPadEmu.cpp Config/Mapping/GCPadWiiU.cpp + Config/Mapping/Hotkey3D.cpp + Config/Mapping/HotkeyGeneral.cpp + Config/Mapping/HotkeyGraphics.cpp + Config/Mapping/HotkeyStates.cpp + Config/Mapping/HotkeyTAS.cpp + Config/Mapping/HotkeyWii.cpp Config/Mapping/MappingBool.cpp Config/Mapping/MappingButton.cpp Config/Mapping/MappingNumeric.cpp @@ -41,6 +48,7 @@ set(SRCS GameList/ListProxyModel.cpp QtUtils/DoubleClickEventFilter.cpp QtUtils/ElidedButton.cpp + QtUtils/FocusEventFilter.cpp Settings/GeneralPane.cpp Settings/InterfacePane.cpp Settings/PathPane.cpp diff --git a/Source/Core/DolphinQt2/Config/Mapping/Hotkey3D.cpp b/Source/Core/DolphinQt2/Config/Mapping/Hotkey3D.cpp new file mode 100644 index 0000000000..c144d53f76 --- /dev/null +++ b/Source/Core/DolphinQt2/Config/Mapping/Hotkey3D.cpp @@ -0,0 +1,42 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "DolphinQt2/Config/Mapping/Hotkey3D.h" + +#include +#include + +#include "Core/HotkeyManager.h" + +Hotkey3D::Hotkey3D(MappingWindow* window) : MappingWidget(window) +{ + CreateMainLayout(); +} + +void Hotkey3D::CreateMainLayout() +{ + m_main_layout = new QHBoxLayout(); + + m_main_layout->addWidget( + CreateGroupBox(tr("3D"), HotkeyManagerEmu::GetHotkeyGroup(HKGP_3D_TOGGLE))); + m_main_layout->addWidget( + CreateGroupBox(tr("3D Depth"), HotkeyManagerEmu::GetHotkeyGroup(HKGP_3D_DEPTH))); + + setLayout(m_main_layout); +} + +InputConfig* Hotkey3D::GetConfig() +{ + return HotkeyManagerEmu::GetConfig(); +} + +void Hotkey3D::LoadSettings() +{ + HotkeyManagerEmu::LoadConfig(); +} + +void Hotkey3D::SaveSettings() +{ + HotkeyManagerEmu::GetConfig()->SaveConfig(); +} diff --git a/Source/Core/DolphinQt2/Config/Mapping/Hotkey3D.h b/Source/Core/DolphinQt2/Config/Mapping/Hotkey3D.h new file mode 100644 index 0000000000..b7e78822f2 --- /dev/null +++ b/Source/Core/DolphinQt2/Config/Mapping/Hotkey3D.h @@ -0,0 +1,25 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include "DolphinQt2/Config/Mapping/MappingWidget.h" + +class QHBoxLayout; + +class Hotkey3D final : public MappingWidget +{ +public: + explicit Hotkey3D(MappingWindow* window); + + InputConfig* GetConfig() override; + +private: + void LoadSettings() override; + void SaveSettings() override; + void CreateMainLayout(); + + // Main + QHBoxLayout* m_main_layout; +}; diff --git a/Source/Core/DolphinQt2/Config/Mapping/HotkeyGeneral.cpp b/Source/Core/DolphinQt2/Config/Mapping/HotkeyGeneral.cpp new file mode 100644 index 0000000000..fc111f745c --- /dev/null +++ b/Source/Core/DolphinQt2/Config/Mapping/HotkeyGeneral.cpp @@ -0,0 +1,47 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "DolphinQt2/Config/Mapping/HotkeyGeneral.h" + +#include +#include +#include + +#include "Core/HotkeyManager.h" + +HotkeyGeneral::HotkeyGeneral(MappingWindow* window) : MappingWidget(window) +{ + CreateMainLayout(); +} + +void HotkeyGeneral::CreateMainLayout() +{ + m_main_layout = new QHBoxLayout(); + + m_main_layout->addWidget( + CreateGroupBox(tr("General"), HotkeyManagerEmu::GetHotkeyGroup(HKGP_GENERAL))); + + auto* vbox = new QVBoxLayout(); + vbox->addWidget(CreateGroupBox(tr("Volume"), HotkeyManagerEmu::GetHotkeyGroup(HKGP_VOLUME))); + vbox->addWidget( + CreateGroupBox(tr("Emulation Speed"), HotkeyManagerEmu::GetHotkeyGroup(HKGP_SPEED))); + m_main_layout->addItem(vbox); + + setLayout(m_main_layout); +} + +InputConfig* HotkeyGeneral::GetConfig() +{ + return HotkeyManagerEmu::GetConfig(); +} + +void HotkeyGeneral::LoadSettings() +{ + HotkeyManagerEmu::LoadConfig(); +} + +void HotkeyGeneral::SaveSettings() +{ + HotkeyManagerEmu::GetConfig()->SaveConfig(); +} diff --git a/Source/Core/DolphinQt2/Config/Mapping/HotkeyGeneral.h b/Source/Core/DolphinQt2/Config/Mapping/HotkeyGeneral.h new file mode 100644 index 0000000000..15c6dd04b3 --- /dev/null +++ b/Source/Core/DolphinQt2/Config/Mapping/HotkeyGeneral.h @@ -0,0 +1,25 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include "DolphinQt2/Config/Mapping/MappingWidget.h" + +class QHBoxLayout; + +class HotkeyGeneral final : public MappingWidget +{ +public: + explicit HotkeyGeneral(MappingWindow* window); + + InputConfig* GetConfig() override; + +private: + void LoadSettings() override; + void SaveSettings() override; + void CreateMainLayout(); + + // Main + QHBoxLayout* m_main_layout; +}; diff --git a/Source/Core/DolphinQt2/Config/Mapping/HotkeyGraphics.cpp b/Source/Core/DolphinQt2/Config/Mapping/HotkeyGraphics.cpp new file mode 100644 index 0000000000..fe4cc8cdba --- /dev/null +++ b/Source/Core/DolphinQt2/Config/Mapping/HotkeyGraphics.cpp @@ -0,0 +1,48 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "DolphinQt2/Config/Mapping/HotkeyGraphics.h" + +#include +#include +#include + +#include "Core/HotkeyManager.h" + +HotkeyGraphics::HotkeyGraphics(MappingWindow* window) : MappingWidget(window) +{ + CreateMainLayout(); +} + +void HotkeyGraphics::CreateMainLayout() +{ + m_main_layout = new QHBoxLayout(); + + m_main_layout->addWidget( + CreateGroupBox(tr("Freelook"), HotkeyManagerEmu::GetHotkeyGroup(HKGP_FREELOOK))); + + auto* vbox = new QVBoxLayout(); + vbox->addWidget(CreateGroupBox(tr("Graphics Toggles"), + HotkeyManagerEmu::GetHotkeyGroup(HKGP_GRAPHICS_TOGGLES))); + vbox->addWidget( + CreateGroupBox(tr("Internal Resolution"), HotkeyManagerEmu::GetHotkeyGroup(HKGP_IR))); + m_main_layout->addItem(vbox); + + setLayout(m_main_layout); +} + +InputConfig* HotkeyGraphics::GetConfig() +{ + return HotkeyManagerEmu::GetConfig(); +} + +void HotkeyGraphics::LoadSettings() +{ + HotkeyManagerEmu::LoadConfig(); +} + +void HotkeyGraphics::SaveSettings() +{ + HotkeyManagerEmu::GetConfig()->SaveConfig(); +} diff --git a/Source/Core/DolphinQt2/Config/Mapping/HotkeyGraphics.h b/Source/Core/DolphinQt2/Config/Mapping/HotkeyGraphics.h new file mode 100644 index 0000000000..63837202b3 --- /dev/null +++ b/Source/Core/DolphinQt2/Config/Mapping/HotkeyGraphics.h @@ -0,0 +1,25 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include "DolphinQt2/Config/Mapping/MappingWidget.h" + +class QHBoxLayout; + +class HotkeyGraphics final : public MappingWidget +{ +public: + explicit HotkeyGraphics(MappingWindow* window); + + InputConfig* GetConfig() override; + +private: + void LoadSettings() override; + void SaveSettings() override; + void CreateMainLayout(); + + // Main + QHBoxLayout* m_main_layout; +}; diff --git a/Source/Core/DolphinQt2/Config/Mapping/HotkeyStates.cpp b/Source/Core/DolphinQt2/Config/Mapping/HotkeyStates.cpp new file mode 100644 index 0000000000..20d85cd544 --- /dev/null +++ b/Source/Core/DolphinQt2/Config/Mapping/HotkeyStates.cpp @@ -0,0 +1,42 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "DolphinQt2/Config/Mapping/HotkeyStates.h" + +#include +#include + +#include "Core/HotkeyManager.h" + +HotkeyStates::HotkeyStates(MappingWindow* window) : MappingWidget(window) +{ + CreateMainLayout(); +} + +void HotkeyStates::CreateMainLayout() +{ + m_main_layout = new QHBoxLayout(); + + m_main_layout->addWidget( + CreateGroupBox(tr("Save"), HotkeyManagerEmu::GetHotkeyGroup(HKGP_SAVE_STATE))); + m_main_layout->addWidget( + CreateGroupBox(tr("Load"), HotkeyManagerEmu::GetHotkeyGroup(HKGP_LOAD_STATE))); + + setLayout(m_main_layout); +} + +InputConfig* HotkeyStates::GetConfig() +{ + return HotkeyManagerEmu::GetConfig(); +} + +void HotkeyStates::LoadSettings() +{ + HotkeyManagerEmu::LoadConfig(); +} + +void HotkeyStates::SaveSettings() +{ + HotkeyManagerEmu::GetConfig()->SaveConfig(); +} diff --git a/Source/Core/DolphinQt2/Config/Mapping/HotkeyStates.h b/Source/Core/DolphinQt2/Config/Mapping/HotkeyStates.h new file mode 100644 index 0000000000..bf36ec96f3 --- /dev/null +++ b/Source/Core/DolphinQt2/Config/Mapping/HotkeyStates.h @@ -0,0 +1,25 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include "DolphinQt2/Config/Mapping/MappingWidget.h" + +class QHBoxLayout; + +class HotkeyStates final : public MappingWidget +{ +public: + explicit HotkeyStates(MappingWindow* window); + + InputConfig* GetConfig() override; + +private: + void LoadSettings() override; + void SaveSettings() override; + void CreateMainLayout(); + + // Main + QHBoxLayout* m_main_layout; +}; diff --git a/Source/Core/DolphinQt2/Config/Mapping/HotkeyTAS.cpp b/Source/Core/DolphinQt2/Config/Mapping/HotkeyTAS.cpp new file mode 100644 index 0000000000..2586ff2d2a --- /dev/null +++ b/Source/Core/DolphinQt2/Config/Mapping/HotkeyTAS.cpp @@ -0,0 +1,42 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "DolphinQt2/Config/Mapping/HotkeyTAS.h" + +#include +#include + +#include "Core/HotkeyManager.h" + +HotkeyTAS::HotkeyTAS(MappingWindow* window) : MappingWidget(window) +{ + CreateMainLayout(); +} + +void HotkeyTAS::CreateMainLayout() +{ + m_main_layout = new QHBoxLayout(); + + m_main_layout->addWidget( + CreateGroupBox(tr("Frame Advance"), HotkeyManagerEmu::GetHotkeyGroup(HKGP_FRAME_ADVANCE))); + m_main_layout->addWidget( + CreateGroupBox(tr("Movie"), HotkeyManagerEmu::GetHotkeyGroup(HKGP_MOVIE))); + + setLayout(m_main_layout); +} + +InputConfig* HotkeyTAS::GetConfig() +{ + return HotkeyManagerEmu::GetConfig(); +} + +void HotkeyTAS::LoadSettings() +{ + HotkeyManagerEmu::LoadConfig(); +} + +void HotkeyTAS::SaveSettings() +{ + HotkeyManagerEmu::GetConfig()->SaveConfig(); +} diff --git a/Source/Core/DolphinQt2/Config/Mapping/HotkeyTAS.h b/Source/Core/DolphinQt2/Config/Mapping/HotkeyTAS.h new file mode 100644 index 0000000000..d6fabc1294 --- /dev/null +++ b/Source/Core/DolphinQt2/Config/Mapping/HotkeyTAS.h @@ -0,0 +1,25 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include "DolphinQt2/Config/Mapping/MappingWidget.h" + +class QHBoxLayout; + +class HotkeyTAS final : public MappingWidget +{ +public: + explicit HotkeyTAS(MappingWindow* window); + + InputConfig* GetConfig() override; + +private: + void LoadSettings() override; + void SaveSettings() override; + void CreateMainLayout(); + + // Main + QHBoxLayout* m_main_layout; +}; diff --git a/Source/Core/DolphinQt2/Config/Mapping/HotkeyWii.cpp b/Source/Core/DolphinQt2/Config/Mapping/HotkeyWii.cpp new file mode 100644 index 0000000000..7cfebf5705 --- /dev/null +++ b/Source/Core/DolphinQt2/Config/Mapping/HotkeyWii.cpp @@ -0,0 +1,39 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "DolphinQt2/Config/Mapping/HotkeyWii.h" + +#include +#include + +#include "Core/HotkeyManager.h" + +HotkeyWii::HotkeyWii(MappingWindow* window) : MappingWidget(window) +{ + CreateMainLayout(); +} + +void HotkeyWii::CreateMainLayout() +{ + m_main_layout = new QHBoxLayout(); + + m_main_layout->addWidget(CreateGroupBox(tr("Wii"), HotkeyManagerEmu::GetHotkeyGroup(HKGP_WII))); + + setLayout(m_main_layout); +} + +InputConfig* HotkeyWii::GetConfig() +{ + return HotkeyManagerEmu::GetConfig(); +} + +void HotkeyWii::LoadSettings() +{ + HotkeyManagerEmu::LoadConfig(); +} + +void HotkeyWii::SaveSettings() +{ + HotkeyManagerEmu::GetConfig()->SaveConfig(); +} diff --git a/Source/Core/DolphinQt2/Config/Mapping/HotkeyWii.h b/Source/Core/DolphinQt2/Config/Mapping/HotkeyWii.h new file mode 100644 index 0000000000..56906e8770 --- /dev/null +++ b/Source/Core/DolphinQt2/Config/Mapping/HotkeyWii.h @@ -0,0 +1,25 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include "DolphinQt2/Config/Mapping/MappingWidget.h" + +class QHBoxLayout; + +class HotkeyWii final : public MappingWidget +{ +public: + explicit HotkeyWii(MappingWindow* window); + + InputConfig* GetConfig() override; + +private: + void LoadSettings() override; + void SaveSettings() override; + void CreateMainLayout(); + + // Main + QHBoxLayout* m_main_layout; +}; diff --git a/Source/Core/DolphinQt2/Config/Mapping/MappingWindow.cpp b/Source/Core/DolphinQt2/Config/Mapping/MappingWindow.cpp index 04e20485b2..33e30a9b93 100644 --- a/Source/Core/DolphinQt2/Config/Mapping/MappingWindow.cpp +++ b/Source/Core/DolphinQt2/Config/Mapping/MappingWindow.cpp @@ -20,6 +20,12 @@ #include "DolphinQt2/Config/Mapping/GCKeyboardEmu.h" #include "DolphinQt2/Config/Mapping/GCPadEmu.h" #include "DolphinQt2/Config/Mapping/GCPadWiiU.h" +#include "DolphinQt2/Config/Mapping/Hotkey3D.h" +#include "DolphinQt2/Config/Mapping/HotkeyGeneral.h" +#include "DolphinQt2/Config/Mapping/HotkeyGraphics.h" +#include "DolphinQt2/Config/Mapping/HotkeyStates.h" +#include "DolphinQt2/Config/Mapping/HotkeyTAS.h" +#include "DolphinQt2/Config/Mapping/HotkeyWii.h" #include "DolphinQt2/Config/Mapping/WiimoteEmuExtension.h" #include "DolphinQt2/Config/Mapping/WiimoteEmuGeneral.h" #include "DolphinQt2/Config/Mapping/WiimoteEmuMotionControl.h" @@ -285,6 +291,18 @@ void MappingWindow::ChangeMappingType(MappingWindow::Type type) AddWidget(tr("Extension"), extension); break; } + case Type::MAPPING_HOTKEYS: + { + widget = new HotkeyGeneral(this); + AddWidget(tr("General"), widget); + AddWidget(tr("TAS Tools"), new HotkeyTAS(this)); + AddWidget(tr("Wii (Remote)"), new HotkeyWii(this)); + AddWidget(tr("Graphics"), new HotkeyGraphics(this)); + AddWidget(tr("3D"), new Hotkey3D(this)); + AddWidget(tr("Save States"), new HotkeyStates(this)); + setWindowTitle(tr("Hotkey Settings")); + break; + } default: return; } diff --git a/Source/Core/DolphinQt2/Config/Mapping/MappingWindow.h b/Source/Core/DolphinQt2/Config/Mapping/MappingWindow.h index c181f642b3..8e6fd82d7c 100644 --- a/Source/Core/DolphinQt2/Config/Mapping/MappingWindow.h +++ b/Source/Core/DolphinQt2/Config/Mapping/MappingWindow.h @@ -41,7 +41,9 @@ public: MAPPING_GC_STEERINGWHEEL, // Wii MAPPING_WIIMOTE_EMU, - MAPPING_WIIMOTE_HYBRID + MAPPING_WIIMOTE_HYBRID, + // Hotkeys + MAPPING_HOTKEYS }; explicit MappingWindow(QWidget* parent, int port_num); diff --git a/Source/Core/DolphinQt2/DolphinQt2.vcxproj b/Source/Core/DolphinQt2/DolphinQt2.vcxproj index 3e5ba69f0e..f1bce1701c 100644 --- a/Source/Core/DolphinQt2/DolphinQt2.vcxproj +++ b/Source/Core/DolphinQt2/DolphinQt2.vcxproj @@ -83,11 +83,13 @@ + + @@ -98,12 +100,14 @@ + + @@ -125,6 +129,12 @@ + + + + + + @@ -140,6 +150,7 @@ + @@ -147,6 +158,7 @@ + diff --git a/Source/Core/DolphinQt2/HotkeyScheduler.cpp b/Source/Core/DolphinQt2/HotkeyScheduler.cpp new file mode 100644 index 0000000000..3be862f8e1 --- /dev/null +++ b/Source/Core/DolphinQt2/HotkeyScheduler.cpp @@ -0,0 +1,363 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "DolphinQt2/HotkeyScheduler.h" + +#include +#include + +#include + +#include "AudioCommon/AudioCommon.h" +#include "Common/Thread.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/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++; + + // TODO GUI Update (Depends on an unimplemented feature) + // if ((frame_step_count == 0 || frame_step_count == FRAME_STEP_DELAY) && !frame_step_hold) + + if (frame_step_count < FRAME_STEP_DELAY) + { + ++frame_step_count; + if (frame_step_hold) + 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; + } + + 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; + + // Fullscreen + if (IsHotkey(HK_FULLSCREEN)) + emit FullScreenHotkey(); + + // Pause and Unpause + if (IsHotkey(HK_PLAY_PAUSE)) + emit PauseHotkey(); + + // Stop + if (IsHotkey(HK_STOP)) + emit StopHotkey(); + + // Frameskipping + HandleFrameskipHotkeys(); + + // Screenshot + if (IsHotkey(HK_SCREENSHOT)) + emit ScreenShotHotkey(); + + // Exit + if (IsHotkey(HK_EXIT)) + emit ExitHotkey(); + + // Volume + if (IsHotkey(HK_VOLUME_DOWN)) + AudioCommon::DecreaseVolume(3); + + if (IsHotkey(HK_VOLUME_UP)) + AudioCommon::IncreaseVolume(3); + + if (IsHotkey(HK_VOLUME_TOGGLE_MUTE)) + AudioCommon::ToggleMuteVolume(); + + auto& settings = Settings::Instance(); + + // Wiimote + if (settings.IsBluetoothPassthroughEnabled()) + { + const auto ios = IOS::HLE::GetIOS(); + auto device = ios ? ios->GetDeviceByName("/dev/usb/oh1/57e/305") : nullptr; + + if (device != nullptr) + std::static_pointer_cast(device)->UpdateSyncButtonState( + IsHotkey(HK_TRIGGER_SYNC_BUTTON, true)); + } + + // TODO Debugging shortcuts (Separate PR) + + if (settings.IsWiiGameRunning()) + { + 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; + + // TODO Implement Wiimote connecting / disconnecting (Separate PR) + // if (wiimote_id > -1) + } + + // Graphics + if (IsHotkey(HK_INCREASE_IR)) + ++g_Config.iEFBScale; + if (IsHotkey(HK_DECREASE_IR)) + g_Config.iEFBScale = std::max(g_Config.iEFBScale - 1, static_cast(SCALE_AUTO)); + if (IsHotkey(HK_TOGGLE_CROP)) + g_Config.bCrop = !g_Config.bCrop; + if (IsHotkey(HK_TOGGLE_AR)) + g_Config.iAspectRatio = (g_Config.iAspectRatio + 1) & 3; + if (IsHotkey(HK_TOGGLE_EFBCOPIES)) + g_Config.bSkipEFBCopyToRam = !g_Config.bSkipEFBCopyToRam; + if (IsHotkey(HK_TOGGLE_FOG)) + g_Config.bDisableFog = !g_Config.bDisableFog; + if (IsHotkey(HK_TOGGLE_DUMPTEXTURES)) + g_Config.bDumpTextures = !g_Config.bDumpTextures; + if (IsHotkey(HK_TOGGLE_TEXTURES)) + g_Config.bHiresTextures = !g_Config.bHiresTextures; + + Core::SetIsThrottlerTempDisabled(IsHotkey(HK_TOGGLE_THROTTLE, true)); + + if (IsHotkey(HK_DECREASE_EMULATION_SPEED)) + { + auto speed = settings.GetEmulationSpeed() - 0.1; + speed = (speed <= 0 || (speed >= 0.95 && speed <= 1.05)) ? 1.0 : speed; + settings.SetEmulationSpeed(speed); + } + + if (IsHotkey(HK_INCREASE_EMULATION_SPEED)) + { + auto speed = settings.GetEmulationSpeed() + 0.1; + speed = (speed >= 0.95 && speed <= 1.05) ? 1.0 : speed; + settings.SetEmulationSpeed(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 (g_Config.iStereoMode != STEREO_SBS) + { + // Disable post-processing shader, as stereoscopy itself is currently a shader + if (g_Config.sPostProcessingShader == DUBOIS_ALGORITHM_SHADER) + g_Config.sPostProcessingShader = ""; + + g_Config.iStereoMode = IsHotkey(HK_TOGGLE_STEREO_SBS) ? STEREO_SBS : STEREO_TAB; + } + else + { + g_Config.iStereoMode = STEREO_OFF; + } + } + + if (IsHotkey(HK_TOGGLE_STEREO_ANAGLYPH)) + { + if (g_Config.iStereoMode != STEREO_ANAGLYPH) + { + g_Config.iStereoMode = STEREO_ANAGLYPH; + g_Config.sPostProcessingShader = DUBOIS_ALGORITHM_SHADER; + } + else + { + g_Config.iStereoMode = STEREO_OFF; + g_Config.sPostProcessingShader = ""; + } + } + + if (IsHotkey(HK_TOGGLE_STEREO_3DVISION)) + { + if (g_Config.iStereoMode != STEREO_3DVISION) + { + if (g_Config.sPostProcessingShader == DUBOIS_ALGORITHM_SHADER) + g_Config.sPostProcessingShader = ""; + + g_Config.iStereoMode = STEREO_3DVISION; + } + else + { + g_Config.iStereoMode = STEREO_OFF; + } + } + } + + if (IsHotkey(HK_DECREASE_DEPTH, true)) + g_Config.iStereoDepth = std::max(g_Config.iStereoDepth - 1, 0); + + if (IsHotkey(HK_INCREASE_DEPTH, true)) + g_Config.iStereoDepth = std::min(g_Config.iStereoDepth + 1, 100); + + if (IsHotkey(HK_DECREASE_CONVERGENCE, true)) + g_Config.iStereoConvergence = std::max(g_Config.iStereoConvergence - 5, 0); + + if (IsHotkey(HK_INCREASE_CONVERGENCE, true)) + g_Config.iStereoConvergence = std::min(g_Config.iStereoConvergence + 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(); + } +} diff --git a/Source/Core/DolphinQt2/HotkeyScheduler.h b/Source/Core/DolphinQt2/HotkeyScheduler.h new file mode 100644 index 0000000000..2deebbce16 --- /dev/null +++ b/Source/Core/DolphinQt2/HotkeyScheduler.h @@ -0,0 +1,37 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include + +#include + +#include "Common/Flag.h" + +class HotkeyScheduler : public QObject +{ + Q_OBJECT +public: + explicit HotkeyScheduler(); + ~HotkeyScheduler(); + + void Start(); + void Stop(); +signals: + void ExitHotkey(); + void FullScreenHotkey(); + void StopHotkey(); + void PauseHotkey(); + void ScreenShotHotkey(); + void SetStateSlotHotkey(int slot); + void StateLoadSlotHotkey(); + void StateSaveSlotHotkey(); + +private: + void Run(); + + Common::Flag m_stop_requested; + std::thread m_thread; +}; diff --git a/Source/Core/DolphinQt2/MainWindow.cpp b/Source/Core/DolphinQt2/MainWindow.cpp index a8049826f2..a487e37b2a 100644 --- a/Source/Core/DolphinQt2/MainWindow.cpp +++ b/Source/Core/DolphinQt2/MainWindow.cpp @@ -24,9 +24,13 @@ #include "DolphinQt2/AboutDialog.h" #include "DolphinQt2/Config/ControllersWindow.h" + +#include "DolphinQt2/Config/Mapping/MappingWindow.h" #include "DolphinQt2/Config/SettingsWindow.h" #include "DolphinQt2/Host.h" +#include "DolphinQt2/HotkeyScheduler.h" #include "DolphinQt2/MainWindow.h" +#include "DolphinQt2/QtUtils/FocusEventFilter.h" #include "DolphinQt2/Resources.h" #include "DolphinQt2/Settings.h" @@ -64,16 +68,32 @@ void MainWindow::InitControllers() Pad::Initialize(); Keyboard::Initialize(); Wiimote::Initialize(Wiimote::InitializeMode::DO_NOT_WAIT_FOR_WIIMOTES); - HotkeyManagerEmu::Initialize(); + m_hotkey_scheduler = new HotkeyScheduler(); + m_hotkey_scheduler->Start(); + + ConnectHotkeys(); } void MainWindow::ShutdownControllers() { + m_hotkey_scheduler->Stop(); + g_controller_interface.Shutdown(); Pad::Shutdown(); Keyboard::Shutdown(); Wiimote::Shutdown(); HotkeyManagerEmu::Shutdown(); + + m_hotkey_scheduler->deleteLater(); +} + +static void InstallHotkeyFilter(QDialog* dialog) +{ + auto* filter = new FocusEventFilter(); + dialog->installEventFilter(filter); + + filter->connect(filter, &FocusEventFilter::focusOutEvent, [] { HotkeyManagerEmu::Enable(true); }); + filter->connect(filter, &FocusEventFilter::focusInEvent, [] { HotkeyManagerEmu::Enable(false); }); } void MainWindow::CreateComponents() @@ -85,6 +105,11 @@ void MainWindow::CreateComponents() m_stack = new QStackedWidget(this); m_controllers_window = new ControllersWindow(this); m_settings_window = new SettingsWindow(this); + m_hotkey_window = new MappingWindow(this, 0); + + InstallHotkeyFilter(m_hotkey_window); + InstallHotkeyFilter(m_controllers_window); + InstallHotkeyFilter(m_settings_window); } void MainWindow::ConnectMenuBar() @@ -113,6 +138,9 @@ void MainWindow::ConnectMenuBar() connect(m_menu_bar, &MenuBar::StateSaveOldest, this, &MainWindow::StateSaveOldest); connect(m_menu_bar, &MenuBar::SetStateSlot, this, &MainWindow::SetStateSlot); + // Options + connect(m_menu_bar, &MenuBar::ConfigureHotkeys, this, &MainWindow::ShowHotkeyDialog); + // View connect(m_menu_bar, &MenuBar::ShowTable, m_game_list, &GameList::SetTableView); connect(m_menu_bar, &MenuBar::ShowList, m_game_list, &GameList::SetListView); @@ -130,6 +158,22 @@ void MainWindow::ConnectMenuBar() [=]() { m_controllers_window->OnEmulationStateChanged(false); }); } +void MainWindow::ConnectHotkeys() +{ + connect(m_hotkey_scheduler, &HotkeyScheduler::ExitHotkey, this, &MainWindow::close); + connect(m_hotkey_scheduler, &HotkeyScheduler::PauseHotkey, this, &MainWindow::Pause); + connect(m_hotkey_scheduler, &HotkeyScheduler::StopHotkey, this, &MainWindow::Stop); + connect(m_hotkey_scheduler, &HotkeyScheduler::ScreenShotHotkey, this, &MainWindow::ScreenShot); + connect(m_hotkey_scheduler, &HotkeyScheduler::FullScreenHotkey, this, &MainWindow::FullScreen); + + connect(m_hotkey_scheduler, &HotkeyScheduler::StateLoadSlotHotkey, this, + &MainWindow::StateLoadSlot); + connect(m_hotkey_scheduler, &HotkeyScheduler::StateSaveSlotHotkey, this, + &MainWindow::StateSaveSlot); + connect(m_hotkey_scheduler, &HotkeyScheduler::SetStateSlotHotkey, this, + &MainWindow::SetStateSlot); +} + void MainWindow::ConnectToolBar() { addToolBar(m_tool_bar); @@ -364,6 +408,14 @@ void MainWindow::ShowAboutDialog() about->show(); } +void MainWindow::ShowHotkeyDialog() +{ + m_hotkey_window->ChangeMappingType(MappingWindow::Type::MAPPING_HOTKEYS); + m_hotkey_window->show(); + m_hotkey_window->raise(); + m_hotkey_window->activateWindow(); +} + void MainWindow::StateLoad() { QString path = QFileDialog::getOpenFileName(this, tr("Select a File"), QDir::currentPath(), diff --git a/Source/Core/DolphinQt2/MainWindow.h b/Source/Core/DolphinQt2/MainWindow.h index 5e089c2572..2b9b2c4e90 100644 --- a/Source/Core/DolphinQt2/MainWindow.h +++ b/Source/Core/DolphinQt2/MainWindow.h @@ -14,6 +14,8 @@ #include "DolphinQt2/RenderWidget.h" #include "DolphinQt2/ToolBar.h" +class HotkeyScheduler; +class MappingWindow; class SettingsWindow; class ControllersWindow; @@ -58,6 +60,7 @@ private: void CreateComponents(); void ConnectGameList(); + void ConnectHotkeys(); void ConnectMenuBar(); void ConnectRenderWidget(); void ConnectStack(); @@ -73,6 +76,7 @@ private: void ShowSettingsWindow(); void ShowControllersWindow(); void ShowAboutDialog(); + void ShowHotkeyDialog(); QStackedWidget* m_stack; ToolBar* m_tool_bar; @@ -82,6 +86,8 @@ private: bool m_rendering_to_main; int m_state_slot = 1; + HotkeyScheduler* m_hotkey_scheduler; ControllersWindow* m_controllers_window; SettingsWindow* m_settings_window; + MappingWindow* m_hotkey_window; }; diff --git a/Source/Core/DolphinQt2/MenuBar.cpp b/Source/Core/DolphinQt2/MenuBar.cpp index ef9a449621..011649e0e1 100644 --- a/Source/Core/DolphinQt2/MenuBar.cpp +++ b/Source/Core/DolphinQt2/MenuBar.cpp @@ -20,7 +20,7 @@ MenuBar::MenuBar(QWidget* parent) : QMenuBar(parent) AddFileMenu(); AddEmulationMenu(); addMenu(tr("Movie")); - addMenu(tr("Options")); + AddOptionsMenu(); AddToolsMenu(); AddViewMenu(); AddHelpMenu(); @@ -171,6 +171,12 @@ void MenuBar::AddViewMenu() AddTableColumnsMenu(view_menu); } +void MenuBar::AddOptionsMenu() +{ + QMenu* options_menu = addMenu(tr("Options")); + options_menu->addAction(tr("Hotkey Settings"), this, &MenuBar::ConfigureHotkeys); +} + void MenuBar::AddHelpMenu() { QMenu* help_menu = addMenu(tr("Help")); diff --git a/Source/Core/DolphinQt2/MenuBar.h b/Source/Core/DolphinQt2/MenuBar.h index fa8c67cc38..a0346f4277 100644 --- a/Source/Core/DolphinQt2/MenuBar.h +++ b/Source/Core/DolphinQt2/MenuBar.h @@ -38,6 +38,9 @@ signals: void StateSaveOldest(); void SetStateSlot(int slot); + // Options + void ConfigureHotkeys(); + // View void ShowTable(); void ShowList(); @@ -66,6 +69,7 @@ private: void AddGameListTypeSection(QMenu* view_menu); void AddTableColumnsMenu(QMenu* view_menu); + void AddOptionsMenu(); void AddToolsMenu(); void AddHelpMenu(); diff --git a/Source/Core/DolphinQt2/QtUtils/FocusEventFilter.cpp b/Source/Core/DolphinQt2/QtUtils/FocusEventFilter.cpp new file mode 100644 index 0000000000..c6023f4ff7 --- /dev/null +++ b/Source/Core/DolphinQt2/QtUtils/FocusEventFilter.cpp @@ -0,0 +1,19 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include +#include + +#include "DolphinQt2/QtUtils/FocusEventFilter.h" + +bool FocusEventFilter::eventFilter(QObject* object, QEvent* event) +{ + if (event->type() == QEvent::FocusOut) + emit focusOutEvent(); + + if (event->type() == QEvent::FocusIn) + emit focusInEvent(); + + return false; +} diff --git a/Source/Core/DolphinQt2/QtUtils/FocusEventFilter.h b/Source/Core/DolphinQt2/QtUtils/FocusEventFilter.h new file mode 100644 index 0000000000..0783622b0f --- /dev/null +++ b/Source/Core/DolphinQt2/QtUtils/FocusEventFilter.h @@ -0,0 +1,18 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include + +class FocusEventFilter : public QObject +{ + Q_OBJECT +signals: + void focusInEvent(); + void focusOutEvent(); + +private: + bool eventFilter(QObject* object, QEvent* event) override; +};