From 77a68e06072e2346b18c2003c1b8cd14a19083c9 Mon Sep 17 00:00:00 2001 From: Kloen Date: Mon, 7 Sep 2015 16:37:13 +0200 Subject: [PATCH] citra-qt: Add input settings configuration --- src/citra/config.cpp | 6 +- src/citra_qt/CMakeLists.txt | 2 + src/citra_qt/config.cpp | 8 +- src/citra_qt/config.h | 4 + src/citra_qt/config/inputs.cpp | 170 +++++++++++++++++++++++++++++++++ src/citra_qt/config/inputs.h | 56 +++++++++++ src/citra_qt/main.cpp | 8 ++ src/citra_qt/main.h | 1 + src/citra_qt/main.ui | 6 ++ src/core/settings.h | 18 ++-- 10 files changed, 263 insertions(+), 16 deletions(-) create mode 100644 src/citra_qt/config/inputs.cpp create mode 100644 src/citra_qt/config/inputs.h diff --git a/src/citra/config.cpp b/src/citra/config.cpp index 8a98bda87..01a879a23 100644 --- a/src/citra/config.cpp +++ b/src/citra/config.cpp @@ -41,12 +41,12 @@ bool Config::LoadINI(INIReader* config, const char* location, const std::string& } static const std::array defaults = { - GLFW_KEY_A, GLFW_KEY_S, GLFW_KEY_Z, GLFW_KEY_X, + GLFW_KEY_X, GLFW_KEY_Z, GLFW_KEY_S, GLFW_KEY_A, GLFW_KEY_Q, GLFW_KEY_W, GLFW_KEY_1, GLFW_KEY_2, - GLFW_KEY_M, GLFW_KEY_N, GLFW_KEY_B, + GLFW_KEY_I, GLFW_KEY_K, GLFW_KEY_J, GLFW_KEY_L, GLFW_KEY_T, GLFW_KEY_G, GLFW_KEY_F, GLFW_KEY_H, GLFW_KEY_UP, GLFW_KEY_DOWN, GLFW_KEY_LEFT, GLFW_KEY_RIGHT, - GLFW_KEY_I, GLFW_KEY_K, GLFW_KEY_J, GLFW_KEY_L + GLFW_KEY_M, GLFW_KEY_N, GLFW_KEY_B }; void Config::ReadValues() { diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index a82e8a85b..99cbb44c5 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -4,6 +4,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) set(SRCS config/controller_config.cpp config/controller_config_util.cpp + config/inputs.cpp config.cpp debugger/callstack.cpp debugger/disassembler.cpp @@ -28,6 +29,7 @@ set(SRCS set(HEADERS config/controller_config.h config/controller_config_util.h + config/inputs.h config.h debugger/callstack.h debugger/disassembler.h diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp index 1f4981ce1..5fcc88948 100644 --- a/src/citra_qt/config.cpp +++ b/src/citra_qt/config.cpp @@ -21,13 +21,13 @@ Config::Config() { Reload(); } -static const std::array defaults = { - Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X, +const std::array Config::defaults = { + Qt::Key_X, Qt::Key_Z, Qt::Key_S, Qt::Key_A, Qt::Key_Q, Qt::Key_W, Qt::Key_1, Qt::Key_2, - Qt::Key_M, Qt::Key_N, Qt::Key_B, + Qt::Key_I, Qt::Key_K, Qt::Key_J, Qt::Key_L, Qt::Key_T, Qt::Key_G, Qt::Key_F, Qt::Key_H, Qt::Key_Up, Qt::Key_Down, Qt::Key_Left, Qt::Key_Right, - Qt::Key_I, Qt::Key_K, Qt::Key_J, Qt::Key_L + Qt::Key_M, Qt::Key_N, Qt::Key_B }; void Config::ReadValues() { diff --git a/src/citra_qt/config.h b/src/citra_qt/config.h index dd0b2ef0b..7eb1554fc 100644 --- a/src/citra_qt/config.h +++ b/src/citra_qt/config.h @@ -4,8 +4,11 @@ #pragma once +#include #include +#include "core/settings.h" + class QSettings; class Config { @@ -20,4 +23,5 @@ public: void Reload(); void Save(); + static const std::array defaults; }; diff --git a/src/citra_qt/config/inputs.cpp b/src/citra_qt/config/inputs.cpp new file mode 100644 index 000000000..a3a7ffc41 --- /dev/null +++ b/src/citra_qt/config/inputs.cpp @@ -0,0 +1,170 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include +#include +#include +#include +#include + +#include "citra_qt/config.h" +#include "citra_qt/config/inputs.h" + +#include "common/common_funcs.h" +#include "common/logging/log.h" + +InputsDialog::InputsDialog(QWidget* parent) : QDialog(parent) { + // create a copy of the current settings + temp_settings = Settings::Values(Settings::values); + signal_mapper = new QSignalMapper(this); + + // create the QPushButtons + for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { + push_buttons[i] = new QPushButton(this); + push_buttons[i]->setCheckable(true); + push_buttons[i]->setDefault(false); + push_buttons[i]->setAutoDefault(false); + } + + static const std::string label_array[] = { + "Y:", "X:", "B:", "A:", + "L:", "R:", "ZL:", "ZR:", + "Left:", "Right:", "Up:", "Down:", + "Left:", "Right:", "Up:", "Down:", + "Left:", "Right:", "Up:", "Down:", + "Start:", "Select:", "Home:" + }; + + static const std::string group_names[] = { + "Face Buttons", "Shoulder Buttons", "C-Stick", + "Directional Pad", "Circle Pad", "System Buttons" + }; + + QGridLayout* grid = new QGridLayout(); + int id = 0; + for (int i = 0; i < ARRAY_SIZE(group_names); ++i) { + QGroupBox* group = new QGroupBox(tr(group_names[i].c_str())); + QGridLayout* box = new QGridLayout; + for (int x = 0; x <= (Settings::NativeInput::NUM_INPUTS / ARRAY_SIZE(group_names)); ++x) { + QLabel* label = new QLabel(tr(label_array[id].c_str())); + box->addWidget(label, (int) x / 2 * 2, (int) x % 2 * 2); + box->addWidget(push_buttons[id], (int) x / 2 * 2 + 1, (int) x % 2 * 2); + signal_mapper->setMapping(push_buttons[id], id); + connect(push_buttons[id], SIGNAL(clicked()), signal_mapper, SLOT(map())); + ++id; + if (id >= Settings::NativeInput::NUM_INPUTS) + break; + } + group->setLayout(box); + grid->addWidget(group, (int) i % 3, (int) i / 3 * 2); + } + + connect(signal_mapper, SIGNAL(mapped(int)), this, SLOT(ChangeValue(int))); + + // the button box that contains the restore default/ok/cancel buttons + QVBoxLayout* verticalLayout = new QVBoxLayout(); + QDialogButtonBox* buttonBox = new QDialogButtonBox(); + buttonBox->setOrientation(Qt::Horizontal); + buttonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok | QDialogButtonBox::RestoreDefaults); + + verticalLayout->addLayout(grid); + verticalLayout->addWidget(buttonBox); + + connect(buttonBox, SIGNAL(accepted()), this, SLOT(SaveSettings())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + + setLayout(verticalLayout); + setWindowTitle(tr("Input Settings")); + + // set up event handlers for the buttons + QPushButton* defaultButton = buttonBox->button(QDialogButtonBox::RestoreDefaults); + connect(defaultButton, SIGNAL(clicked()), this, SLOT(RestoreDefaultSettings())); + + // display current key settings + UpdateKeyLabels(); +} + +void InputsDialog::ChangeValue(int id) { + + if (current_button_id > -1) + push_buttons[current_button_id]->setChecked(false); + + if (current_button_id == id) { + push_buttons[current_button_id]->setChecked(false); + current_button_id = -1; + } else { + push_buttons[id]->setChecked(true); + current_button_id = id; + } +} + +void InputsDialog::UpdateValue(int key) { + + bool update = std::none_of(std::begin(Settings::NativeInput::All), std::end(Settings::NativeInput::All), + [&](Settings::NativeInput::Values val) { return key == temp_settings.input_mappings[val]; }); + + if (update) { + temp_settings.input_mappings[Settings::NativeInput::All[current_button_id]] = key; + push_buttons[current_button_id]->setChecked(false); + push_buttons[current_button_id]->setText(GetKeyName(temp_settings.input_mappings[Settings::NativeInput::All[current_button_id]])); + current_button_id = -1; + } +} + +void InputsDialog::UpdateKeyLabels() { + for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { + push_buttons[i]->setText(GetKeyName(temp_settings.input_mappings[Settings::NativeInput::All[i]])); + } +} + +QString InputsDialog::GetKeyName(int key_code) { + if (key_code == Qt::Key_Shift) + return tr("Shift"); + + if (key_code == Qt::Key_Control) + return tr("Ctrl"); + + if (key_code == Qt::Key_Alt) + return tr("Alt"); + + if (key_code == Qt::Key_Meta) + return tr("Meta"); + + return QKeySequence(key_code).toString(); +} + +void InputsDialog::RestoreDefaultSettings() { + // load the default button settings into temp_settings + for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { + temp_settings.input_mappings[Settings::NativeInput::All[i]] = Config::defaults[i].toInt(); + } + + // then display it + UpdateKeyLabels(); +} + +void InputsDialog::SaveSettings() { + Config config; + + // load the temporary settings into our real settings + for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { + Settings::values.input_mappings[Settings::NativeInput::All[i]] = + temp_settings.input_mappings[Settings::NativeInput::All[i]]; + } + + // then save it + config.Save(); + + // Close the dialog after save the bindings + accept(); +} + +void InputsDialog::keyPressEvent(QKeyEvent* key) { + if (current_button_id != -1 && key->key() != Qt::Key_Escape) + UpdateValue(key->key()); + else + QDialog::keyPressEvent(key); +} diff --git a/src/citra_qt/config/inputs.h b/src/citra_qt/config/inputs.h new file mode 100644 index 000000000..d283f87c3 --- /dev/null +++ b/src/citra_qt/config/inputs.h @@ -0,0 +1,56 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +#include +#include +#include +#include + +#include "core/settings.h" + +/// The input configuration dialog +class InputsDialog : public QDialog { + Q_OBJECT + +public: + InputsDialog(QWidget* parent = nullptr); + + /** + * Given a key code, return the key name. + * @note This function is conceptually similar to "QKeySequence(key_code).toString()", which however returns gibberish strings for modifier keys (e.g. Ctrl). Hence this function provides special cases for these keys. + */ + static QString GetKeyName(int key_code); + + void keyPressEvent(QKeyEvent* event) override; + +private: + /// Update QPushButton labels to reflect current button mapping. + void UpdateKeyLabels(); + + /// An array of all the QPushButtons for easy iteration over them + std::array push_buttons; + + /// Temporary settings used when configuration is changed but not saved yet + Settings::Values temp_settings; + + /// Map of all the QPushButtons signals + QSignalMapper* signal_mapper; + + /// Current QPushButton id, it's -1 as default value since it's an incorrect id, right ones are from 0 to 22. + int current_button_id = -1; + +private slots: + void SaveSettings(); + void RestoreDefaultSettings(); + + /// Set/Unset the QPushButton with the given id to allow it to modify his bind key. Discards previous selected button. + void ChangeValue(int id); + + /// Update the QPushButton & key binding of the current_button_id with the given key if it's possible (Unused and allowed key). + void UpdateValue(int key); +}; diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 01841b33c..b62bc15ab 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -15,6 +15,8 @@ #include "citra_qt/hotkeys.h" #include "citra_qt/main.h" +#include "citra_qt/config/inputs.h" + // Debugger #include "citra_qt/debugger/callstack.h" #include "citra_qt/debugger/disassembler.h" @@ -169,6 +171,7 @@ GMainWindow::GMainWindow() : emu_thread(nullptr) connect(ui.action_Use_Shader_JIT, SIGNAL(triggered(bool)), this, SLOT(SetShaderJITEnabled(bool))); connect(ui.action_Single_Window_Mode, SIGNAL(triggered(bool)), this, SLOT(ToggleWindowMode())); connect(ui.action_Hotkeys, SIGNAL(triggered()), this, SLOT(OnOpenHotkeysDialog())); + connect(ui.action_Inputs, SIGNAL(triggered()), this, SLOT(OnOpenInputsDialog())); connect(this, SIGNAL(EmulationStarting(EmuThread*)), disasmWidget, SLOT(OnEmulationStarting(EmuThread*))); connect(this, SIGNAL(EmulationStopping()), disasmWidget, SLOT(OnEmulationStopping())); @@ -418,6 +421,11 @@ void GMainWindow::SetShaderJITEnabled(bool enabled) { VideoCore::g_shader_jit_enabled = enabled; } +void GMainWindow::OnOpenInputsDialog() { + InputsDialog dialog(this); + dialog.exec(); +} + void GMainWindow::ToggleWindowMode() { if (ui.action_Single_Window_Mode->isChecked()) { // Render in the main window... diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h index 32523fded..2a835a30f 100644 --- a/src/citra_qt/main.h +++ b/src/citra_qt/main.h @@ -95,6 +95,7 @@ private slots: void OnDisplayTitleBars(bool); void SetHardwareRendererEnabled(bool); void SetShaderJITEnabled(bool); + void OnOpenInputsDialog(); void ToggleWindowMode(); private: diff --git a/src/citra_qt/main.ui b/src/citra_qt/main.ui index 1ba700a3a..a949e2463 100644 --- a/src/citra_qt/main.ui +++ b/src/citra_qt/main.ui @@ -75,6 +75,7 @@ + @@ -153,6 +154,11 @@ Configure &Hotkeys ... + + + Configure &Controls + + true diff --git a/src/core/settings.h b/src/core/settings.h index 0b05e5bee..a3a3c2ac7 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -11,29 +11,29 @@ namespace Settings { namespace NativeInput { enum Values { - A, B, X, Y, + Y, X, B, A, L, R, ZL, ZR, - START, SELECT, HOME, + CUP, CDOWN, CLEFT, CRIGHT, DUP, DDOWN, DLEFT, DRIGHT, SUP, SDOWN, SLEFT, SRIGHT, - CUP, CDOWN, CLEFT, CRIGHT, + START, SELECT, HOME, NUM_INPUTS }; static const std::array Mapping = {{ - "pad_a", "pad_b", "pad_x", "pad_y", + "pad_y", "pad_x", "pad_b", "pad_a", "pad_l", "pad_r", "pad_zl", "pad_zr", - "pad_start", "pad_select", "pad_home", + "pad_cup", "pad_cdown", "pad_cleft", "pad_cright", "pad_dup", "pad_ddown", "pad_dleft", "pad_dright", "pad_sup", "pad_sdown", "pad_sleft", "pad_sright", - "pad_cup", "pad_cdown", "pad_cleft", "pad_cright" + "pad_start", "pad_select", "pad_home" }}; static const std::array All = {{ - A, B, X, Y, + Y, X, B, A, L, R, ZL, ZR, - START, SELECT, HOME, + CUP, CDOWN, CLEFT, CRIGHT, DUP, DDOWN, DLEFT, DRIGHT, SUP, SDOWN, SLEFT, SRIGHT, - CUP, CDOWN, CLEFT, CRIGHT + START, SELECT, HOME }}; }