summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2019-04-09 18:08:30 -0400
committerGravatar GitHub2019-04-09 18:08:30 -0400
commit1a3098f11a21bd102c63f2bc4ebb01789d3fd93e (patch)
tree8f977d1f87ff108edaf285ee1569cdff64d747d2 /src
parentMerge pull request #2370 from lioncash/qt-warn (diff)
parentyuzu: Make hotkeys configurable via the GUI (diff)
downloadyuzu-1a3098f11a21bd102c63f2bc4ebb01789d3fd93e.tar.gz
yuzu-1a3098f11a21bd102c63f2bc4ebb01789d3fd93e.tar.xz
yuzu-1a3098f11a21bd102c63f2bc4ebb01789d3fd93e.zip
Merge pull request #2132 from FearlessTobi/port-4437
Port citra-emu/citra#4437: "citra-qt: Make hotkeys configurable via the GUI (Attempt 2)"
Diffstat (limited to 'src')
-rw-r--r--src/yuzu/CMakeLists.txt6
-rw-r--r--src/yuzu/applets/profile_select.cpp1
-rw-r--r--src/yuzu/applets/profile_select.h2
-rw-r--r--src/yuzu/configuration/config.cpp59
-rw-r--r--src/yuzu/configuration/config.h3
-rw-r--r--src/yuzu/configuration/configure.ui19
-rw-r--r--src/yuzu/configuration/configure_dialog.cpp16
-rw-r--r--src/yuzu/configuration/configure_dialog.h3
-rw-r--r--src/yuzu/configuration/configure_general.cpp4
-rw-r--r--src/yuzu/configuration/configure_general.h1
-rw-r--r--src/yuzu/configuration/configure_general.ui24
-rw-r--r--src/yuzu/configuration/configure_hotkeys.cpp121
-rw-r--r--src/yuzu/configuration/configure_hotkeys.h48
-rw-r--r--src/yuzu/configuration/configure_hotkeys.ui42
-rw-r--r--src/yuzu/hotkeys.cpp73
-rw-r--r--src/yuzu/hotkeys.h42
-rw-r--r--src/yuzu/hotkeys.ui46
-rw-r--r--src/yuzu/main.cpp53
-rw-r--r--src/yuzu/main.h2
-rw-r--r--src/yuzu/ui_settings.cpp1
-rw-r--r--src/yuzu/ui_settings.h7
-rw-r--r--src/yuzu/util/sequence_dialog/sequence_dialog.cpp37
-rw-r--r--src/yuzu/util/sequence_dialog/sequence_dialog.h24
23 files changed, 426 insertions, 208 deletions
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 4cab599b4..732a1bf89 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -31,6 +31,8 @@ add_executable(yuzu
31 configuration/configure_general.h 31 configuration/configure_general.h
32 configuration/configure_graphics.cpp 32 configuration/configure_graphics.cpp
33 configuration/configure_graphics.h 33 configuration/configure_graphics.h
34 configuration/configure_hotkeys.cpp
35 configuration/configure_hotkeys.h
34 configuration/configure_input.cpp 36 configuration/configure_input.cpp
35 configuration/configure_input.h 37 configuration/configure_input.h
36 configuration/configure_input_player.cpp 38 configuration/configure_input_player.cpp
@@ -78,6 +80,8 @@ add_executable(yuzu
78 ui_settings.h 80 ui_settings.h
79 util/limitable_input_dialog.cpp 81 util/limitable_input_dialog.cpp
80 util/limitable_input_dialog.h 82 util/limitable_input_dialog.h
83 util/sequence_dialog/sequence_dialog.cpp
84 util/sequence_dialog/sequence_dialog.h
81 util/spinbox.cpp 85 util/spinbox.cpp
82 util/spinbox.h 86 util/spinbox.h
83 util/util.cpp 87 util/util.cpp
@@ -95,6 +99,7 @@ set(UIS
95 configuration/configure_gamelist.ui 99 configuration/configure_gamelist.ui
96 configuration/configure_general.ui 100 configuration/configure_general.ui
97 configuration/configure_graphics.ui 101 configuration/configure_graphics.ui
102 configuration/configure_hotkeys.ui
98 configuration/configure_input.ui 103 configuration/configure_input.ui
99 configuration/configure_input_player.ui 104 configuration/configure_input_player.ui
100 configuration/configure_input_simple.ui 105 configuration/configure_input_simple.ui
@@ -105,7 +110,6 @@ set(UIS
105 configuration/configure_touchscreen_advanced.ui 110 configuration/configure_touchscreen_advanced.ui
106 configuration/configure_web.ui 111 configuration/configure_web.ui
107 compatdb.ui 112 compatdb.ui
108 hotkeys.ui
109 loading_screen.ui 113 loading_screen.ui
110 main.ui 114 main.ui
111) 115)
diff --git a/src/yuzu/applets/profile_select.cpp b/src/yuzu/applets/profile_select.cpp
index f95f7fe3c..743b24d76 100644
--- a/src/yuzu/applets/profile_select.cpp
+++ b/src/yuzu/applets/profile_select.cpp
@@ -4,6 +4,7 @@
4 4
5#include <mutex> 5#include <mutex>
6#include <QDialogButtonBox> 6#include <QDialogButtonBox>
7#include <QHeaderView>
7#include <QLabel> 8#include <QLabel>
8#include <QLineEdit> 9#include <QLineEdit>
9#include <QScrollArea> 10#include <QScrollArea>
diff --git a/src/yuzu/applets/profile_select.h b/src/yuzu/applets/profile_select.h
index 868573324..1c2922e54 100644
--- a/src/yuzu/applets/profile_select.h
+++ b/src/yuzu/applets/profile_select.h
@@ -7,6 +7,7 @@
7#include <vector> 7#include <vector>
8#include <QDialog> 8#include <QDialog>
9#include <QList> 9#include <QList>
10#include <QTreeView>
10#include "core/frontend/applets/profile_select.h" 11#include "core/frontend/applets/profile_select.h"
11 12
12class GMainWindow; 13class GMainWindow;
@@ -16,7 +17,6 @@ class QLabel;
16class QScrollArea; 17class QScrollArea;
17class QStandardItem; 18class QStandardItem;
18class QStandardItemModel; 19class QStandardItemModel;
19class QTreeView;
20class QVBoxLayout; 20class QVBoxLayout;
21 21
22class QtProfileSelectionDialog final : public QDialog { 22class QtProfileSelectionDialog final : public QDialog {
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index dead9f807..802db3945 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -2,6 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <array>
6#include <QKeySequence>
5#include <QSettings> 7#include <QSettings>
6#include "common/file_util.h" 8#include "common/file_util.h"
7#include "configure_input_simple.h" 9#include "configure_input_simple.h"
@@ -9,7 +11,6 @@
9#include "core/hle/service/hid/controllers/npad.h" 11#include "core/hle/service/hid/controllers/npad.h"
10#include "input_common/main.h" 12#include "input_common/main.h"
11#include "yuzu/configuration/config.h" 13#include "yuzu/configuration/config.h"
12#include "yuzu/ui_settings.h"
13 14
14Config::Config() { 15Config::Config() {
15 // TODO: Don't hardcode the path; let the frontend decide where to put the config files. 16 // TODO: Don't hardcode the path; let the frontend decide where to put the config files.
@@ -17,7 +18,6 @@ Config::Config() {
17 FileUtil::CreateFullPath(qt_config_loc); 18 FileUtil::CreateFullPath(qt_config_loc);
18 qt_config = 19 qt_config =
19 std::make_unique<QSettings>(QString::fromStdString(qt_config_loc), QSettings::IniFormat); 20 std::make_unique<QSettings>(QString::fromStdString(qt_config_loc), QSettings::IniFormat);
20
21 Reload(); 21 Reload();
22} 22}
23 23
@@ -205,6 +205,27 @@ const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> Config::default
205 Qt::Key_Control, Qt::Key_Shift, Qt::Key_AltGr, Qt::Key_ApplicationRight, 205 Qt::Key_Control, Qt::Key_Shift, Qt::Key_AltGr, Qt::Key_ApplicationRight,
206}; 206};
207 207
208// This shouldn't have anything except static initializers (no functions). So
209// QKeySequnce(...).toString() is NOT ALLOWED HERE.
210// This must be in alphabetical order according to action name as it must have the same order as
211// UISetting::values.shortcuts, which is alphabetically ordered.
212const std::array<UISettings::Shortcut, 15> Config::default_hotkeys{
213 {{"Capture Screenshot", "Main Window", {"Ctrl+P", Qt::ApplicationShortcut}},
214 {"Continue/Pause Emulation", "Main Window", {"F4", Qt::WindowShortcut}},
215 {"Decrease Speed Limit", "Main Window", {"-", Qt::ApplicationShortcut}},
216 {"Exit yuzu", "Main Window", {"Ctrl+Q", Qt::WindowShortcut}},
217 {"Exit Fullscreen", "Main Window", {"Esc", Qt::WindowShortcut}},
218 {"Fullscreen", "Main Window", {"F11", Qt::WindowShortcut}},
219 {"Increase Speed Limit", "Main Window", {"+", Qt::ApplicationShortcut}},
220 {"Load Amiibo", "Main Window", {"F2", Qt::ApplicationShortcut}},
221 {"Load File", "Main Window", {"Ctrl+O", Qt::WindowShortcut}},
222 {"Restart Emulation", "Main Window", {"F6", Qt::WindowShortcut}},
223 {"Stop Emulation", "Main Window", {"F5", Qt::WindowShortcut}},
224 {"Toggle Filter Bar", "Main Window", {"Ctrl+F", Qt::WindowShortcut}},
225 {"Toggle Speed Limit", "Main Window", {"Ctrl+Z", Qt::ApplicationShortcut}},
226 {"Toggle Status Bar", "Main Window", {"Ctrl+S", Qt::WindowShortcut}},
227 {"Change Docked Mode", "Main Window", {"F10", Qt::ApplicationShortcut}}}};
228
208void Config::ReadPlayerValues() { 229void Config::ReadPlayerValues() {
209 for (std::size_t p = 0; p < Settings::values.players.size(); ++p) { 230 for (std::size_t p = 0; p < Settings::values.players.size(); ++p) {
210 auto& player = Settings::values.players[p]; 231 auto& player = Settings::values.players[p];
@@ -508,20 +529,15 @@ void Config::ReadValues() {
508 qt_config->endGroup(); 529 qt_config->endGroup();
509 530
510 qt_config->beginGroup("Shortcuts"); 531 qt_config->beginGroup("Shortcuts");
511 QStringList groups = qt_config->childGroups(); 532 for (auto [name, group, shortcut] : default_hotkeys) {
512 for (auto group : groups) { 533 auto [keyseq, context] = shortcut;
513 qt_config->beginGroup(group); 534 qt_config->beginGroup(group);
514 535 qt_config->beginGroup(name);
515 QStringList hotkeys = qt_config->childGroups(); 536 UISettings::values.shortcuts.push_back(
516 for (auto hotkey : hotkeys) { 537 {name,
517 qt_config->beginGroup(hotkey); 538 group,
518 UISettings::values.shortcuts.emplace_back(UISettings::Shortcut( 539 {ReadSetting("KeySeq", keyseq).toString(), ReadSetting("Context", context).toInt()}});
519 group + "/" + hotkey, 540 qt_config->endGroup();
520 UISettings::ContextualShortcut(ReadSetting("KeySeq").toString(),
521 ReadSetting("Context").toInt())));
522 qt_config->endGroup();
523 }
524
525 qt_config->endGroup(); 541 qt_config->endGroup();
526 } 542 }
527 qt_config->endGroup(); 543 qt_config->endGroup();
@@ -758,9 +774,16 @@ void Config::SaveValues() {
758 qt_config->endGroup(); 774 qt_config->endGroup();
759 775
760 qt_config->beginGroup("Shortcuts"); 776 qt_config->beginGroup("Shortcuts");
761 for (auto shortcut : UISettings::values.shortcuts) { 777 // Lengths of UISettings::values.shortcuts & default_hotkeys are same.
762 WriteSetting(shortcut.first + "/KeySeq", shortcut.second.first); 778 // However, their ordering must also be the same.
763 WriteSetting(shortcut.first + "/Context", shortcut.second.second); 779 for (std::size_t i = 0; i < default_hotkeys.size(); i++) {
780 auto [name, group, shortcut] = UISettings::values.shortcuts[i];
781 qt_config->beginGroup(group);
782 qt_config->beginGroup(name);
783 WriteSetting("KeySeq", shortcut.first, default_hotkeys[i].shortcut.first);
784 WriteSetting("Context", shortcut.second, default_hotkeys[i].shortcut.second);
785 qt_config->endGroup();
786 qt_config->endGroup();
764 } 787 }
765 qt_config->endGroup(); 788 qt_config->endGroup();
766 789
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index f4185db18..221d2364c 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -9,6 +9,7 @@
9#include <string> 9#include <string>
10#include <QVariant> 10#include <QVariant>
11#include "core/settings.h" 11#include "core/settings.h"
12#include "yuzu/ui_settings.h"
12 13
13class QSettings; 14class QSettings;
14 15
@@ -47,6 +48,8 @@ private:
47 void WriteSetting(const QString& name, const QVariant& value); 48 void WriteSetting(const QString& name, const QVariant& value);
48 void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value); 49 void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value);
49 50
51 static const std::array<UISettings::Shortcut, 15> default_hotkeys;
52
50 std::unique_ptr<QSettings> qt_config; 53 std::unique_ptr<QSettings> qt_config;
51 std::string qt_config_loc; 54 std::string qt_config_loc;
52}; 55};
diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui
index 3f03f0b77..267717bc9 100644
--- a/src/yuzu/configuration/configure.ui
+++ b/src/yuzu/configuration/configure.ui
@@ -7,9 +7,15 @@
7 <x>0</x> 7 <x>0</x>
8 <y>0</y> 8 <y>0</y>
9 <width>382</width> 9 <width>382</width>
10 <height>241</height> 10 <height>650</height>
11 </rect> 11 </rect>
12 </property> 12 </property>
13 <property name="minimumSize">
14 <size>
15 <width>0</width>
16 <height>650</height>
17 </size>
18 </property>
13 <property name="windowTitle"> 19 <property name="windowTitle">
14 <string>yuzu Configuration</string> 20 <string>yuzu Configuration</string>
15 </property> 21 </property>
@@ -62,6 +68,11 @@
62 <string>Input</string> 68 <string>Input</string>
63 </attribute> 69 </attribute>
64 </widget> 70 </widget>
71 <widget class="ConfigureHotkeys" name="hotkeysTab">
72 <attribute name="title">
73 <string>Hotkeys</string>
74 </attribute>
75 </widget>
65 <widget class="ConfigureGraphics" name="graphicsTab"> 76 <widget class="ConfigureGraphics" name="graphicsTab">
66 <attribute name="title"> 77 <attribute name="title">
67 <string>Graphics</string> 78 <string>Graphics</string>
@@ -150,6 +161,12 @@
150 <header>configuration/configure_input_simple.h</header> 161 <header>configuration/configure_input_simple.h</header>
151 <container>1</container> 162 <container>1</container>
152 </customwidget> 163 </customwidget>
164 <customwidget>
165 <class>ConfigureHotkeys</class>
166 <extends>QWidget</extends>
167 <header>configuration/configure_hotkeys.h</header>
168 <container>1</container>
169 </customwidget>
153 </customwidgets> 170 </customwidgets>
154 <resources/> 171 <resources/>
155 <connections> 172 <connections>
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp
index 777050405..51bd1f121 100644
--- a/src/yuzu/configuration/configure_dialog.cpp
+++ b/src/yuzu/configuration/configure_dialog.cpp
@@ -8,20 +8,22 @@
8#include "ui_configure.h" 8#include "ui_configure.h"
9#include "yuzu/configuration/config.h" 9#include "yuzu/configuration/config.h"
10#include "yuzu/configuration/configure_dialog.h" 10#include "yuzu/configuration/configure_dialog.h"
11#include "yuzu/configuration/configure_input_player.h"
11#include "yuzu/hotkeys.h" 12#include "yuzu/hotkeys.h"
12 13
13ConfigureDialog::ConfigureDialog(QWidget* parent, const HotkeyRegistry& registry) 14ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry)
14 : QDialog(parent), ui(new Ui::ConfigureDialog) { 15 : QDialog(parent), registry(registry), ui(new Ui::ConfigureDialog) {
15 ui->setupUi(this); 16 ui->setupUi(this);
16 ui->generalTab->PopulateHotkeyList(registry); 17 ui->hotkeysTab->Populate(registry);
17 this->setConfiguration(); 18 this->setConfiguration();
18 this->PopulateSelectionList(); 19 this->PopulateSelectionList();
19 connect(ui->selectorList, &QListWidget::itemSelectionChanged, this, 20 connect(ui->selectorList, &QListWidget::itemSelectionChanged, this,
20 &ConfigureDialog::UpdateVisibleTabs); 21 &ConfigureDialog::UpdateVisibleTabs);
21
22 adjustSize(); 22 adjustSize();
23
24 ui->selectorList->setCurrentRow(0); 23 ui->selectorList->setCurrentRow(0);
24
25 // Synchronise lists upon initialisation
26 ui->hotkeysTab->EmitHotkeysChanged();
25} 27}
26 28
27ConfigureDialog::~ConfigureDialog() = default; 29ConfigureDialog::~ConfigureDialog() = default;
@@ -34,6 +36,7 @@ void ConfigureDialog::applyConfiguration() {
34 ui->systemTab->applyConfiguration(); 36 ui->systemTab->applyConfiguration();
35 ui->profileManagerTab->applyConfiguration(); 37 ui->profileManagerTab->applyConfiguration();
36 ui->inputTab->applyConfiguration(); 38 ui->inputTab->applyConfiguration();
39 ui->hotkeysTab->applyConfiguration(registry);
37 ui->graphicsTab->applyConfiguration(); 40 ui->graphicsTab->applyConfiguration();
38 ui->audioTab->applyConfiguration(); 41 ui->audioTab->applyConfiguration();
39 ui->debugTab->applyConfiguration(); 42 ui->debugTab->applyConfiguration();
@@ -47,7 +50,7 @@ void ConfigureDialog::PopulateSelectionList() {
47 {{tr("General"), {tr("General"), tr("Web"), tr("Debug"), tr("Game List")}}, 50 {{tr("General"), {tr("General"), tr("Web"), tr("Debug"), tr("Game List")}},
48 {tr("System"), {tr("System"), tr("Profiles"), tr("Audio")}}, 51 {tr("System"), {tr("System"), tr("Profiles"), tr("Audio")}},
49 {tr("Graphics"), {tr("Graphics")}}, 52 {tr("Graphics"), {tr("Graphics")}},
50 {tr("Controls"), {tr("Input")}}}}; 53 {tr("Controls"), {tr("Input"), tr("Hotkeys")}}}};
51 54
52 for (const auto& entry : items) { 55 for (const auto& entry : items) {
53 auto* const item = new QListWidgetItem(entry.first); 56 auto* const item = new QListWidgetItem(entry.first);
@@ -66,6 +69,7 @@ void ConfigureDialog::UpdateVisibleTabs() {
66 {tr("System"), ui->systemTab}, 69 {tr("System"), ui->systemTab},
67 {tr("Profiles"), ui->profileManagerTab}, 70 {tr("Profiles"), ui->profileManagerTab},
68 {tr("Input"), ui->inputTab}, 71 {tr("Input"), ui->inputTab},
72 {tr("Hotkeys"), ui->hotkeysTab},
69 {tr("Graphics"), ui->graphicsTab}, 73 {tr("Graphics"), ui->graphicsTab},
70 {tr("Audio"), ui->audioTab}, 74 {tr("Audio"), ui->audioTab},
71 {tr("Debug"), ui->debugTab}, 75 {tr("Debug"), ui->debugTab},
diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h
index 243d9fa09..2363ba584 100644
--- a/src/yuzu/configuration/configure_dialog.h
+++ b/src/yuzu/configuration/configure_dialog.h
@@ -17,7 +17,7 @@ class ConfigureDialog : public QDialog {
17 Q_OBJECT 17 Q_OBJECT
18 18
19public: 19public:
20 explicit ConfigureDialog(QWidget* parent, const HotkeyRegistry& registry); 20 explicit ConfigureDialog(QWidget* parent, HotkeyRegistry& registry);
21 ~ConfigureDialog() override; 21 ~ConfigureDialog() override;
22 22
23 void applyConfiguration(); 23 void applyConfiguration();
@@ -28,4 +28,5 @@ private:
28 void PopulateSelectionList(); 28 void PopulateSelectionList();
29 29
30 std::unique_ptr<Ui::ConfigureDialog> ui; 30 std::unique_ptr<Ui::ConfigureDialog> ui;
31 HotkeyRegistry& registry;
31}; 32};
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index 389fcf667..eeb038afb 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -35,10 +35,6 @@ void ConfigureGeneral::setConfiguration() {
35 ui->use_cpu_jit->setChecked(Settings::values.use_cpu_jit); 35 ui->use_cpu_jit->setChecked(Settings::values.use_cpu_jit);
36} 36}
37 37
38void ConfigureGeneral::PopulateHotkeyList(const HotkeyRegistry& registry) {
39 ui->widget->Populate(registry);
40}
41
42void ConfigureGeneral::applyConfiguration() { 38void ConfigureGeneral::applyConfiguration() {
43 UISettings::values.gamedir_deepscan = ui->toggle_deepscan->isChecked(); 39 UISettings::values.gamedir_deepscan = ui->toggle_deepscan->isChecked();
44 UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked(); 40 UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
diff --git a/src/yuzu/configuration/configure_general.h b/src/yuzu/configuration/configure_general.h
index 59738af40..df41d995b 100644
--- a/src/yuzu/configuration/configure_general.h
+++ b/src/yuzu/configuration/configure_general.h
@@ -20,7 +20,6 @@ public:
20 explicit ConfigureGeneral(QWidget* parent = nullptr); 20 explicit ConfigureGeneral(QWidget* parent = nullptr);
21 ~ConfigureGeneral() override; 21 ~ConfigureGeneral() override;
22 22
23 void PopulateHotkeyList(const HotkeyRegistry& registry);
24 void applyConfiguration(); 23 void applyConfiguration();
25 24
26private: 25private:
diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui
index 01d1c0b8e..1a5721fe7 100644
--- a/src/yuzu/configuration/configure_general.ui
+++ b/src/yuzu/configuration/configure_general.ui
@@ -98,22 +98,6 @@
98 </widget> 98 </widget>
99 </item> 99 </item>
100 <item> 100 <item>
101 <widget class="QGroupBox" name="HotKeysGroupBox">
102 <property name="title">
103 <string>Hotkeys</string>
104 </property>
105 <layout class="QHBoxLayout" name="HotKeysHorizontalLayout">
106 <item>
107 <layout class="QVBoxLayout" name="HotKeysVerticalLayout">
108 <item>
109 <widget class="GHotkeysDialog" name="widget" native="true"/>
110 </item>
111 </layout>
112 </item>
113 </layout>
114 </widget>
115 </item>
116 <item>
117 <spacer name="verticalSpacer"> 101 <spacer name="verticalSpacer">
118 <property name="orientation"> 102 <property name="orientation">
119 <enum>Qt::Vertical</enum> 103 <enum>Qt::Vertical</enum>
@@ -130,14 +114,6 @@
130 </item> 114 </item>
131 </layout> 115 </layout>
132 </widget> 116 </widget>
133 <customwidgets>
134 <customwidget>
135 <class>GHotkeysDialog</class>
136 <extends>QWidget</extends>
137 <header>hotkeys.h</header>
138 <container>1</container>
139 </customwidget>
140 </customwidgets>
141 <resources/> 117 <resources/>
142 <connections/> 118 <connections/>
143</ui> 119</ui>
diff --git a/src/yuzu/configuration/configure_hotkeys.cpp b/src/yuzu/configuration/configure_hotkeys.cpp
new file mode 100644
index 000000000..bfb562535
--- /dev/null
+++ b/src/yuzu/configuration/configure_hotkeys.cpp
@@ -0,0 +1,121 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <QMessageBox>
6#include <QStandardItemModel>
7#include "core/settings.h"
8#include "ui_configure_hotkeys.h"
9#include "yuzu/configuration/configure_hotkeys.h"
10#include "yuzu/hotkeys.h"
11#include "yuzu/util/sequence_dialog/sequence_dialog.h"
12
13ConfigureHotkeys::ConfigureHotkeys(QWidget* parent)
14 : QWidget(parent), ui(std::make_unique<Ui::ConfigureHotkeys>()) {
15 ui->setupUi(this);
16 setFocusPolicy(Qt::ClickFocus);
17
18 model = new QStandardItemModel(this);
19 model->setColumnCount(3);
20 model->setHorizontalHeaderLabels({tr("Action"), tr("Hotkey"), tr("Context")});
21
22 connect(ui->hotkey_list, &QTreeView::doubleClicked, this, &ConfigureHotkeys::Configure);
23 ui->hotkey_list->setModel(model);
24
25 // TODO(Kloen): Make context configurable as well (hiding the column for now)
26 ui->hotkey_list->hideColumn(2);
27
28 ui->hotkey_list->setColumnWidth(0, 200);
29 ui->hotkey_list->resizeColumnToContents(1);
30}
31
32ConfigureHotkeys::~ConfigureHotkeys() = default;
33
34void ConfigureHotkeys::EmitHotkeysChanged() {
35 emit HotkeysChanged(GetUsedKeyList());
36}
37
38QList<QKeySequence> ConfigureHotkeys::GetUsedKeyList() const {
39 QList<QKeySequence> list;
40 for (int r = 0; r < model->rowCount(); r++) {
41 const QStandardItem* parent = model->item(r, 0);
42 for (int r2 = 0; r2 < parent->rowCount(); r2++) {
43 const QStandardItem* keyseq = parent->child(r2, 1);
44 list << QKeySequence::fromString(keyseq->text(), QKeySequence::NativeText);
45 }
46 }
47 return list;
48}
49
50void ConfigureHotkeys::Populate(const HotkeyRegistry& registry) {
51 for (const auto& group : registry.hotkey_groups) {
52 auto* parent_item = new QStandardItem(group.first);
53 parent_item->setEditable(false);
54 for (const auto& hotkey : group.second) {
55 auto* action = new QStandardItem(hotkey.first);
56 auto* keyseq =
57 new QStandardItem(hotkey.second.keyseq.toString(QKeySequence::NativeText));
58 action->setEditable(false);
59 keyseq->setEditable(false);
60 parent_item->appendRow({action, keyseq});
61 }
62 model->appendRow(parent_item);
63 }
64
65 ui->hotkey_list->expandAll();
66}
67
68void ConfigureHotkeys::Configure(QModelIndex index) {
69 if (index.parent() == QModelIndex())
70 return;
71
72 index = index.sibling(index.row(), 1);
73 auto* model = ui->hotkey_list->model();
74 auto previous_key = model->data(index);
75
76 auto* hotkey_dialog = new SequenceDialog;
77 int return_code = hotkey_dialog->exec();
78
79 auto key_sequence = hotkey_dialog->GetSequence();
80
81 if (return_code == QDialog::Rejected || key_sequence.isEmpty())
82 return;
83
84 if (IsUsedKey(key_sequence) && key_sequence != QKeySequence(previous_key.toString())) {
85 QMessageBox::critical(this, tr("Error in inputted key"),
86 tr("You're using a key that's already bound."));
87 } else {
88 model->setData(index, key_sequence.toString(QKeySequence::NativeText));
89 EmitHotkeysChanged();
90 }
91}
92
93bool ConfigureHotkeys::IsUsedKey(QKeySequence key_sequence) {
94 return GetUsedKeyList().contains(key_sequence);
95}
96
97void ConfigureHotkeys::applyConfiguration(HotkeyRegistry& registry) {
98 for (int key_id = 0; key_id < model->rowCount(); key_id++) {
99 const QStandardItem* parent = model->item(key_id, 0);
100 for (int key_column_id = 0; key_column_id < parent->rowCount(); key_column_id++) {
101 const QStandardItem* action = parent->child(key_column_id, 0);
102 const QStandardItem* keyseq = parent->child(key_column_id, 1);
103 for (auto& [group, sub_actions] : registry.hotkey_groups) {
104 if (group != parent->text())
105 continue;
106 for (auto& [action_name, hotkey] : sub_actions) {
107 if (action_name != action->text())
108 continue;
109 hotkey.keyseq = QKeySequence(keyseq->text());
110 }
111 }
112 }
113 }
114
115 registry.SaveHotkeys();
116 Settings::Apply();
117}
118
119void ConfigureHotkeys::retranslateUi() {
120 ui->retranslateUi(this);
121}
diff --git a/src/yuzu/configuration/configure_hotkeys.h b/src/yuzu/configuration/configure_hotkeys.h
new file mode 100644
index 000000000..cd203aad6
--- /dev/null
+++ b/src/yuzu/configuration/configure_hotkeys.h
@@ -0,0 +1,48 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <QWidget>
9#include "core/settings.h"
10
11namespace Ui {
12class ConfigureHotkeys;
13}
14
15class HotkeyRegistry;
16class QStandardItemModel;
17
18class ConfigureHotkeys : public QWidget {
19 Q_OBJECT
20
21public:
22 explicit ConfigureHotkeys(QWidget* parent = nullptr);
23 ~ConfigureHotkeys() override;
24
25 void applyConfiguration(HotkeyRegistry& registry);
26 void retranslateUi();
27
28 void EmitHotkeysChanged();
29
30 /**
31 * Populates the hotkey list widget using data from the provided registry.
32 * Called everytime the Configure dialog is opened.
33 * @param registry The HotkeyRegistry whose data is used to populate the list.
34 */
35 void Populate(const HotkeyRegistry& registry);
36
37signals:
38 void HotkeysChanged(QList<QKeySequence> new_key_list);
39
40private:
41 void Configure(QModelIndex index);
42 bool IsUsedKey(QKeySequence key_sequence);
43 QList<QKeySequence> GetUsedKeyList() const;
44
45 std::unique_ptr<Ui::ConfigureHotkeys> ui;
46
47 QStandardItemModel* model;
48};
diff --git a/src/yuzu/configuration/configure_hotkeys.ui b/src/yuzu/configuration/configure_hotkeys.ui
new file mode 100644
index 000000000..0d0b70f38
--- /dev/null
+++ b/src/yuzu/configuration/configure_hotkeys.ui
@@ -0,0 +1,42 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>ConfigureHotkeys</class>
4 <widget class="QWidget" name="ConfigureHotkeys">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>363</width>
10 <height>388</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Hotkey Settings</string>
15 </property>
16 <layout class="QVBoxLayout" name="verticalLayout">
17 <item>
18 <layout class="QVBoxLayout" name="verticalLayout_2">
19 <item>
20 <widget class="QLabel" name="label_2">
21 <property name="text">
22 <string>Double-click on a binding to change it.</string>
23 </property>
24 </widget>
25 </item>
26 <item>
27 <widget class="QTreeView" name="hotkey_list">
28 <property name="editTriggers">
29 <set>QAbstractItemView::NoEditTriggers</set>
30 </property>
31 <property name="sortingEnabled">
32 <bool>false</bool>
33 </property>
34 </widget>
35 </item>
36 </layout>
37 </item>
38 </layout>
39 </widget>
40 <resources/>
41 <connections/>
42</ui> \ No newline at end of file
diff --git a/src/yuzu/hotkeys.cpp b/src/yuzu/hotkeys.cpp
index dce399774..4582e7f21 100644
--- a/src/yuzu/hotkeys.cpp
+++ b/src/yuzu/hotkeys.cpp
@@ -2,7 +2,6 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <map>
6#include <QKeySequence> 5#include <QKeySequence>
7#include <QShortcut> 6#include <QShortcut>
8#include <QTreeWidgetItem> 7#include <QTreeWidgetItem>
@@ -13,47 +12,32 @@
13HotkeyRegistry::HotkeyRegistry() = default; 12HotkeyRegistry::HotkeyRegistry() = default;
14HotkeyRegistry::~HotkeyRegistry() = default; 13HotkeyRegistry::~HotkeyRegistry() = default;
15 14
16void HotkeyRegistry::LoadHotkeys() {
17 // Make sure NOT to use a reference here because it would become invalid once we call
18 // beginGroup()
19 for (auto shortcut : UISettings::values.shortcuts) {
20 const QStringList cat = shortcut.first.split('/');
21 Q_ASSERT(cat.size() >= 2);
22
23 // RegisterHotkey assigns default keybindings, so use old values as default parameters
24 Hotkey& hk = hotkey_groups[cat[0]][cat[1]];
25 if (!shortcut.second.first.isEmpty()) {
26 hk.keyseq = QKeySequence::fromString(shortcut.second.first);
27 hk.context = static_cast<Qt::ShortcutContext>(shortcut.second.second);
28 }
29 if (hk.shortcut)
30 hk.shortcut->setKey(hk.keyseq);
31 }
32}
33
34void HotkeyRegistry::SaveHotkeys() { 15void HotkeyRegistry::SaveHotkeys() {
35 UISettings::values.shortcuts.clear(); 16 UISettings::values.shortcuts.clear();
36 for (const auto& group : hotkey_groups) { 17 for (const auto& group : hotkey_groups) {
37 for (const auto& hotkey : group.second) { 18 for (const auto& hotkey : group.second) {
38 UISettings::values.shortcuts.emplace_back( 19 UISettings::values.shortcuts.push_back(
39 UISettings::Shortcut(group.first + '/' + hotkey.first, 20 {hotkey.first, group.first,
40 UISettings::ContextualShortcut(hotkey.second.keyseq.toString(), 21 UISettings::ContextualShortcut(hotkey.second.keyseq.toString(),
41 hotkey.second.context))); 22 hotkey.second.context)});
42 } 23 }
43 } 24 }
44} 25}
45 26
46void HotkeyRegistry::RegisterHotkey(const QString& group, const QString& action, 27void HotkeyRegistry::LoadHotkeys() {
47 const QKeySequence& default_keyseq, 28 // Make sure NOT to use a reference here because it would become invalid once we call
48 Qt::ShortcutContext default_context) { 29 // beginGroup()
49 auto& hotkey_group = hotkey_groups[group]; 30 for (auto shortcut : UISettings::values.shortcuts) {
50 if (hotkey_group.find(action) != hotkey_group.end()) { 31 Hotkey& hk = hotkey_groups[shortcut.group][shortcut.name];
51 return; 32 if (!shortcut.shortcut.first.isEmpty()) {
33 hk.keyseq = QKeySequence::fromString(shortcut.shortcut.first, QKeySequence::NativeText);
34 hk.context = static_cast<Qt::ShortcutContext>(shortcut.shortcut.second);
35 }
36 if (hk.shortcut) {
37 hk.shortcut->disconnect();
38 hk.shortcut->setKey(hk.keyseq);
39 }
52 } 40 }
53
54 auto& hotkey_action = hotkey_groups[group][action];
55 hotkey_action.keyseq = default_keyseq;
56 hotkey_action.context = default_context;
57} 41}
58 42
59QShortcut* HotkeyRegistry::GetHotkey(const QString& group, const QString& action, QWidget* widget) { 43QShortcut* HotkeyRegistry::GetHotkey(const QString& group, const QString& action, QWidget* widget) {
@@ -65,24 +49,11 @@ QShortcut* HotkeyRegistry::GetHotkey(const QString& group, const QString& action
65 return hk.shortcut; 49 return hk.shortcut;
66} 50}
67 51
68GHotkeysDialog::GHotkeysDialog(QWidget* parent) : QWidget(parent) { 52QKeySequence HotkeyRegistry::GetKeySequence(const QString& group, const QString& action) {
69 ui.setupUi(this); 53 return hotkey_groups[group][action].keyseq;
70} 54}
71 55
72void GHotkeysDialog::Populate(const HotkeyRegistry& registry) { 56Qt::ShortcutContext HotkeyRegistry::GetShortcutContext(const QString& group,
73 for (const auto& group : registry.hotkey_groups) { 57 const QString& action) {
74 QTreeWidgetItem* toplevel_item = new QTreeWidgetItem(QStringList(group.first)); 58 return hotkey_groups[group][action].context;
75 for (const auto& hotkey : group.second) {
76 QStringList columns;
77 columns << hotkey.first << hotkey.second.keyseq.toString();
78 QTreeWidgetItem* item = new QTreeWidgetItem(columns);
79 toplevel_item->addChild(item);
80 }
81 ui.treeWidget->addTopLevelItem(toplevel_item);
82 }
83 // TODO: Make context configurable as well (hiding the column for now)
84 ui.treeWidget->setColumnCount(2);
85
86 ui.treeWidget->resizeColumnToContents(0);
87 ui.treeWidget->resizeColumnToContents(1);
88} 59}
diff --git a/src/yuzu/hotkeys.h b/src/yuzu/hotkeys.h
index f38e6c002..4f526dc7e 100644
--- a/src/yuzu/hotkeys.h
+++ b/src/yuzu/hotkeys.h
@@ -5,7 +5,6 @@
5#pragma once 5#pragma once
6 6
7#include <map> 7#include <map>
8#include "ui_hotkeys.h"
9 8
10class QDialog; 9class QDialog;
11class QKeySequence; 10class QKeySequence;
@@ -14,7 +13,7 @@ class QShortcut;
14 13
15class HotkeyRegistry final { 14class HotkeyRegistry final {
16public: 15public:
17 friend class GHotkeysDialog; 16 friend class ConfigureHotkeys;
18 17
19 explicit HotkeyRegistry(); 18 explicit HotkeyRegistry();
20 ~HotkeyRegistry(); 19 ~HotkeyRegistry();
@@ -49,22 +48,27 @@ public:
49 QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widget); 48 QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widget);
50 49
51 /** 50 /**
52 * Register a hotkey. 51 * Returns a QKeySequence object whose signal can be connected to QAction::setShortcut.
53 * 52 *
54 * @param group General group this hotkey belongs to (e.g. "Main Window", "Debugger") 53 * @param group General group this hotkey belongs to (e.g. "Main Window", "Debugger").
55 * @param action Name of the action (e.g. "Start Emulation", "Load Image") 54 * @param action Name of the action (e.g. "Start Emulation", "Load Image").
56 * @param default_keyseq Default key sequence to assign if the hotkey wasn't present in the 55 */
57 * settings file before 56 QKeySequence GetKeySequence(const QString& group, const QString& action);
58 * @param default_context Default context to assign if the hotkey wasn't present in the settings 57
59 * file before 58 /**
60 * @warning Both the group and action strings will be displayed in the hotkey settings dialog 59 * Returns a Qt::ShortcutContext object who can be connected to other
60 * QAction::setShortcutContext.
61 *
62 * @param group General group this shortcut context belongs to (e.g. "Main Window",
63 * "Debugger").
64 * @param action Name of the action (e.g. "Start Emulation", "Load Image").
61 */ 65 */
62 void RegisterHotkey(const QString& group, const QString& action, 66 Qt::ShortcutContext GetShortcutContext(const QString& group, const QString& action);
63 const QKeySequence& default_keyseq = {},
64 Qt::ShortcutContext default_context = Qt::WindowShortcut);
65 67
66private: 68private:
67 struct Hotkey { 69 struct Hotkey {
70 Hotkey() : shortcut(nullptr), context(Qt::WindowShortcut) {}
71
68 QKeySequence keyseq; 72 QKeySequence keyseq;
69 QShortcut* shortcut = nullptr; 73 QShortcut* shortcut = nullptr;
70 Qt::ShortcutContext context = Qt::WindowShortcut; 74 Qt::ShortcutContext context = Qt::WindowShortcut;
@@ -75,15 +79,3 @@ private:
75 79
76 HotkeyGroupMap hotkey_groups; 80 HotkeyGroupMap hotkey_groups;
77}; 81};
78
79class GHotkeysDialog : public QWidget {
80 Q_OBJECT
81
82public:
83 explicit GHotkeysDialog(QWidget* parent = nullptr);
84
85 void Populate(const HotkeyRegistry& registry);
86
87private:
88 Ui::hotkeys ui;
89};
diff --git a/src/yuzu/hotkeys.ui b/src/yuzu/hotkeys.ui
deleted file mode 100644
index 050fe064e..000000000
--- a/src/yuzu/hotkeys.ui
+++ /dev/null
@@ -1,46 +0,0 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>hotkeys</class>
4 <widget class="QWidget" name="hotkeys">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>363</width>
10 <height>388</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Hotkey Settings</string>
15 </property>
16 <layout class="QVBoxLayout" name="verticalLayout">
17 <item>
18 <widget class="QTreeWidget" name="treeWidget">
19 <property name="selectionBehavior">
20 <enum>QAbstractItemView::SelectItems</enum>
21 </property>
22 <property name="headerHidden">
23 <bool>false</bool>
24 </property>
25 <column>
26 <property name="text">
27 <string>Action</string>
28 </property>
29 </column>
30 <column>
31 <property name="text">
32 <string>Hotkey</string>
33 </property>
34 </column>
35 <column>
36 <property name="text">
37 <string>Context</string>
38 </property>
39 </column>
40 </widget>
41 </item>
42 </layout>
43 </widget>
44 <resources/>
45 <connections/>
46</ui>
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 2b9db69a3..77b6f7cc8 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -514,33 +514,34 @@ void GMainWindow::InitializeRecentFileMenuActions() {
514} 514}
515 515
516void GMainWindow::InitializeHotkeys() { 516void GMainWindow::InitializeHotkeys() {
517 hotkey_registry.RegisterHotkey("Main Window", "Load File", QKeySequence::Open);
518 hotkey_registry.RegisterHotkey("Main Window", "Start Emulation");
519 hotkey_registry.RegisterHotkey("Main Window", "Continue/Pause", QKeySequence(Qt::Key_F4));
520 hotkey_registry.RegisterHotkey("Main Window", "Restart", QKeySequence(Qt::Key_F5));
521 hotkey_registry.RegisterHotkey("Main Window", "Fullscreen", QKeySequence::FullScreen);
522 hotkey_registry.RegisterHotkey("Main Window", "Exit Fullscreen", QKeySequence(Qt::Key_Escape),
523 Qt::ApplicationShortcut);
524 hotkey_registry.RegisterHotkey("Main Window", "Toggle Speed Limit", QKeySequence("CTRL+Z"),
525 Qt::ApplicationShortcut);
526 hotkey_registry.RegisterHotkey("Main Window", "Increase Speed Limit", QKeySequence("+"),
527 Qt::ApplicationShortcut);
528 hotkey_registry.RegisterHotkey("Main Window", "Decrease Speed Limit", QKeySequence("-"),
529 Qt::ApplicationShortcut);
530 hotkey_registry.RegisterHotkey("Main Window", "Load Amiibo", QKeySequence(Qt::Key_F2),
531 Qt::ApplicationShortcut);
532 hotkey_registry.RegisterHotkey("Main Window", "Capture Screenshot",
533 QKeySequence(QKeySequence::Print));
534 hotkey_registry.RegisterHotkey("Main Window", "Change Docked Mode", QKeySequence(Qt::Key_F10));
535
536 hotkey_registry.LoadHotkeys(); 517 hotkey_registry.LoadHotkeys();
537 518
519 ui.action_Load_File->setShortcut(hotkey_registry.GetKeySequence("Main Window", "Load File"));
520 ui.action_Load_File->setShortcutContext(
521 hotkey_registry.GetShortcutContext("Main Window", "Load File"));
522
523 ui.action_Exit->setShortcut(hotkey_registry.GetKeySequence("Main Window", "Exit yuzu"));
524 ui.action_Exit->setShortcutContext(
525 hotkey_registry.GetShortcutContext("Main Window", "Exit yuzu"));
526
527 ui.action_Stop->setShortcut(hotkey_registry.GetKeySequence("Main Window", "Stop Emulation"));
528 ui.action_Stop->setShortcutContext(
529 hotkey_registry.GetShortcutContext("Main Window", "Stop Emulation"));
530
531 ui.action_Show_Filter_Bar->setShortcut(
532 hotkey_registry.GetKeySequence("Main Window", "Toggle Filter Bar"));
533 ui.action_Show_Filter_Bar->setShortcutContext(
534 hotkey_registry.GetShortcutContext("Main Window", "Toggle Filter Bar"));
535
536 ui.action_Show_Status_Bar->setShortcut(
537 hotkey_registry.GetKeySequence("Main Window", "Toggle Status Bar"));
538 ui.action_Show_Status_Bar->setShortcutContext(
539 hotkey_registry.GetShortcutContext("Main Window", "Toggle Status Bar"));
540
538 connect(hotkey_registry.GetHotkey("Main Window", "Load File", this), &QShortcut::activated, 541 connect(hotkey_registry.GetHotkey("Main Window", "Load File", this), &QShortcut::activated,
539 this, &GMainWindow::OnMenuLoadFile); 542 this, &GMainWindow::OnMenuLoadFile);
540 connect(hotkey_registry.GetHotkey("Main Window", "Start Emulation", this), 543 connect(hotkey_registry.GetHotkey("Main Window", "Continue/Pause Emulation", this),
541 &QShortcut::activated, this, &GMainWindow::OnStartGame); 544 &QShortcut::activated, this, [&] {
542 connect(hotkey_registry.GetHotkey("Main Window", "Continue/Pause", this), &QShortcut::activated,
543 this, [&] {
544 if (emulation_running) { 545 if (emulation_running) {
545 if (emu_thread->IsRunning()) { 546 if (emu_thread->IsRunning()) {
546 OnPauseGame(); 547 OnPauseGame();
@@ -549,8 +550,8 @@ void GMainWindow::InitializeHotkeys() {
549 } 550 }
550 } 551 }
551 }); 552 });
552 connect(hotkey_registry.GetHotkey("Main Window", "Restart", this), &QShortcut::activated, this, 553 connect(hotkey_registry.GetHotkey("Main Window", "Restart Emulation", this),
553 [this] { 554 &QShortcut::activated, this, [this] {
554 if (!Core::System::GetInstance().IsPoweredOn()) 555 if (!Core::System::GetInstance().IsPoweredOn())
555 return; 556 return;
556 BootGame(QString(game_path)); 557 BootGame(QString(game_path));
@@ -697,7 +698,6 @@ void GMainWindow::ConnectMenuEvents() {
697 &GMainWindow::ToggleWindowMode); 698 &GMainWindow::ToggleWindowMode);
698 connect(ui.action_Display_Dock_Widget_Headers, &QAction::triggered, this, 699 connect(ui.action_Display_Dock_Widget_Headers, &QAction::triggered, this,
699 &GMainWindow::OnDisplayTitleBars); 700 &GMainWindow::OnDisplayTitleBars);
700 ui.action_Show_Filter_Bar->setShortcut(tr("CTRL+F"));
701 connect(ui.action_Show_Filter_Bar, &QAction::triggered, this, &GMainWindow::OnToggleFilterBar); 701 connect(ui.action_Show_Filter_Bar, &QAction::triggered, this, &GMainWindow::OnToggleFilterBar);
702 connect(ui.action_Show_Status_Bar, &QAction::triggered, statusBar(), &QStatusBar::setVisible); 702 connect(ui.action_Show_Status_Bar, &QAction::triggered, statusBar(), &QStatusBar::setVisible);
703 703
@@ -1662,6 +1662,7 @@ void GMainWindow::OnConfigure() {
1662 auto result = configureDialog.exec(); 1662 auto result = configureDialog.exec();
1663 if (result == QDialog::Accepted) { 1663 if (result == QDialog::Accepted) {
1664 configureDialog.applyConfiguration(); 1664 configureDialog.applyConfiguration();
1665 InitializeHotkeys();
1665 if (UISettings::values.theme != old_theme) 1666 if (UISettings::values.theme != old_theme)
1666 UpdateUITheme(); 1667 UpdateUITheme();
1667 if (UISettings::values.enable_discord_presence != old_discord_presence) 1668 if (UISettings::values.enable_discord_presence != old_discord_presence)
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 7f3aa998e..ba406ae64 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -120,7 +120,6 @@ private:
120 void InitializeWidgets(); 120 void InitializeWidgets();
121 void InitializeDebugWidgets(); 121 void InitializeDebugWidgets();
122 void InitializeRecentFileMenuActions(); 122 void InitializeRecentFileMenuActions();
123 void InitializeHotkeys();
124 123
125 void SetDefaultUIGeometry(); 124 void SetDefaultUIGeometry();
126 void RestoreUIState(); 125 void RestoreUIState();
@@ -196,6 +195,7 @@ private slots:
196 void OnAbout(); 195 void OnAbout();
197 void OnToggleFilterBar(); 196 void OnToggleFilterBar();
198 void OnDisplayTitleBars(bool); 197 void OnDisplayTitleBars(bool);
198 void InitializeHotkeys();
199 void ToggleFullscreen(); 199 void ToggleFullscreen();
200 void ShowFullscreen(); 200 void ShowFullscreen();
201 void HideFullscreen(); 201 void HideFullscreen();
diff --git a/src/yuzu/ui_settings.cpp b/src/yuzu/ui_settings.cpp
index a314493fc..4bdc302e0 100644
--- a/src/yuzu/ui_settings.cpp
+++ b/src/yuzu/ui_settings.cpp
@@ -12,5 +12,4 @@ const Themes themes{{
12}}; 12}};
13 13
14Values values = {}; 14Values values = {};
15
16} // namespace UISettings 15} // namespace UISettings
diff --git a/src/yuzu/ui_settings.h b/src/yuzu/ui_settings.h
index 82aaeedb0..45e705b61 100644
--- a/src/yuzu/ui_settings.h
+++ b/src/yuzu/ui_settings.h
@@ -15,7 +15,12 @@
15namespace UISettings { 15namespace UISettings {
16 16
17using ContextualShortcut = std::pair<QString, int>; 17using ContextualShortcut = std::pair<QString, int>;
18using Shortcut = std::pair<QString, ContextualShortcut>; 18
19struct Shortcut {
20 QString name;
21 QString group;
22 ContextualShortcut shortcut;
23};
19 24
20using Themes = std::array<std::pair<const char*, const char*>, 2>; 25using Themes = std::array<std::pair<const char*, const char*>, 2>;
21extern const Themes themes; 26extern const Themes themes;
diff --git a/src/yuzu/util/sequence_dialog/sequence_dialog.cpp b/src/yuzu/util/sequence_dialog/sequence_dialog.cpp
new file mode 100644
index 000000000..d3edf6ec3
--- /dev/null
+++ b/src/yuzu/util/sequence_dialog/sequence_dialog.cpp
@@ -0,0 +1,37 @@
1// Copyright 2018 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <QDialogButtonBox>
6#include <QKeySequenceEdit>
7#include <QVBoxLayout>
8#include "yuzu/util/sequence_dialog/sequence_dialog.h"
9
10SequenceDialog::SequenceDialog(QWidget* parent) : QDialog(parent) {
11 setWindowTitle(tr("Enter a hotkey"));
12 auto* layout = new QVBoxLayout(this);
13 key_sequence = new QKeySequenceEdit;
14 layout->addWidget(key_sequence);
15 auto* buttons =
16 new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal);
17 buttons->setCenterButtons(true);
18 layout->addWidget(buttons);
19 connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
20 connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
21 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
22}
23
24SequenceDialog::~SequenceDialog() = default;
25
26QKeySequence SequenceDialog::GetSequence() const {
27 // Only the first key is returned. The other 3, if present, are ignored.
28 return QKeySequence(key_sequence->keySequence()[0]);
29}
30
31bool SequenceDialog::focusNextPrevChild(bool next) {
32 return false;
33}
34
35void SequenceDialog::closeEvent(QCloseEvent*) {
36 reject();
37}
diff --git a/src/yuzu/util/sequence_dialog/sequence_dialog.h b/src/yuzu/util/sequence_dialog/sequence_dialog.h
new file mode 100644
index 000000000..969c77740
--- /dev/null
+++ b/src/yuzu/util/sequence_dialog/sequence_dialog.h
@@ -0,0 +1,24 @@
1// Copyright 2018 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <QDialog>
8
9class QKeySequenceEdit;
10
11class SequenceDialog : public QDialog {
12 Q_OBJECT
13
14public:
15 explicit SequenceDialog(QWidget* parent = nullptr);
16 ~SequenceDialog() override;
17
18 QKeySequence GetSequence() const;
19 void closeEvent(QCloseEvent*) override;
20
21private:
22 QKeySequenceEdit* key_sequence;
23 bool focusNextPrevChild(bool next) override;
24};