Merge pull request #4437 from adityaruplaha/hotkey-config-squashed
citra-qt: Make hotkeys configurable via the GUI (Attempt 2)
This commit is contained in:
		| @@ -41,6 +41,8 @@ add_executable(citra-qt | |||||||
|     configuration/configure_general.h |     configuration/configure_general.h | ||||||
|     configuration/configure_graphics.cpp |     configuration/configure_graphics.cpp | ||||||
|     configuration/configure_graphics.h |     configuration/configure_graphics.h | ||||||
|  |     configuration/configure_hotkeys.cpp | ||||||
|  |     configuration/configure_hotkeys.h | ||||||
|     configuration/configure_input.cpp |     configuration/configure_input.cpp | ||||||
|     configuration/configure_input.h |     configuration/configure_input.h | ||||||
|     configuration/configure_motion_touch.cpp |     configuration/configure_motion_touch.cpp | ||||||
| @@ -109,8 +111,10 @@ add_executable(citra-qt | |||||||
|     updater/updater.cpp |     updater/updater.cpp | ||||||
|     updater/updater.h |     updater/updater.h | ||||||
|     updater/updater_p.h |     updater/updater_p.h | ||||||
|     util/clickable_label.h |  | ||||||
|     util/clickable_label.cpp |     util/clickable_label.cpp | ||||||
|  |     util/clickable_label.h | ||||||
|  |     util/sequence_dialog/sequence_dialog.cpp | ||||||
|  |     util/sequence_dialog/sequence_dialog.h | ||||||
|     util/spinbox.cpp |     util/spinbox.cpp | ||||||
|     util/spinbox.h |     util/spinbox.h | ||||||
|     util/util.cpp |     util/util.cpp | ||||||
| @@ -126,6 +130,7 @@ set(UIS | |||||||
|     configuration/configure_debug.ui |     configuration/configure_debug.ui | ||||||
|     configuration/configure_general.ui |     configuration/configure_general.ui | ||||||
|     configuration/configure_graphics.ui |     configuration/configure_graphics.ui | ||||||
|  |     configuration/configure_hotkeys.ui | ||||||
|     configuration/configure_input.ui |     configuration/configure_input.ui | ||||||
|     configuration/configure_motion_touch.ui |     configuration/configure_motion_touch.ui | ||||||
|     configuration/configure_system.ui |     configuration/configure_system.ui | ||||||
| @@ -140,7 +145,6 @@ set(UIS | |||||||
|     multiplayer/moderation_dialog.ui |     multiplayer/moderation_dialog.ui | ||||||
|     aboutdialog.ui |     aboutdialog.ui | ||||||
|     cheats.ui |     cheats.ui | ||||||
|     hotkeys.ui |  | ||||||
|     main.ui |     main.ui | ||||||
|     compatdb.ui |     compatdb.ui | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -3,10 +3,11 @@ | |||||||
| // Refer to the license.txt file included. | // Refer to the license.txt file included. | ||||||
|  |  | ||||||
| #include <algorithm> | #include <algorithm> | ||||||
|  | #include <array> | ||||||
| #include <unordered_map> | #include <unordered_map> | ||||||
|  | #include <QKeySequence> | ||||||
| #include <QSettings> | #include <QSettings> | ||||||
| #include "citra_qt/configuration/config.h" | #include "citra_qt/configuration/config.h" | ||||||
| #include "citra_qt/ui_settings.h" |  | ||||||
| #include "common/file_util.h" | #include "common/file_util.h" | ||||||
| #include "core/hle/service/service.h" | #include "core/hle/service/service.h" | ||||||
| #include "input_common/main.h" | #include "input_common/main.h" | ||||||
| @@ -19,7 +20,6 @@ Config::Config() { | |||||||
|     FileUtil::CreateFullPath(qt_config_loc); |     FileUtil::CreateFullPath(qt_config_loc); | ||||||
|     qt_config = |     qt_config = | ||||||
|         std::make_unique<QSettings>(QString::fromStdString(qt_config_loc), QSettings::IniFormat); |         std::make_unique<QSettings>(QString::fromStdString(qt_config_loc), QSettings::IniFormat); | ||||||
|  |  | ||||||
|     Reload(); |     Reload(); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -50,6 +50,31 @@ const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> Config: | |||||||
|     }, |     }, | ||||||
| }}; | }}; | ||||||
|  |  | ||||||
|  | // This shouldn't have anything except static initializers (no functions). So | ||||||
|  | // QKeySequnce(...).toString() is NOT ALLOWED HERE. | ||||||
|  | // This must be in alphabetical order according to action name as it must have the same order as | ||||||
|  | // UISetting::values.shortcuts, which is alphabetically ordered. | ||||||
|  | const std::array<UISettings::Shortcut, 19> Config::default_hotkeys{ | ||||||
|  |     {{"Advance Frame", "Main Window", {"\\", Qt::ApplicationShortcut}}, | ||||||
|  |      {"Capture Screenshot", "Main Window", {"Ctrl+P", Qt::ApplicationShortcut}}, | ||||||
|  |      {"Continue/Pause Emulation", "Main Window", {"F4", Qt::WindowShortcut}}, | ||||||
|  |      {"Decrease Speed Limit", "Main Window", {"-", Qt::ApplicationShortcut}}, | ||||||
|  |      {"Exit Citra", "Main Window", {"Ctrl+Q", Qt::WindowShortcut}}, | ||||||
|  |      {"Exit Fullscreen", "Main Window", {"Esc", Qt::WindowShortcut}}, | ||||||
|  |      {"Fullscreen", "Main Window", {"F11", Qt::WindowShortcut}}, | ||||||
|  |      {"Increase Speed Limit", "Main Window", {"+", Qt::ApplicationShortcut}}, | ||||||
|  |      {"Load Amiibo", "Main Window", {"F2", Qt::ApplicationShortcut}}, | ||||||
|  |      {"Load File", "Main Window", {"Ctrl+O", Qt::WindowShortcut}}, | ||||||
|  |      {"Remove Amiibo", "Main Window", {"F3", Qt::ApplicationShortcut}}, | ||||||
|  |      {"Restart Emulation", "Main Window", {"F6", Qt::WindowShortcut}}, | ||||||
|  |      {"Stop Emulation", "Main Window", {"F5", Qt::WindowShortcut}}, | ||||||
|  |      {"Swap Screens", "Main Window", {"F9", Qt::WindowShortcut}}, | ||||||
|  |      {"Toggle Filter Bar", "Main Window", {"Ctrl+F", Qt::WindowShortcut}}, | ||||||
|  |      {"Toggle Frame Advancing", "Main Window", {"Ctrl+A", Qt::ApplicationShortcut}}, | ||||||
|  |      {"Toggle Screen Layout", "Main Window", {"F10", Qt::WindowShortcut}}, | ||||||
|  |      {"Toggle Speed Limit", "Main Window", {"Ctrl+Z", Qt::ApplicationShortcut}}, | ||||||
|  |      {"Toggle Status Bar", "Main Window", {"Ctrl+S", Qt::WindowShortcut}}}}; | ||||||
|  |  | ||||||
| void Config::ReadValues() { | void Config::ReadValues() { | ||||||
|     qt_config->beginGroup("Controls"); |     qt_config->beginGroup("Controls"); | ||||||
|  |  | ||||||
| @@ -318,20 +343,15 @@ void Config::ReadValues() { | |||||||
|     qt_config->endGroup(); |     qt_config->endGroup(); | ||||||
|  |  | ||||||
|     qt_config->beginGroup("Shortcuts"); |     qt_config->beginGroup("Shortcuts"); | ||||||
|     QStringList groups = qt_config->childGroups(); |     for (auto [name, group, shortcut] : default_hotkeys) { | ||||||
|     for (auto group : groups) { |         auto [keyseq, context] = shortcut; | ||||||
|         qt_config->beginGroup(group); |         qt_config->beginGroup(group); | ||||||
|  |         qt_config->beginGroup(name); | ||||||
|         QStringList hotkeys = qt_config->childGroups(); |         UISettings::values.shortcuts.push_back( | ||||||
|         for (auto hotkey : hotkeys) { |             {name, | ||||||
|             qt_config->beginGroup(hotkey); |              group, | ||||||
|             UISettings::values.shortcuts.emplace_back(UISettings::Shortcut( |              {ReadSetting("KeySeq", keyseq).toString(), ReadSetting("Context", context).toInt()}}); | ||||||
|                 group + "/" + hotkey, |         qt_config->endGroup(); | ||||||
|                 UISettings::ContextualShortcut(ReadSetting("KeySeq").toString(), |  | ||||||
|                                                ReadSetting("Context").toInt()))); |  | ||||||
|             qt_config->endGroup(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         qt_config->endGroup(); |         qt_config->endGroup(); | ||||||
|     } |     } | ||||||
|     qt_config->endGroup(); |     qt_config->endGroup(); | ||||||
| @@ -563,9 +583,16 @@ void Config::SaveValues() { | |||||||
|     qt_config->endGroup(); |     qt_config->endGroup(); | ||||||
|  |  | ||||||
|     qt_config->beginGroup("Shortcuts"); |     qt_config->beginGroup("Shortcuts"); | ||||||
|     for (auto shortcut : UISettings::values.shortcuts) { |     // Lengths of UISettings::values.shortcuts & default_hotkeys are same. | ||||||
|         WriteSetting(shortcut.first + "/KeySeq", shortcut.second.first); |     // However, their ordering must also be the same. | ||||||
|         WriteSetting(shortcut.first + "/Context", shortcut.second.second); |     for (std::size_t i = 0; i < default_hotkeys.size(); i++) { | ||||||
|  |         auto [name, group, shortcut] = UISettings::values.shortcuts[i]; | ||||||
|  |         qt_config->beginGroup(group); | ||||||
|  |         qt_config->beginGroup(name); | ||||||
|  |         WriteSetting("KeySeq", shortcut.first, default_hotkeys[i].shortcut.first); | ||||||
|  |         WriteSetting("Context", shortcut.second, default_hotkeys[i].shortcut.second); | ||||||
|  |         qt_config->endGroup(); | ||||||
|  |         qt_config->endGroup(); | ||||||
|     } |     } | ||||||
|     qt_config->endGroup(); |     qt_config->endGroup(); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ | |||||||
| #include <memory> | #include <memory> | ||||||
| #include <string> | #include <string> | ||||||
| #include <QVariant> | #include <QVariant> | ||||||
|  | #include "citra_qt/ui_settings.h" | ||||||
| #include "core/settings.h" | #include "core/settings.h" | ||||||
|  |  | ||||||
| class QSettings; | class QSettings; | ||||||
| @@ -31,6 +32,8 @@ private: | |||||||
|     void WriteSetting(const QString& name, const QVariant& value); |     void WriteSetting(const QString& name, const QVariant& value); | ||||||
|     void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value); |     void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value); | ||||||
|  |  | ||||||
|  |     static const std::array<UISettings::Shortcut, 19> default_hotkeys; | ||||||
|  |  | ||||||
|     std::unique_ptr<QSettings> qt_config; |     std::unique_ptr<QSettings> qt_config; | ||||||
|     std::string qt_config_loc; |     std::string qt_config_loc; | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -38,6 +38,11 @@ | |||||||
|          <string>Input</string> |          <string>Input</string> | ||||||
|         </attribute> |         </attribute> | ||||||
|        </widget> |        </widget> | ||||||
|  |        <widget class="ConfigureHotkeys" name="hotkeysTab"> | ||||||
|  |         <attribute name="title"> | ||||||
|  |          <string>Hotkeys</string> | ||||||
|  |         </attribute> | ||||||
|  |        </widget> | ||||||
|        <widget class="ConfigureGraphics" name="graphicsTab"> |        <widget class="ConfigureGraphics" name="graphicsTab"> | ||||||
|         <attribute name="title"> |         <attribute name="title"> | ||||||
|          <string>Graphics</string> |          <string>Graphics</string> | ||||||
| @@ -118,6 +123,12 @@ | |||||||
|    <header>configuration/configure_input.h</header> |    <header>configuration/configure_input.h</header> | ||||||
|    <container>1</container> |    <container>1</container> | ||||||
|   </customwidget> |   </customwidget> | ||||||
|  |   <customwidget> | ||||||
|  |    <class>ConfigureHotkeys</class> | ||||||
|  |    <extends>QWidget</extends> | ||||||
|  |    <header>configuration/configure_hotkeys.h</header> | ||||||
|  |    <container>1</container> | ||||||
|  |   </customwidget> | ||||||
|   <customwidget> |   <customwidget> | ||||||
|    <class>ConfigureGraphics</class> |    <class>ConfigureGraphics</class> | ||||||
|    <extends>QWidget</extends> |    <extends>QWidget</extends> | ||||||
|   | |||||||
| @@ -10,18 +10,27 @@ | |||||||
| #include "core/settings.h" | #include "core/settings.h" | ||||||
| #include "ui_configure.h" | #include "ui_configure.h" | ||||||
|  |  | ||||||
| ConfigureDialog::ConfigureDialog(QWidget* parent, const HotkeyRegistry& registry) | ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry) | ||||||
|     : QDialog(parent), ui(new Ui::ConfigureDialog) { |     : QDialog(parent), registry(registry), ui(new Ui::ConfigureDialog) { | ||||||
|     ui->setupUi(this); |     ui->setupUi(this); | ||||||
|     ui->generalTab->PopulateHotkeyList(registry); |     ui->hotkeysTab->Populate(registry); | ||||||
|  |  | ||||||
|     this->PopulateSelectionList(); |     this->PopulateSelectionList(); | ||||||
|     connect(ui->uiTab, &ConfigureUi::languageChanged, this, &ConfigureDialog::onLanguageChanged); |     connect(ui->uiTab, &ConfigureUi::languageChanged, this, &ConfigureDialog::onLanguageChanged); | ||||||
|     connect(ui->selectorList, &QListWidget::itemSelectionChanged, this, |     connect(ui->selectorList, &QListWidget::itemSelectionChanged, this, | ||||||
|             &ConfigureDialog::UpdateVisibleTabs); |             &ConfigureDialog::UpdateVisibleTabs); | ||||||
|  |  | ||||||
|     adjustSize(); |     adjustSize(); | ||||||
|  |  | ||||||
|     ui->selectorList->setCurrentRow(0); |     ui->selectorList->setCurrentRow(0); | ||||||
|  |  | ||||||
|  |     // Set up used key list synchronisation | ||||||
|  |     connect(ui->inputTab, &ConfigureInput::InputKeysChanged, ui->hotkeysTab, | ||||||
|  |             &ConfigureHotkeys::OnInputKeysChanged); | ||||||
|  |     connect(ui->hotkeysTab, &ConfigureHotkeys::HotkeysChanged, ui->inputTab, | ||||||
|  |             &ConfigureInput::OnHotkeysChanged); | ||||||
|  |  | ||||||
|  |     // Synchronise lists upon initialisation | ||||||
|  |     ui->inputTab->EmitInputKeysChanged(); | ||||||
|  |     ui->hotkeysTab->EmitHotkeysChanged(); | ||||||
| } | } | ||||||
|  |  | ||||||
| ConfigureDialog::~ConfigureDialog() = default; | ConfigureDialog::~ConfigureDialog() = default; | ||||||
| @@ -43,6 +52,7 @@ void ConfigureDialog::applyConfiguration() { | |||||||
|     ui->systemTab->applyConfiguration(); |     ui->systemTab->applyConfiguration(); | ||||||
|     ui->inputTab->applyConfiguration(); |     ui->inputTab->applyConfiguration(); | ||||||
|     ui->inputTab->ApplyProfile(); |     ui->inputTab->ApplyProfile(); | ||||||
|  |     ui->hotkeysTab->applyConfiguration(registry); | ||||||
|     ui->graphicsTab->applyConfiguration(); |     ui->graphicsTab->applyConfiguration(); | ||||||
|     ui->audioTab->applyConfiguration(); |     ui->audioTab->applyConfiguration(); | ||||||
|     ui->cameraTab->applyConfiguration(); |     ui->cameraTab->applyConfiguration(); | ||||||
| @@ -61,7 +71,7 @@ void ConfigureDialog::PopulateSelectionList() { | |||||||
|           {QT_TR_NOOP("General"), QT_TR_NOOP("Web"), QT_TR_NOOP("Debug"), QT_TR_NOOP("UI")}}, |           {QT_TR_NOOP("General"), QT_TR_NOOP("Web"), QT_TR_NOOP("Debug"), QT_TR_NOOP("UI")}}, | ||||||
|          {tr("System"), {QT_TR_NOOP("System"), QT_TR_NOOP("Audio"), QT_TR_NOOP("Camera")}}, |          {tr("System"), {QT_TR_NOOP("System"), QT_TR_NOOP("Audio"), QT_TR_NOOP("Camera")}}, | ||||||
|          {tr("Graphics"), {QT_TR_NOOP("Graphics")}}, |          {tr("Graphics"), {QT_TR_NOOP("Graphics")}}, | ||||||
|          {tr("Controls"), {QT_TR_NOOP("Input")}}}}; |          {tr("Controls"), {QT_TR_NOOP("Input"), QT_TR_NOOP("Hotkeys")}}}}; | ||||||
|  |  | ||||||
|     for (const auto& entry : items) { |     for (const auto& entry : items) { | ||||||
|         auto* item = new QListWidgetItem(entry.first); |         auto* item = new QListWidgetItem(entry.first); | ||||||
| @@ -91,6 +101,7 @@ void ConfigureDialog::retranslateUi() { | |||||||
|     ui->generalTab->retranslateUi(); |     ui->generalTab->retranslateUi(); | ||||||
|     ui->systemTab->retranslateUi(); |     ui->systemTab->retranslateUi(); | ||||||
|     ui->inputTab->retranslateUi(); |     ui->inputTab->retranslateUi(); | ||||||
|  |     ui->hotkeysTab->retranslateUi(); | ||||||
|     ui->graphicsTab->retranslateUi(); |     ui->graphicsTab->retranslateUi(); | ||||||
|     ui->audioTab->retranslateUi(); |     ui->audioTab->retranslateUi(); | ||||||
|     ui->cameraTab->retranslateUi(); |     ui->cameraTab->retranslateUi(); | ||||||
| @@ -105,9 +116,11 @@ void ConfigureDialog::UpdateVisibleTabs() { | |||||||
|         return; |         return; | ||||||
|  |  | ||||||
|     const QHash<QString, QWidget*> widgets = { |     const QHash<QString, QWidget*> widgets = { | ||||||
|         {"General", ui->generalTab},   {"System", ui->systemTab}, {"Input", ui->inputTab}, |         {"General", ui->generalTab},   {"System", ui->systemTab}, | ||||||
|         {"Graphics", ui->graphicsTab}, {"Audio", ui->audioTab},   {"Camera", ui->cameraTab}, |         {"Input", ui->inputTab},       {"Hotkeys", ui->hotkeysTab}, | ||||||
|         {"Debug", ui->debugTab},       {"Web", ui->webTab},       {"UI", ui->uiTab}}; |         {"Graphics", ui->graphicsTab}, {"Audio", ui->audioTab}, | ||||||
|  |         {"Camera", ui->cameraTab},     {"Debug", ui->debugTab}, | ||||||
|  |         {"Web", ui->webTab},           {"UI", ui->uiTab}}; | ||||||
|  |  | ||||||
|     ui->tabWidget->clear(); |     ui->tabWidget->clear(); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -17,7 +17,7 @@ class ConfigureDialog : public QDialog { | |||||||
|     Q_OBJECT |     Q_OBJECT | ||||||
|  |  | ||||||
| public: | public: | ||||||
|     explicit ConfigureDialog(QWidget* parent, const HotkeyRegistry& registry); |     explicit ConfigureDialog(QWidget* parent, HotkeyRegistry& registry); | ||||||
|     ~ConfigureDialog() override; |     ~ConfigureDialog() override; | ||||||
|  |  | ||||||
|     void applyConfiguration(); |     void applyConfiguration(); | ||||||
| @@ -35,4 +35,5 @@ private: | |||||||
|     void retranslateUi(); |     void retranslateUi(); | ||||||
|  |  | ||||||
|     std::unique_ptr<Ui::ConfigureDialog> ui; |     std::unique_ptr<Ui::ConfigureDialog> ui; | ||||||
|  |     HotkeyRegistry& registry; | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -32,10 +32,6 @@ void ConfigureGeneral::setConfiguration() { | |||||||
|     ui->region_combobox->setCurrentIndex(Settings::values.region_value + 1); |     ui->region_combobox->setCurrentIndex(Settings::values.region_value + 1); | ||||||
| } | } | ||||||
|  |  | ||||||
| void ConfigureGeneral::PopulateHotkeyList(const HotkeyRegistry& registry) { |  | ||||||
|     ui->hotkeysDialog->Populate(registry); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ConfigureGeneral::ResetDefaults() { | void ConfigureGeneral::ResetDefaults() { | ||||||
|     QMessageBox::StandardButton answer = QMessageBox::question( |     QMessageBox::StandardButton answer = QMessageBox::question( | ||||||
|         this, tr("Citra"), |         this, tr("Citra"), | ||||||
| @@ -60,5 +56,4 @@ void ConfigureGeneral::applyConfiguration() { | |||||||
|  |  | ||||||
| void ConfigureGeneral::retranslateUi() { | void ConfigureGeneral::retranslateUi() { | ||||||
|     ui->retranslateUi(this); |     ui->retranslateUi(this); | ||||||
|     ui->hotkeysDialog->retranslateUi(); |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,7 +20,6 @@ public: | |||||||
|     explicit ConfigureGeneral(QWidget* parent = nullptr); |     explicit ConfigureGeneral(QWidget* parent = nullptr); | ||||||
|     ~ConfigureGeneral() override; |     ~ConfigureGeneral() override; | ||||||
|  |  | ||||||
|     void PopulateHotkeyList(const HotkeyRegistry& registry); |  | ||||||
|     void ResetDefaults(); |     void ResetDefaults(); | ||||||
|     void applyConfiguration(); |     void applyConfiguration(); | ||||||
|     void retranslateUi(); |     void retranslateUi(); | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ | |||||||
|     <x>0</x> |     <x>0</x> | ||||||
|     <y>0</y> |     <y>0</y> | ||||||
|     <width>345</width> |     <width>345</width> | ||||||
|     <height>504</height> |     <height>357</height> | ||||||
|    </rect> |    </rect> | ||||||
|   </property> |   </property> | ||||||
|   <property name="windowTitle"> |   <property name="windowTitle"> | ||||||
| @@ -21,17 +21,13 @@ | |||||||
|        <property name="title"> |        <property name="title"> | ||||||
|         <string>General</string> |         <string>General</string> | ||||||
|        </property> |        </property> | ||||||
|        <layout class="QHBoxLayout" name="horizontalLayout_3"> |        <layout class="QVBoxLayout" name="verticalLayout_5"> | ||||||
|         <item> |         <item> | ||||||
|          <layout class="QVBoxLayout" name="verticalLayout_2"> |          <widget class="QCheckBox" name="toggle_check_exit"> | ||||||
|           <item> |           <property name="text"> | ||||||
|            <widget class="QCheckBox" name="toggle_check_exit"> |            <string>Confirm exit while emulation is running</string> | ||||||
|             <property name="text"> |           </property> | ||||||
|              <string>Confirm exit while emulation is running</string> |          </widget> | ||||||
|             </property> |  | ||||||
|            </widget> |  | ||||||
|           </item> |  | ||||||
|          </layout> |  | ||||||
|         </item> |         </item> | ||||||
|        </layout> |        </layout> | ||||||
|       </widget> |       </widget> | ||||||
| @@ -41,24 +37,20 @@ | |||||||
|        <property name="title"> |        <property name="title"> | ||||||
|         <string>Updates</string> |         <string>Updates</string> | ||||||
|        </property> |        </property> | ||||||
|        <layout class="QHBoxLayout" name="horizontalLayout_update"> |        <layout class="QVBoxLayout" name="verticalLayout_4"> | ||||||
|         <item> |         <item> | ||||||
|          <layout class="QVBoxLayout" name="verticalLayout_update"> |          <widget class="QCheckBox" name="toggle_update_check"> | ||||||
|           <item> |           <property name="text"> | ||||||
|            <widget class="QCheckBox" name="toggle_update_check"> |            <string>Check for updates on start</string> | ||||||
|             <property name="text"> |           </property> | ||||||
|              <string>Check for updates on start</string> |          </widget> | ||||||
|             </property> |         </item> | ||||||
|            </widget> |         <item> | ||||||
|           </item> |          <widget class="QCheckBox" name="toggle_auto_update"> | ||||||
|           <item> |           <property name="text"> | ||||||
|            <widget class="QCheckBox" name="toggle_auto_update"> |            <string>Silently auto update after closing</string> | ||||||
|             <property name="text"> |           </property> | ||||||
|              <string>Silently auto update after closing</string> |          </widget> | ||||||
|             </property> |  | ||||||
|            </widget> |  | ||||||
|           </item> |  | ||||||
|          </layout> |  | ||||||
|         </item> |         </item> | ||||||
|        </layout> |        </layout> | ||||||
|       </widget> |       </widget> | ||||||
| @@ -68,81 +60,57 @@ | |||||||
|        <property name="title"> |        <property name="title"> | ||||||
|         <string>Emulation</string> |         <string>Emulation</string> | ||||||
|        </property> |        </property> | ||||||
|        <layout class="QHBoxLayout" name="horizontalLayout_5"> |        <layout class="QGridLayout" name="gridLayout"> | ||||||
|         <item> |         <item row="0" column="0"> | ||||||
|          <layout class="QVBoxLayout" name="verticalLayout_6"> |          <widget class="QLabel" name="label"> | ||||||
|           <item> |           <property name="text"> | ||||||
|            <layout class="QHBoxLayout" name="horizontalLayout_6"> |            <string>Region:</string> | ||||||
|             <item> |           </property> | ||||||
|              <widget class="QLabel" name="label"> |          </widget> | ||||||
|               <property name="text"> |  | ||||||
|                <string>Region:</string> |  | ||||||
|               </property> |  | ||||||
|              </widget> |  | ||||||
|             </item> |  | ||||||
|             <item> |  | ||||||
|              <widget class="QComboBox" name="region_combobox"> |  | ||||||
|               <item> |  | ||||||
|                <property name="text"> |  | ||||||
|                 <string>Auto-select</string> |  | ||||||
|                </property> |  | ||||||
|               </item> |  | ||||||
|               <item> |  | ||||||
|                <property name="text"> |  | ||||||
|                 <string notr="true">JPN</string> |  | ||||||
|                </property> |  | ||||||
|               </item> |  | ||||||
|               <item> |  | ||||||
|                <property name="text"> |  | ||||||
|                 <string notr="true">USA</string> |  | ||||||
|                </property> |  | ||||||
|               </item> |  | ||||||
|               <item> |  | ||||||
|                <property name="text"> |  | ||||||
|                 <string notr="true">EUR</string> |  | ||||||
|                </property> |  | ||||||
|               </item> |  | ||||||
|               <item> |  | ||||||
|                <property name="text"> |  | ||||||
|                 <string notr="true">AUS</string> |  | ||||||
|                </property> |  | ||||||
|               </item> |  | ||||||
|               <item> |  | ||||||
|                <property name="text"> |  | ||||||
|                 <string notr="true">CHN</string> |  | ||||||
|                </property> |  | ||||||
|               </item> |  | ||||||
|               <item> |  | ||||||
|                <property name="text"> |  | ||||||
|                 <string notr="true">KOR</string> |  | ||||||
|                </property> |  | ||||||
|               </item> |  | ||||||
|               <item> |  | ||||||
|                <property name="text"> |  | ||||||
|                 <string notr="true">TWN</string> |  | ||||||
|                </property> |  | ||||||
|               </item> |  | ||||||
|              </widget> |  | ||||||
|             </item> |  | ||||||
|            </layout> |  | ||||||
|           </item> |  | ||||||
|          </layout> |  | ||||||
|         </item> |         </item> | ||||||
|        </layout> |         <item row="0" column="1"> | ||||||
|       </widget> |          <widget class="QComboBox" name="region_combobox"> | ||||||
|      </item> |  | ||||||
|      <item> |  | ||||||
|       <widget class="QGroupBox" name="groupBox_3"> |  | ||||||
|        <property name="title"> |  | ||||||
|         <string>Hotkeys</string> |  | ||||||
|        </property> |  | ||||||
|        <layout class="QHBoxLayout" name="horizontalLayout_4"> |  | ||||||
|         <item> |  | ||||||
|          <layout class="QVBoxLayout" name="verticalLayout_4"> |  | ||||||
|           <item> |           <item> | ||||||
|            <widget class="GHotkeysDialog" name="hotkeysDialog" native="true"/> |            <property name="text"> | ||||||
|  |             <string>Auto-select</string> | ||||||
|  |            </property> | ||||||
|           </item> |           </item> | ||||||
|          </layout> |           <item> | ||||||
|  |            <property name="text"> | ||||||
|  |             <string notr="true">JPN</string> | ||||||
|  |            </property> | ||||||
|  |           </item> | ||||||
|  |           <item> | ||||||
|  |            <property name="text"> | ||||||
|  |             <string notr="true">USA</string> | ||||||
|  |            </property> | ||||||
|  |           </item> | ||||||
|  |           <item> | ||||||
|  |            <property name="text"> | ||||||
|  |             <string notr="true">EUR</string> | ||||||
|  |            </property> | ||||||
|  |           </item> | ||||||
|  |           <item> | ||||||
|  |            <property name="text"> | ||||||
|  |             <string notr="true">AUS</string> | ||||||
|  |            </property> | ||||||
|  |           </item> | ||||||
|  |           <item> | ||||||
|  |            <property name="text"> | ||||||
|  |             <string notr="true">CHN</string> | ||||||
|  |            </property> | ||||||
|  |           </item> | ||||||
|  |           <item> | ||||||
|  |            <property name="text"> | ||||||
|  |             <string notr="true">KOR</string> | ||||||
|  |            </property> | ||||||
|  |           </item> | ||||||
|  |           <item> | ||||||
|  |            <property name="text"> | ||||||
|  |             <string notr="true">TWN</string> | ||||||
|  |            </property> | ||||||
|  |           </item> | ||||||
|  |          </widget> | ||||||
|         </item> |         </item> | ||||||
|        </layout> |        </layout> | ||||||
|       </widget> |       </widget> | ||||||
| @@ -154,18 +122,23 @@ | |||||||
|        </property> |        </property> | ||||||
|       </widget> |       </widget> | ||||||
|      </item> |      </item> | ||||||
|  |      <item> | ||||||
|  |       <spacer name="verticalSpacer"> | ||||||
|  |        <property name="orientation"> | ||||||
|  |         <enum>Qt::Vertical</enum> | ||||||
|  |        </property> | ||||||
|  |        <property name="sizeHint" stdset="0"> | ||||||
|  |         <size> | ||||||
|  |          <width>20</width> | ||||||
|  |          <height>40</height> | ||||||
|  |         </size> | ||||||
|  |        </property> | ||||||
|  |       </spacer> | ||||||
|  |      </item> | ||||||
|     </layout> |     </layout> | ||||||
|    </item> |    </item> | ||||||
|   </layout> |   </layout> | ||||||
|  </widget> |  </widget> | ||||||
|  <customwidgets> |  | ||||||
|   <customwidget> |  | ||||||
|    <class>GHotkeysDialog</class> |  | ||||||
|    <extends>QWidget</extends> |  | ||||||
|    <header>hotkeys.h</header> |  | ||||||
|    <container>1</container> |  | ||||||
|   </customwidget> |  | ||||||
|  </customwidgets> |  | ||||||
|  <resources/> |  <resources/> | ||||||
|  <connections/> |  <connections/> | ||||||
| </ui> | </ui> | ||||||
|   | |||||||
							
								
								
									
										125
									
								
								src/citra_qt/configuration/configure_hotkeys.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								src/citra_qt/configuration/configure_hotkeys.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,125 @@ | |||||||
|  | // Copyright 2017 Citra Emulator Project | ||||||
|  | // Licensed under GPLv2 or any later version | ||||||
|  | // Refer to the license.txt file included. | ||||||
|  |  | ||||||
|  | #include <QMessageBox> | ||||||
|  | #include <QStandardItemModel> | ||||||
|  | #include "citra_qt/configuration/configure_hotkeys.h" | ||||||
|  | #include "citra_qt/hotkeys.h" | ||||||
|  | #include "citra_qt/util/sequence_dialog/sequence_dialog.h" | ||||||
|  | #include "core/settings.h" | ||||||
|  | #include "ui_configure_hotkeys.h" | ||||||
|  |  | ||||||
|  | ConfigureHotkeys::ConfigureHotkeys(QWidget* parent) | ||||||
|  |     : QWidget(parent), ui(std::make_unique<Ui::ConfigureHotkeys>()) { | ||||||
|  |     ui->setupUi(this); | ||||||
|  |     setFocusPolicy(Qt::ClickFocus); | ||||||
|  |  | ||||||
|  |     model = new QStandardItemModel(this); | ||||||
|  |     model->setColumnCount(3); | ||||||
|  |     model->setHorizontalHeaderLabels({tr("Action"), tr("Hotkey"), tr("Context")}); | ||||||
|  |  | ||||||
|  |     connect(ui->hotkey_list, &QTreeView::doubleClicked, this, &ConfigureHotkeys::Configure); | ||||||
|  |     ui->hotkey_list->setModel(model); | ||||||
|  |  | ||||||
|  |     // TODO(Kloen): Make context configurable as well (hiding the column for now) | ||||||
|  |     ui->hotkey_list->hideColumn(2); | ||||||
|  |  | ||||||
|  |     ui->hotkey_list->setColumnWidth(0, 200); | ||||||
|  |     ui->hotkey_list->resizeColumnToContents(1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ConfigureHotkeys::~ConfigureHotkeys() = default; | ||||||
|  |  | ||||||
|  | void ConfigureHotkeys::EmitHotkeysChanged() { | ||||||
|  |     emit HotkeysChanged(GetUsedKeyList()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QList<QKeySequence> ConfigureHotkeys::GetUsedKeyList() { | ||||||
|  |     QList<QKeySequence> list; | ||||||
|  |     for (int r = 0; r < model->rowCount(); r++) { | ||||||
|  |         QStandardItem* parent = model->item(r, 0); | ||||||
|  |         for (int r2 = 0; r2 < parent->rowCount(); r2++) { | ||||||
|  |             QStandardItem* keyseq = parent->child(r2, 1); | ||||||
|  |             list << QKeySequence::fromString(keyseq->text(), QKeySequence::NativeText); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return list; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ConfigureHotkeys::Populate(const HotkeyRegistry& registry) { | ||||||
|  |     for (const auto& group : registry.hotkey_groups) { | ||||||
|  |         QStandardItem* parent_item = new QStandardItem(group.first); | ||||||
|  |         parent_item->setEditable(false); | ||||||
|  |         for (const auto& hotkey : group.second) { | ||||||
|  |             QStandardItem* action = new QStandardItem(hotkey.first); | ||||||
|  |             QStandardItem* keyseq = | ||||||
|  |                 new QStandardItem(hotkey.second.keyseq.toString(QKeySequence::NativeText)); | ||||||
|  |             action->setEditable(false); | ||||||
|  |             keyseq->setEditable(false); | ||||||
|  |             parent_item->appendRow({action, keyseq}); | ||||||
|  |         } | ||||||
|  |         model->appendRow(parent_item); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ui->hotkey_list->expandAll(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ConfigureHotkeys::OnInputKeysChanged(QList<QKeySequence> new_key_list) { | ||||||
|  |     input_keys_list = new_key_list; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ConfigureHotkeys::Configure(QModelIndex index) { | ||||||
|  |     if (index.parent() == QModelIndex()) | ||||||
|  |         return; | ||||||
|  |  | ||||||
|  |     index = index.sibling(index.row(), 1); | ||||||
|  |     auto* model = ui->hotkey_list->model(); | ||||||
|  |     auto previous_key = model->data(index); | ||||||
|  |  | ||||||
|  |     auto* hotkey_dialog = new SequenceDialog; | ||||||
|  |     int return_code = hotkey_dialog->exec(); | ||||||
|  |  | ||||||
|  |     auto key_sequence = hotkey_dialog->GetSequence(); | ||||||
|  |  | ||||||
|  |     if (return_code == QDialog::Rejected || key_sequence.isEmpty()) | ||||||
|  |         return; | ||||||
|  |  | ||||||
|  |     if (IsUsedKey(key_sequence) && key_sequence != QKeySequence(previous_key.toString())) { | ||||||
|  |         QMessageBox::critical(this, tr("Error in inputted key"), | ||||||
|  |                               tr("You're using a key that's already bound.")); | ||||||
|  |     } else { | ||||||
|  |         model->setData(index, key_sequence.toString(QKeySequence::NativeText)); | ||||||
|  |         EmitHotkeysChanged(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool ConfigureHotkeys::IsUsedKey(QKeySequence key_sequence) { | ||||||
|  |     return input_keys_list.contains(key_sequence) || GetUsedKeyList().contains(key_sequence); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ConfigureHotkeys::applyConfiguration(HotkeyRegistry& registry) { | ||||||
|  |     for (int key_id = 0; key_id < model->rowCount(); key_id++) { | ||||||
|  |         QStandardItem* parent = model->item(key_id, 0); | ||||||
|  |         for (int key_column_id = 0; key_column_id < parent->rowCount(); key_column_id++) { | ||||||
|  |             QStandardItem* action = parent->child(key_column_id, 0); | ||||||
|  |             QStandardItem* keyseq = parent->child(key_column_id, 1); | ||||||
|  |             for (auto& [group, sub_actions] : registry.hotkey_groups) { | ||||||
|  |                 if (group != parent->text()) | ||||||
|  |                     continue; | ||||||
|  |                 for (auto& [action_name, hotkey] : sub_actions) { | ||||||
|  |                     if (action_name != action->text()) | ||||||
|  |                         continue; | ||||||
|  |                     hotkey.keyseq = QKeySequence(keyseq->text()); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     registry.SaveHotkeys(); | ||||||
|  |     Settings::Apply(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ConfigureHotkeys::retranslateUi() { | ||||||
|  |     ui->retranslateUi(this); | ||||||
|  | } | ||||||
							
								
								
									
										58
									
								
								src/citra_qt/configuration/configure_hotkeys.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/citra_qt/configuration/configure_hotkeys.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | |||||||
|  | // Copyright 2017 Citra Emulator Project | ||||||
|  | // Licensed under GPLv2 or any later version | ||||||
|  | // Refer to the license.txt file included. | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <memory> | ||||||
|  | #include <QWidget> | ||||||
|  | #include "core/settings.h" | ||||||
|  |  | ||||||
|  | namespace Ui { | ||||||
|  | class ConfigureHotkeys; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class HotkeyRegistry; | ||||||
|  | class QStandardItemModel; | ||||||
|  |  | ||||||
|  | class ConfigureHotkeys : public QWidget { | ||||||
|  |     Q_OBJECT | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |     explicit ConfigureHotkeys(QWidget* parent = nullptr); | ||||||
|  |     ~ConfigureHotkeys(); | ||||||
|  |  | ||||||
|  |     void applyConfiguration(HotkeyRegistry& registry); | ||||||
|  |     void retranslateUi(); | ||||||
|  |  | ||||||
|  |     void EmitHotkeysChanged(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Populates the hotkey list widget using data from the provided registry. | ||||||
|  |      * Called everytime the Configure dialog is opened. | ||||||
|  |      * @param registry The HotkeyRegistry whose data is used to populate the list. | ||||||
|  |      */ | ||||||
|  |     void Populate(const HotkeyRegistry& registry); | ||||||
|  |  | ||||||
|  | public slots: | ||||||
|  |     void OnInputKeysChanged(QList<QKeySequence> new_key_list); | ||||||
|  |  | ||||||
|  | signals: | ||||||
|  |     void HotkeysChanged(QList<QKeySequence> new_key_list); | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     void Configure(QModelIndex index); | ||||||
|  |     bool IsUsedKey(QKeySequence key_sequence); | ||||||
|  |     QList<QKeySequence> GetUsedKeyList(); | ||||||
|  |  | ||||||
|  |     std::unique_ptr<Ui::ConfigureHotkeys> ui; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * List of keyboard keys currently registered to any of the 3DS inputs. | ||||||
|  |      * These can't be bound to any hotkey. | ||||||
|  |      * Synchronised with ConfigureInput via signal-slot. | ||||||
|  |      */ | ||||||
|  |     QList<QKeySequence> input_keys_list; | ||||||
|  |  | ||||||
|  |     QStandardItemModel* model; | ||||||
|  | }; | ||||||
							
								
								
									
										42
									
								
								src/citra_qt/configuration/configure_hotkeys.ui
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/citra_qt/configuration/configure_hotkeys.ui
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <ui version="4.0"> | ||||||
|  |  <class>ConfigureHotkeys</class> | ||||||
|  |  <widget class="QWidget" name="ConfigureHotkeys"> | ||||||
|  |   <property name="geometry"> | ||||||
|  |    <rect> | ||||||
|  |     <x>0</x> | ||||||
|  |     <y>0</y> | ||||||
|  |     <width>363</width> | ||||||
|  |     <height>388</height> | ||||||
|  |    </rect> | ||||||
|  |   </property> | ||||||
|  |   <property name="windowTitle"> | ||||||
|  |    <string>Hotkey Settings</string> | ||||||
|  |   </property> | ||||||
|  |   <layout class="QVBoxLayout" name="verticalLayout"> | ||||||
|  |    <item> | ||||||
|  |     <layout class="QVBoxLayout" name="verticalLayout_2"> | ||||||
|  |      <item> | ||||||
|  |       <widget class="QLabel" name="label_2"> | ||||||
|  |        <property name="text"> | ||||||
|  |         <string>Double-click on a binding to change it.</string> | ||||||
|  |        </property> | ||||||
|  |       </widget> | ||||||
|  |      </item> | ||||||
|  |      <item> | ||||||
|  |       <widget class="QTreeView" name="hotkey_list"> | ||||||
|  |        <property name="editTriggers"> | ||||||
|  |         <set>QAbstractItemView::NoEditTriggers</set> | ||||||
|  |        </property> | ||||||
|  |        <property name="sortingEnabled"> | ||||||
|  |         <bool>false</bool> | ||||||
|  |        </property> | ||||||
|  |       </widget> | ||||||
|  |      </item> | ||||||
|  |     </layout> | ||||||
|  |    </item> | ||||||
|  |   </layout> | ||||||
|  |  </widget> | ||||||
|  |  <resources/> | ||||||
|  |  <connections/> | ||||||
|  | </ui> | ||||||
| @@ -276,6 +276,30 @@ void ConfigureInput::ApplyProfile() { | |||||||
|     Settings::values.current_input_profile_index = ui->profile->currentIndex(); |     Settings::values.current_input_profile_index = ui->profile->currentIndex(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void ConfigureInput::EmitInputKeysChanged() { | ||||||
|  |     emit InputKeysChanged(GetUsedKeyboardKeys()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ConfigureInput::OnHotkeysChanged(QList<QKeySequence> new_key_list) { | ||||||
|  |     hotkey_list = new_key_list; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QList<QKeySequence> ConfigureInput::GetUsedKeyboardKeys() { | ||||||
|  |     QList<QKeySequence> list; | ||||||
|  |     for (int button = 0; button < Settings::NativeButton::NumButtons; button++) { | ||||||
|  |         auto button_param = buttons_param[button]; | ||||||
|  |  | ||||||
|  |         if (button_param.Get("engine", "") == "keyboard") { | ||||||
|  |             list << QKeySequence(button_param.Get("code", 0)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // TODO(adityaruplaha): Add home button to list when we finally emulate it | ||||||
|  |     // Button ID of home button is 14: Referred from citra_qt/configuration/config.cpp | ||||||
|  |     list.removeOne(list.indexOf(QKeySequence(buttons_param[14].Get("code", 0)))); | ||||||
|  |     return list; | ||||||
|  | } | ||||||
|  |  | ||||||
| void ConfigureInput::loadConfiguration() { | void ConfigureInput::loadConfiguration() { | ||||||
|     std::transform(Settings::values.current_input_profile.buttons.begin(), |     std::transform(Settings::values.current_input_profile.buttons.begin(), | ||||||
|                    Settings::values.current_input_profile.buttons.end(), buttons_param.begin(), |                    Settings::values.current_input_profile.buttons.end(), buttons_param.begin(), | ||||||
| @@ -332,11 +356,14 @@ void ConfigureInput::updateButtonLabels() { | |||||||
|         } |         } | ||||||
|         analog_map_stick[analog_id]->setText(tr("Set Analog Stick")); |         analog_map_stick[analog_id]->setText(tr("Set Analog Stick")); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     EmitInputKeysChanged(); | ||||||
| } | } | ||||||
|  |  | ||||||
| void ConfigureInput::handleClick(QPushButton* button, | void ConfigureInput::handleClick(QPushButton* button, | ||||||
|                                  std::function<void(const Common::ParamPackage&)> new_input_setter, |                                  std::function<void(const Common::ParamPackage&)> new_input_setter, | ||||||
|                                  InputCommon::Polling::DeviceType type) { |                                  InputCommon::Polling::DeviceType type) { | ||||||
|  |     previous_key_code = QKeySequence(button->text())[0]; | ||||||
|     button->setText(tr("[press key]")); |     button->setText(tr("[press key]")); | ||||||
|     button->setFocus(); |     button->setFocus(); | ||||||
|  |  | ||||||
| @@ -378,16 +405,26 @@ void ConfigureInput::keyPressEvent(QKeyEvent* event) { | |||||||
|     if (!input_setter || !event) |     if (!input_setter || !event) | ||||||
|         return; |         return; | ||||||
|  |  | ||||||
|     if (event->key() != Qt::Key_Escape) { |     if (event->key() != Qt::Key_Escape && event->key() != previous_key_code) { | ||||||
|         if (want_keyboard_keys) { |         if (want_keyboard_keys) { | ||||||
|  |             // Check if key is already bound | ||||||
|  |             if (hotkey_list.contains(QKeySequence(event->key())) || | ||||||
|  |                 GetUsedKeyboardKeys().contains(QKeySequence(event->key()))) { | ||||||
|  |                 setPollingResult({}, true); | ||||||
|  |                 QMessageBox::critical(this, tr("Error!"), | ||||||
|  |                                       tr("You're using a key that's already bound.")); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|             setPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())}, |             setPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())}, | ||||||
|                              false); |                              false); | ||||||
|         } else { |         } else { | ||||||
|             // Escape key wasn't pressed and we don't want any keyboard keys, so don't stop polling |             // Escape key wasn't pressed and we don't want any keyboard keys, so don't stop | ||||||
|  |             // polling | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     setPollingResult({}, true); |     setPollingResult({}, true); | ||||||
|  |     previous_key_code = 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| void ConfigureInput::retranslateUi() { | void ConfigureInput::retranslateUi() { | ||||||
|   | |||||||
| @@ -11,6 +11,7 @@ | |||||||
| #include <string> | #include <string> | ||||||
| #include <unordered_map> | #include <unordered_map> | ||||||
| #include <QKeyEvent> | #include <QKeyEvent> | ||||||
|  | #include <QKeySequence> | ||||||
| #include <QWidget> | #include <QWidget> | ||||||
| #include "common/param_package.h" | #include "common/param_package.h" | ||||||
| #include "core/settings.h" | #include "core/settings.h" | ||||||
| @@ -38,9 +39,15 @@ public: | |||||||
|  |  | ||||||
|     /// Load configuration settings. |     /// Load configuration settings. | ||||||
|     void loadConfiguration(); |     void loadConfiguration(); | ||||||
|  |     void EmitInputKeysChanged(); | ||||||
|  |  | ||||||
|     // Save the current input profile index |     /// Save the current input profile index | ||||||
|     void ApplyProfile(); |     void ApplyProfile(); | ||||||
|  | public slots: | ||||||
|  |     void OnHotkeysChanged(QList<QKeySequence> new_key_list); | ||||||
|  |  | ||||||
|  | signals: | ||||||
|  |     void InputKeysChanged(QList<QKeySequence> new_key_list); | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     std::unique_ptr<Ui::ConfigureInput> ui; |     std::unique_ptr<Ui::ConfigureInput> ui; | ||||||
| @@ -72,10 +79,20 @@ private: | |||||||
|  |  | ||||||
|     std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> device_pollers; |     std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> device_pollers; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * List of keys currently registered to hotkeys. | ||||||
|  |      * These can't be bound to any input key. | ||||||
|  |      * Synchronised with ConfigureHotkeys via signal-slot. | ||||||
|  |      */ | ||||||
|  |     QList<QKeySequence> hotkey_list; | ||||||
|  |  | ||||||
|     /// A flag to indicate if keyboard keys are okay when configuring an input. If this is false, |     /// A flag to indicate if keyboard keys are okay when configuring an input. If this is false, | ||||||
|     /// keyboard events are ignored. |     /// keyboard events are ignored. | ||||||
|     bool want_keyboard_keys = false; |     bool want_keyboard_keys = false; | ||||||
|  |  | ||||||
|  |     /// Generates list of all used keys | ||||||
|  |     QList<QKeySequence> GetUsedKeyboardKeys(); | ||||||
|  |  | ||||||
|     /// Restore all buttons to their default values. |     /// Restore all buttons to their default values. | ||||||
|     void restoreDefaults(); |     void restoreDefaults(); | ||||||
|     /// Clear all input configuration |     /// Clear all input configuration | ||||||
| @@ -89,6 +106,9 @@ private: | |||||||
|                      std::function<void(const Common::ParamPackage&)> new_input_setter, |                      std::function<void(const Common::ParamPackage&)> new_input_setter, | ||||||
|                      InputCommon::Polling::DeviceType type); |                      InputCommon::Polling::DeviceType type); | ||||||
|  |  | ||||||
|  |     /// The key code of the previous state of the key being currently bound. | ||||||
|  |     int previous_key_code; | ||||||
|  |  | ||||||
|     /// Finish polling and configure input using the input_setter |     /// Finish polling and configure input using the input_setter | ||||||
|     void setPollingResult(const Common::ParamPackage& params, bool abort); |     void setPollingResult(const Common::ParamPackage& params, bool abort); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,7 +2,6 @@ | |||||||
| // Licensed under GPLv2 or any later version | // Licensed under GPLv2 or any later version | ||||||
| // Refer to the license.txt file included. | // Refer to the license.txt file included. | ||||||
|  |  | ||||||
| #include <map> |  | ||||||
| #include <QKeySequence> | #include <QKeySequence> | ||||||
| #include <QShortcut> | #include <QShortcut> | ||||||
| #include <QtGlobal> | #include <QtGlobal> | ||||||
| @@ -12,47 +11,32 @@ | |||||||
| HotkeyRegistry::HotkeyRegistry() = default; | HotkeyRegistry::HotkeyRegistry() = default; | ||||||
| HotkeyRegistry::~HotkeyRegistry() = default; | HotkeyRegistry::~HotkeyRegistry() = default; | ||||||
|  |  | ||||||
| void HotkeyRegistry::LoadHotkeys() { |  | ||||||
|     // Make sure NOT to use a reference here because it would become invalid once we call |  | ||||||
|     // beginGroup() |  | ||||||
|     for (auto shortcut : UISettings::values.shortcuts) { |  | ||||||
|         const QStringList cat = shortcut.first.split('/'); |  | ||||||
|         Q_ASSERT(cat.size() >= 2); |  | ||||||
|  |  | ||||||
|         // RegisterHotkey assigns default keybindings, so use old values as default parameters |  | ||||||
|         Hotkey& hk = hotkey_groups[cat[0]][cat[1]]; |  | ||||||
|         if (!shortcut.second.first.isEmpty()) { |  | ||||||
|             hk.keyseq = QKeySequence::fromString(shortcut.second.first); |  | ||||||
|             hk.context = static_cast<Qt::ShortcutContext>(shortcut.second.second); |  | ||||||
|         } |  | ||||||
|         if (hk.shortcut) |  | ||||||
|             hk.shortcut->setKey(hk.keyseq); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void HotkeyRegistry::SaveHotkeys() { | void HotkeyRegistry::SaveHotkeys() { | ||||||
|     UISettings::values.shortcuts.clear(); |     UISettings::values.shortcuts.clear(); | ||||||
|     for (const auto& group : hotkey_groups) { |     for (const auto& group : hotkey_groups) { | ||||||
|         for (const auto& hotkey : group.second) { |         for (const auto& hotkey : group.second) { | ||||||
|             UISettings::values.shortcuts.emplace_back( |             UISettings::values.shortcuts.push_back( | ||||||
|                 UISettings::Shortcut(group.first + '/' + hotkey.first, |                 {hotkey.first, group.first, | ||||||
|                                      UISettings::ContextualShortcut(hotkey.second.keyseq.toString(), |                  UISettings::ContextualShortcut(hotkey.second.keyseq.toString(), | ||||||
|                                                                     hotkey.second.context))); |                                                 hotkey.second.context)}); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| void HotkeyRegistry::RegisterHotkey(const QString& group, const QString& action, | void HotkeyRegistry::LoadHotkeys() { | ||||||
|                                     const QKeySequence& default_keyseq, |     // Make sure NOT to use a reference here because it would become invalid once we call | ||||||
|                                     Qt::ShortcutContext default_context) { |     // beginGroup() | ||||||
|     auto& hotkey_group = hotkey_groups[group]; |     for (auto shortcut : UISettings::values.shortcuts) { | ||||||
|     if (hotkey_group.find(action) != hotkey_group.end()) { |         Hotkey& hk = hotkey_groups[shortcut.group][shortcut.name]; | ||||||
|         return; |         if (!shortcut.shortcut.first.isEmpty()) { | ||||||
|  |             hk.keyseq = QKeySequence::fromString(shortcut.shortcut.first, QKeySequence::NativeText); | ||||||
|  |             hk.context = static_cast<Qt::ShortcutContext>(shortcut.shortcut.second); | ||||||
|  |         } | ||||||
|  |         if (hk.shortcut) { | ||||||
|  |             hk.shortcut->disconnect(); | ||||||
|  |             hk.shortcut->setKey(hk.keyseq); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     auto& hotkey_action = hotkey_groups[group][action]; |  | ||||||
|     hotkey_action.keyseq = default_keyseq; |  | ||||||
|     hotkey_action.context = default_context; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| QShortcut* HotkeyRegistry::GetHotkey(const QString& group, const QString& action, QWidget* widget) { | QShortcut* HotkeyRegistry::GetHotkey(const QString& group, const QString& action, QWidget* widget) { | ||||||
| @@ -64,28 +48,13 @@ QShortcut* HotkeyRegistry::GetHotkey(const QString& group, const QString& action | |||||||
|     return hk.shortcut; |     return hk.shortcut; | ||||||
| } | } | ||||||
|  |  | ||||||
| GHotkeysDialog::GHotkeysDialog(QWidget* parent) : QWidget(parent) { | QKeySequence HotkeyRegistry::GetKeySequence(const QString& group, const QString& action) { | ||||||
|     ui.setupUi(this); |     Hotkey& hk = hotkey_groups[group][action]; | ||||||
|  |     return hk.keyseq; | ||||||
| } | } | ||||||
|  |  | ||||||
| void GHotkeysDialog::Populate(const HotkeyRegistry& registry) { | Qt::ShortcutContext HotkeyRegistry::GetShortcutContext(const QString& group, | ||||||
|     for (const auto& group : registry.hotkey_groups) { |                                                        const QString& action) { | ||||||
|         QTreeWidgetItem* toplevel_item = new QTreeWidgetItem(QStringList(group.first)); |     Hotkey& hk = hotkey_groups[group][action]; | ||||||
|         for (const auto& hotkey : group.second) { |     return hk.context; | ||||||
|             QStringList columns; |  | ||||||
|             columns << hotkey.first << hotkey.second.keyseq.toString(); |  | ||||||
|             QTreeWidgetItem* item = new QTreeWidgetItem(columns); |  | ||||||
|             toplevel_item->addChild(item); |  | ||||||
|         } |  | ||||||
|         ui.treeWidget->addTopLevelItem(toplevel_item); |  | ||||||
|     } |  | ||||||
|     // TODO: Make context configurable as well (hiding the column for now) |  | ||||||
|     ui.treeWidget->setColumnCount(2); |  | ||||||
|  |  | ||||||
|     ui.treeWidget->resizeColumnToContents(0); |  | ||||||
|     ui.treeWidget->resizeColumnToContents(1); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void GHotkeysDialog::retranslateUi() { |  | ||||||
|     ui.retranslateUi(this); |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -5,7 +5,6 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include <map> | #include <map> | ||||||
| #include "ui_hotkeys.h" |  | ||||||
|  |  | ||||||
| class QDialog; | class QDialog; | ||||||
| class QKeySequence; | class QKeySequence; | ||||||
| @@ -14,7 +13,7 @@ class QShortcut; | |||||||
|  |  | ||||||
| class HotkeyRegistry final { | class HotkeyRegistry final { | ||||||
| public: | public: | ||||||
|     friend class GHotkeysDialog; |     friend class ConfigureHotkeys; | ||||||
|  |  | ||||||
|     explicit HotkeyRegistry(); |     explicit HotkeyRegistry(); | ||||||
|     ~HotkeyRegistry(); |     ~HotkeyRegistry(); | ||||||
| @@ -49,22 +48,27 @@ public: | |||||||
|     QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widget); |     QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widget); | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Register a hotkey. |      * Returns a QKeySequence object whose signal can be connected to QAction::setShortcut. | ||||||
|      * |      * | ||||||
|      * @param group General group this hotkey belongs to (e.g. "Main Window", "Debugger") |      * @param group  General group this hotkey belongs to (e.g. "Main Window", "Debugger"). | ||||||
|      * @param action Name of the action (e.g. "Start Emulation", "Load Image") |      * @param action Name of the action (e.g. "Start Emulation", "Load Image"). | ||||||
|      * @param default_keyseq Default key sequence to assign if the hotkey wasn't present in the |  | ||||||
|      *                       settings file before |  | ||||||
|      * @param default_context Default context to assign if the hotkey wasn't present in the settings |  | ||||||
|      *                        file before |  | ||||||
|      * @warning Both the group and action strings will be displayed in the hotkey settings dialog |  | ||||||
|      */ |      */ | ||||||
|     void RegisterHotkey(const QString& group, const QString& action, |     QKeySequence GetKeySequence(const QString& group, const QString& action); | ||||||
|                         const QKeySequence& default_keyseq = {}, |  | ||||||
|                         Qt::ShortcutContext default_context = Qt::WindowShortcut); |     /** | ||||||
|  |      * Returns a Qt::ShortcutContext object who can be connected to other | ||||||
|  |      * QAction::setShortcutContext. | ||||||
|  |      * | ||||||
|  |      * @param group  General group this shortcut context belongs to (e.g. "Main Window", | ||||||
|  |      * "Debugger"). | ||||||
|  |      * @param action Name of the action (e.g. "Start Emulation", "Load Image"). | ||||||
|  |      */ | ||||||
|  |     Qt::ShortcutContext GetShortcutContext(const QString& group, const QString& action); | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     struct Hotkey { |     struct Hotkey { | ||||||
|  |         Hotkey() : shortcut(nullptr), context(Qt::WindowShortcut) {} | ||||||
|  |  | ||||||
|         QKeySequence keyseq; |         QKeySequence keyseq; | ||||||
|         QShortcut* shortcut = nullptr; |         QShortcut* shortcut = nullptr; | ||||||
|         Qt::ShortcutContext context = Qt::WindowShortcut; |         Qt::ShortcutContext context = Qt::WindowShortcut; | ||||||
| @@ -75,16 +79,3 @@ private: | |||||||
|  |  | ||||||
|     HotkeyGroupMap hotkey_groups; |     HotkeyGroupMap hotkey_groups; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| class GHotkeysDialog : public QWidget { |  | ||||||
|     Q_OBJECT |  | ||||||
|  |  | ||||||
| public: |  | ||||||
|     explicit GHotkeysDialog(QWidget* parent = nullptr); |  | ||||||
|     void retranslateUi(); |  | ||||||
|  |  | ||||||
|     void Populate(const HotkeyRegistry& registry); |  | ||||||
|  |  | ||||||
| private: |  | ||||||
|     Ui::hotkeys ui; |  | ||||||
| }; |  | ||||||
|   | |||||||
| @@ -1,46 +0,0 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8"?> |  | ||||||
| <ui version="4.0"> |  | ||||||
|  <class>hotkeys</class> |  | ||||||
|  <widget class="QWidget" name="hotkeys"> |  | ||||||
|   <property name="geometry"> |  | ||||||
|    <rect> |  | ||||||
|     <x>0</x> |  | ||||||
|     <y>0</y> |  | ||||||
|     <width>363</width> |  | ||||||
|     <height>388</height> |  | ||||||
|    </rect> |  | ||||||
|   </property> |  | ||||||
|   <property name="windowTitle"> |  | ||||||
|    <string>Hotkey Settings</string> |  | ||||||
|   </property> |  | ||||||
|   <layout class="QVBoxLayout" name="verticalLayout"> |  | ||||||
|    <item> |  | ||||||
|     <widget class="QTreeWidget" name="treeWidget"> |  | ||||||
|      <property name="selectionBehavior"> |  | ||||||
|       <enum>QAbstractItemView::SelectItems</enum> |  | ||||||
|      </property> |  | ||||||
|      <property name="headerHidden"> |  | ||||||
|       <bool>false</bool> |  | ||||||
|      </property> |  | ||||||
|      <column> |  | ||||||
|       <property name="text"> |  | ||||||
|        <string>Action</string> |  | ||||||
|       </property> |  | ||||||
|      </column> |  | ||||||
|      <column> |  | ||||||
|       <property name="text"> |  | ||||||
|        <string>Hotkey</string> |  | ||||||
|       </property> |  | ||||||
|      </column> |  | ||||||
|      <column> |  | ||||||
|       <property name="text"> |  | ||||||
|        <string>Context</string> |  | ||||||
|       </property> |  | ||||||
|      </column> |  | ||||||
|     </widget> |  | ||||||
|    </item> |  | ||||||
|   </layout> |  | ||||||
|  </widget> |  | ||||||
|  <resources/> |  | ||||||
|  <connections/> |  | ||||||
| </ui> |  | ||||||
| @@ -344,40 +344,35 @@ void GMainWindow::InitializeRecentFileMenuActions() { | |||||||
| } | } | ||||||
|  |  | ||||||
| void GMainWindow::InitializeHotkeys() { | void GMainWindow::InitializeHotkeys() { | ||||||
|     hotkey_registry.RegisterHotkey("Main Window", "Load File", QKeySequence::Open); |  | ||||||
|     hotkey_registry.RegisterHotkey("Main Window", "Start Emulation"); |  | ||||||
|     hotkey_registry.RegisterHotkey("Main Window", "Continue/Pause", QKeySequence(Qt::Key_F4)); |  | ||||||
|     hotkey_registry.RegisterHotkey("Main Window", "Restart", QKeySequence(Qt::Key_F5)); |  | ||||||
|     hotkey_registry.RegisterHotkey("Main Window", "Swap Screens", QKeySequence(Qt::Key_F9)); |  | ||||||
|     hotkey_registry.RegisterHotkey("Main Window", "Toggle Screen Layout", |  | ||||||
|                                    QKeySequence(Qt::Key_F10)); |  | ||||||
|     hotkey_registry.RegisterHotkey("Main Window", "Fullscreen", QKeySequence::FullScreen); |  | ||||||
|     hotkey_registry.RegisterHotkey("Main Window", "Exit Fullscreen", QKeySequence(Qt::Key_Escape), |  | ||||||
|                                    Qt::ApplicationShortcut); |  | ||||||
|     hotkey_registry.RegisterHotkey("Main Window", "Toggle Speed Limit", QKeySequence("CTRL+Z"), |  | ||||||
|                                    Qt::ApplicationShortcut); |  | ||||||
|     hotkey_registry.RegisterHotkey("Main Window", "Increase Speed Limit", QKeySequence("+"), |  | ||||||
|                                    Qt::ApplicationShortcut); |  | ||||||
|     hotkey_registry.RegisterHotkey("Main Window", "Decrease Speed Limit", QKeySequence("-"), |  | ||||||
|                                    Qt::ApplicationShortcut); |  | ||||||
|     hotkey_registry.RegisterHotkey("Main Window", "Toggle Frame Advancing", QKeySequence("CTRL+A"), |  | ||||||
|                                    Qt::ApplicationShortcut); |  | ||||||
|     hotkey_registry.RegisterHotkey("Main Window", "Advance Frame", QKeySequence(Qt::Key_Backslash), |  | ||||||
|                                    Qt::ApplicationShortcut); |  | ||||||
|     hotkey_registry.RegisterHotkey("Main Window", "Load Amiibo", QKeySequence(Qt::Key_F2), |  | ||||||
|                                    Qt::ApplicationShortcut); |  | ||||||
|     hotkey_registry.RegisterHotkey("Main Window", "Remove Amiibo", QKeySequence(Qt::Key_F3), |  | ||||||
|                                    Qt::ApplicationShortcut); |  | ||||||
|     hotkey_registry.RegisterHotkey("Main Window", "Capture Screenshot", QKeySequence(tr("CTRL+P"))); |  | ||||||
|  |  | ||||||
|     hotkey_registry.LoadHotkeys(); |     hotkey_registry.LoadHotkeys(); | ||||||
|  |  | ||||||
|  |     ui.action_Load_File->setShortcut(hotkey_registry.GetKeySequence("Main Window", "Load File")); | ||||||
|  |     ui.action_Load_File->setShortcutContext( | ||||||
|  |         hotkey_registry.GetShortcutContext("Main Window", "Load File")); | ||||||
|  |  | ||||||
|  |     ui.action_Exit->setShortcut(hotkey_registry.GetKeySequence("Main Window", "Exit Citra")); | ||||||
|  |     ui.action_Exit->setShortcutContext( | ||||||
|  |         hotkey_registry.GetShortcutContext("Main Window", "Exit Citra")); | ||||||
|  |  | ||||||
|  |     ui.action_Stop->setShortcut(hotkey_registry.GetKeySequence("Main Window", "Stop Emulation")); | ||||||
|  |     ui.action_Stop->setShortcutContext( | ||||||
|  |         hotkey_registry.GetShortcutContext("Main Window", "Stop Emulation")); | ||||||
|  |  | ||||||
|  |     ui.action_Show_Filter_Bar->setShortcut( | ||||||
|  |         hotkey_registry.GetKeySequence("Main Window", "Toggle Filter Bar")); | ||||||
|  |     ui.action_Show_Filter_Bar->setShortcutContext( | ||||||
|  |         hotkey_registry.GetShortcutContext("Main Window", "Toggle Filter Bar")); | ||||||
|  |  | ||||||
|  |     ui.action_Show_Status_Bar->setShortcut( | ||||||
|  |         hotkey_registry.GetKeySequence("Main Window", "Toggle Status Bar")); | ||||||
|  |     ui.action_Show_Status_Bar->setShortcutContext( | ||||||
|  |         hotkey_registry.GetShortcutContext("Main Window", "Toggle Status Bar")); | ||||||
|  |  | ||||||
|     connect(hotkey_registry.GetHotkey("Main Window", "Load File", this), &QShortcut::activated, |     connect(hotkey_registry.GetHotkey("Main Window", "Load File", this), &QShortcut::activated, | ||||||
|             this, &GMainWindow::OnMenuLoadFile); |             this, &GMainWindow::OnMenuLoadFile); | ||||||
|     connect(hotkey_registry.GetHotkey("Main Window", "Start Emulation", this), |  | ||||||
|             &QShortcut::activated, this, &GMainWindow::OnStartGame); |     connect(hotkey_registry.GetHotkey("Main Window", "Continue/Pause Emulation", this), | ||||||
|     connect(hotkey_registry.GetHotkey("Main Window", "Continue/Pause", this), &QShortcut::activated, |             &QShortcut::activated, this, [&] { | ||||||
|             this, [&] { |  | ||||||
|                 if (emulation_running) { |                 if (emulation_running) { | ||||||
|                     if (emu_thread->IsRunning()) { |                     if (emu_thread->IsRunning()) { | ||||||
|                         OnPauseGame(); |                         OnPauseGame(); | ||||||
| @@ -386,8 +381,8 @@ void GMainWindow::InitializeHotkeys() { | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             }); |             }); | ||||||
|     connect(hotkey_registry.GetHotkey("Main Window", "Restart", this), &QShortcut::activated, this, |     connect(hotkey_registry.GetHotkey("Main Window", "Restart Emulation", this), | ||||||
|             [this] { |             &QShortcut::activated, this, [this] { | ||||||
|                 if (!Core::System::GetInstance().IsPoweredOn()) |                 if (!Core::System::GetInstance().IsPoweredOn()) | ||||||
|                     return; |                     return; | ||||||
|                 BootGame(QString(game_path)); |                 BootGame(QString(game_path)); | ||||||
| @@ -546,7 +541,6 @@ void GMainWindow::ConnectMenuEvents() { | |||||||
|             &GMainWindow::ToggleWindowMode); |             &GMainWindow::ToggleWindowMode); | ||||||
|     connect(ui.action_Display_Dock_Widget_Headers, &QAction::triggered, this, |     connect(ui.action_Display_Dock_Widget_Headers, &QAction::triggered, this, | ||||||
|             &GMainWindow::OnDisplayTitleBars); |             &GMainWindow::OnDisplayTitleBars); | ||||||
|     ui.action_Show_Filter_Bar->setShortcut(tr("CTRL+F")); |  | ||||||
|     connect(ui.action_Show_Filter_Bar, &QAction::triggered, this, &GMainWindow::OnToggleFilterBar); |     connect(ui.action_Show_Filter_Bar, &QAction::triggered, this, &GMainWindow::OnToggleFilterBar); | ||||||
|     connect(ui.action_Show_Status_Bar, &QAction::triggered, statusBar(), &QStatusBar::setVisible); |     connect(ui.action_Show_Status_Bar, &QAction::triggered, statusBar(), &QStatusBar::setVisible); | ||||||
|  |  | ||||||
| @@ -1332,6 +1326,7 @@ void GMainWindow::OnConfigure() { | |||||||
|     auto result = configureDialog.exec(); |     auto result = configureDialog.exec(); | ||||||
|     if (result == QDialog::Accepted) { |     if (result == QDialog::Accepted) { | ||||||
|         configureDialog.applyConfiguration(); |         configureDialog.applyConfiguration(); | ||||||
|  |         InitializeHotkeys(); | ||||||
|         if (UISettings::values.theme != old_theme) |         if (UISettings::values.theme != old_theme) | ||||||
|             UpdateUITheme(); |             UpdateUITheme(); | ||||||
|         if (UISettings::values.enable_discord_presence != old_discord_presence) |         if (UISettings::values.enable_discord_presence != old_discord_presence) | ||||||
|   | |||||||
| @@ -96,7 +96,6 @@ private: | |||||||
|     void InitializeWidgets(); |     void InitializeWidgets(); | ||||||
|     void InitializeDebugWidgets(); |     void InitializeDebugWidgets(); | ||||||
|     void InitializeRecentFileMenuActions(); |     void InitializeRecentFileMenuActions(); | ||||||
|     void InitializeHotkeys(); |  | ||||||
|  |  | ||||||
|     void SetDefaultUIGeometry(); |     void SetDefaultUIGeometry(); | ||||||
|     void SyncMenuUISettings(); |     void SyncMenuUISettings(); | ||||||
| @@ -171,6 +170,7 @@ private slots: | |||||||
|     void OnOpenCitraFolder(); |     void OnOpenCitraFolder(); | ||||||
|     void OnToggleFilterBar(); |     void OnToggleFilterBar(); | ||||||
|     void OnDisplayTitleBars(bool); |     void OnDisplayTitleBars(bool); | ||||||
|  |     void InitializeHotkeys(); | ||||||
|     void ToggleFullscreen(); |     void ToggleFullscreen(); | ||||||
|     void ChangeScreenLayout(); |     void ChangeScreenLayout(); | ||||||
|     void ToggleScreenLayout(); |     void ToggleScreenLayout(); | ||||||
|   | |||||||
| @@ -14,5 +14,4 @@ const Themes themes{{ | |||||||
| }}; | }}; | ||||||
|  |  | ||||||
| Values values = {}; | Values values = {}; | ||||||
|  |  | ||||||
| } // namespace UISettings | } // namespace UISettings | ||||||
|   | |||||||
| @@ -17,7 +17,12 @@ | |||||||
| namespace UISettings { | namespace UISettings { | ||||||
|  |  | ||||||
| using ContextualShortcut = std::pair<QString, int>; | using ContextualShortcut = std::pair<QString, int>; | ||||||
| using Shortcut = std::pair<QString, ContextualShortcut>; |  | ||||||
|  | struct Shortcut { | ||||||
|  |     QString name; | ||||||
|  |     QString group; | ||||||
|  |     ContextualShortcut shortcut; | ||||||
|  | }; | ||||||
|  |  | ||||||
| using Themes = std::array<std::pair<const char*, const char*>, 4>; | using Themes = std::array<std::pair<const char*, const char*>, 4>; | ||||||
| extern const Themes themes; | extern const Themes themes; | ||||||
|   | |||||||
							
								
								
									
										37
									
								
								src/citra_qt/util/sequence_dialog/sequence_dialog.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/citra_qt/util/sequence_dialog/sequence_dialog.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | |||||||
|  | // Copyright 2018 Citra Emulator Project | ||||||
|  | // Licensed under GPLv2 or any later version | ||||||
|  | // Refer to the license.txt file included. | ||||||
|  |  | ||||||
|  | #include <QDialogButtonBox> | ||||||
|  | #include <QKeySequenceEdit> | ||||||
|  | #include <QVBoxLayout> | ||||||
|  | #include "citra_qt/util/sequence_dialog/sequence_dialog.h" | ||||||
|  |  | ||||||
|  | SequenceDialog::SequenceDialog(QWidget* parent) : QDialog(parent) { | ||||||
|  |     setWindowTitle(tr("Enter a hotkey")); | ||||||
|  |     auto* layout = new QVBoxLayout(this); | ||||||
|  |     key_sequence = new QKeySequenceEdit; | ||||||
|  |     layout->addWidget(key_sequence); | ||||||
|  |     auto* buttons = | ||||||
|  |         new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal); | ||||||
|  |     buttons->setCenterButtons(true); | ||||||
|  |     layout->addWidget(buttons); | ||||||
|  |     connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept); | ||||||
|  |     connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject); | ||||||
|  |     setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SequenceDialog::~SequenceDialog() = default; | ||||||
|  |  | ||||||
|  | QKeySequence SequenceDialog::GetSequence() { | ||||||
|  |     // Only the first key is returned. The other 3, if present, are ignored. | ||||||
|  |     return QKeySequence(key_sequence->keySequence()[0]); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool SequenceDialog::focusNextPrevChild(bool next) { | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SequenceDialog::closeEvent(QCloseEvent*) { | ||||||
|  |     reject(); | ||||||
|  | } | ||||||
							
								
								
									
										25
									
								
								src/citra_qt/util/sequence_dialog/sequence_dialog.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/citra_qt/util/sequence_dialog/sequence_dialog.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | // Copyright 2018 Citra Emulator Project | ||||||
|  | // Licensed under GPLv2 or any later version | ||||||
|  | // Refer to the license.txt file included. | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <memory> | ||||||
|  | #include <QDialog> | ||||||
|  |  | ||||||
|  | class QKeySequenceEdit; | ||||||
|  |  | ||||||
|  | class SequenceDialog : public QDialog { | ||||||
|  |     Q_OBJECT | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |     explicit SequenceDialog(QWidget* parent = nullptr); | ||||||
|  |     ~SequenceDialog(); | ||||||
|  |  | ||||||
|  |     QKeySequence GetSequence(); | ||||||
|  |     void closeEvent(QCloseEvent*) override; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     QKeySequenceEdit* key_sequence; | ||||||
|  |     bool focusNextPrevChild(bool next) override; | ||||||
|  | }; | ||||||
		Reference in New Issue
	
	Block a user