diff --git a/src/citra_qt/configure_input.cpp b/src/citra_qt/configure_input.cpp index 8846a68b2..4a14757ad 100644 --- a/src/citra_qt/configure_input.cpp +++ b/src/citra_qt/configure_input.cpp @@ -2,13 +2,21 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include #include #include #include "citra_qt/config.h" #include "citra_qt/configure_input.h" +#include "common/param_package.h" +#include "input_common/main.h" -static QString getKeyName(Qt::Key key_code) { +const std::array + ConfigureInput::analog_sub_buttons{{ + "up", "down", "left", "right", "modifier", + }}; + +static QString getKeyName(int key_code) { switch (key_code) { case Qt::Key_Shift: return QObject::tr("Shift"); @@ -23,6 +31,20 @@ static QString getKeyName(Qt::Key key_code) { } } +static void SetButtonKey(int key, Common::ParamPackage& button_param) { + button_param = Common::ParamPackage{InputCommon::GenerateKeyboardParam(key)}; +} + +static void SetAnalogKey(int key, Common::ParamPackage& analog_param, + const std::string& button_name) { + if (analog_param.Get("engine", "") != "analog_from_button") { + analog_param = { + {"engine", "analog_from_button"}, {"modifier_scale", "0.5"}, + }; + } + analog_param.Set(button_name, InputCommon::GenerateKeyboardParam(key)); +} + ConfigureInput::ConfigureInput(QWidget* parent) : QWidget(parent), ui(std::make_unique()), timer(std::make_unique()) { @@ -31,36 +53,38 @@ ConfigureInput::ConfigureInput(QWidget* parent) setFocusPolicy(Qt::ClickFocus); button_map = { - {Settings::NativeInput::Values::A, ui->buttonA}, - {Settings::NativeInput::Values::B, ui->buttonB}, - {Settings::NativeInput::Values::X, ui->buttonX}, - {Settings::NativeInput::Values::Y, ui->buttonY}, - {Settings::NativeInput::Values::L, ui->buttonL}, - {Settings::NativeInput::Values::R, ui->buttonR}, - {Settings::NativeInput::Values::ZL, ui->buttonZL}, - {Settings::NativeInput::Values::ZR, ui->buttonZR}, - {Settings::NativeInput::Values::START, ui->buttonStart}, - {Settings::NativeInput::Values::SELECT, ui->buttonSelect}, - {Settings::NativeInput::Values::HOME, ui->buttonHome}, - {Settings::NativeInput::Values::DUP, ui->buttonDpadUp}, - {Settings::NativeInput::Values::DDOWN, ui->buttonDpadDown}, - {Settings::NativeInput::Values::DLEFT, ui->buttonDpadLeft}, - {Settings::NativeInput::Values::DRIGHT, ui->buttonDpadRight}, - {Settings::NativeInput::Values::CUP, ui->buttonCStickUp}, - {Settings::NativeInput::Values::CDOWN, ui->buttonCStickDown}, - {Settings::NativeInput::Values::CLEFT, ui->buttonCStickLeft}, - {Settings::NativeInput::Values::CRIGHT, ui->buttonCStickRight}, - {Settings::NativeInput::Values::CIRCLE_UP, ui->buttonCircleUp}, - {Settings::NativeInput::Values::CIRCLE_DOWN, ui->buttonCircleDown}, - {Settings::NativeInput::Values::CIRCLE_LEFT, ui->buttonCircleLeft}, - {Settings::NativeInput::Values::CIRCLE_RIGHT, ui->buttonCircleRight}, - {Settings::NativeInput::Values::CIRCLE_MODIFIER, ui->buttonCircleMod}, + ui->buttonA, ui->buttonB, ui->buttonX, ui->buttonY, ui->buttonDpadUp, + ui->buttonDpadDown, ui->buttonDpadLeft, ui->buttonDpadRight, ui->buttonL, ui->buttonR, + ui->buttonStart, ui->buttonSelect, ui->buttonZL, ui->buttonZR, ui->buttonHome, }; - for (const auto& entry : button_map) { - const Settings::NativeInput::Values input_id = entry.first; - connect(entry.second, &QPushButton::released, - [this, input_id]() { handleClick(input_id); }); + analog_map = {{ + { + ui->buttonCircleUp, ui->buttonCircleDown, ui->buttonCircleLeft, ui->buttonCircleRight, + ui->buttonCircleMod, + }, + { + ui->buttonCStickUp, ui->buttonCStickDown, ui->buttonCStickLeft, ui->buttonCStickRight, + nullptr, + }, + }}; + + for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) { + if (button_map[button_id]) + connect(button_map[button_id], &QPushButton::released, [=]() { + handleClick(button_map[button_id], + [=](int key) { SetButtonKey(key, buttons_param[button_id]); }); + }); + } + + for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) { + for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) { + connect(analog_map[analog_id][sub_button_id], &QPushButton::released, [=]() { + handleClick(analog_map[analog_id][sub_button_id], [=](int key) { + SetAnalogKey(key, analogs_param[analog_id], analog_sub_buttons[sub_button_id]); + }); + }); + } } connect(ui->buttonRestoreDefaults, &QPushButton::released, [this]() { restoreDefaults(); }); @@ -69,43 +93,93 @@ ConfigureInput::ConfigureInput(QWidget* parent) connect(timer.get(), &QTimer::timeout, [this]() { releaseKeyboard(); releaseMouse(); - current_input_id = boost::none; + key_setter = boost::none; updateButtonLabels(); }); this->loadConfiguration(); + + // TODO(wwylele): enable these when the input emulation for them is implemented + ui->buttonZL->setEnabled(false); + ui->buttonZR->setEnabled(false); + ui->buttonHome->setEnabled(false); + ui->buttonCStickUp->setEnabled(false); + ui->buttonCStickDown->setEnabled(false); + ui->buttonCStickLeft->setEnabled(false); + ui->buttonCStickRight->setEnabled(false); } void ConfigureInput::applyConfiguration() { - for (const auto& input_id : Settings::NativeInput::All) { - const size_t index = static_cast(input_id); - Settings::values.input_mappings[index] = static_cast(key_map[input_id]); - } + std::transform(buttons_param.begin(), buttons_param.end(), Settings::values.buttons.begin(), + [](const Common::ParamPackage& param) { return param.Serialize(); }); + std::transform(analogs_param.begin(), analogs_param.end(), Settings::values.analogs.begin(), + [](const Common::ParamPackage& param) { return param.Serialize(); }); + Settings::Apply(); } void ConfigureInput::loadConfiguration() { - for (const auto& input_id : Settings::NativeInput::All) { - const size_t index = static_cast(input_id); - key_map[input_id] = static_cast(Settings::values.input_mappings[index]); - } + std::transform(Settings::values.buttons.begin(), Settings::values.buttons.end(), + buttons_param.begin(), + [](const std::string& str) { return Common::ParamPackage(str); }); + std::transform(Settings::values.analogs.begin(), Settings::values.analogs.end(), + analogs_param.begin(), + [](const std::string& str) { return Common::ParamPackage(str); }); updateButtonLabels(); } -void ConfigureInput::restoreDefaults() {} +void ConfigureInput::restoreDefaults() { + for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) { + SetButtonKey(Config::default_buttons[button_id], buttons_param[button_id]); + } + + for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) { + for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) { + SetAnalogKey(Config::default_analogs[analog_id][sub_button_id], + analogs_param[analog_id], analog_sub_buttons[sub_button_id]); + } + } + updateButtonLabels(); + applyConfiguration(); +} void ConfigureInput::updateButtonLabels() { - for (const auto& input_id : Settings::NativeInput::All) { - button_map[input_id]->setText(getKeyName(key_map[input_id])); + QString non_keyboard(tr("[non-keyboard]")); + + auto KeyToText = [&non_keyboard](const Common::ParamPackage& param) { + if (param.Get("engine", "") != "keyboard") { + return non_keyboard; + } else { + return getKeyName(param.Get("code", 0)); + } + }; + + for (int button = 0; button < Settings::NativeButton::NumButtons; button++) { + button_map[button]->setText(KeyToText(buttons_param[button])); + } + + for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) { + if (analogs_param[analog_id].Get("engine", "") != "analog_from_button") { + for (QPushButton* button : analog_map[analog_id]) { + if (button) + button->setText(non_keyboard); + } + } else { + for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) { + Common::ParamPackage param( + analogs_param[analog_id].Get(analog_sub_buttons[sub_button_id], "")); + if (analog_map[analog_id][sub_button_id]) + analog_map[analog_id][sub_button_id]->setText(KeyToText(param)); + } + } } } -void ConfigureInput::handleClick(Settings::NativeInput::Values input_id) { - QPushButton* button = button_map[input_id]; +void ConfigureInput::handleClick(QPushButton* button, std::function new_key_setter) { button->setText(tr("[press key]")); button->setFocus(); - current_input_id = input_id; + key_setter = new_key_setter; grabKeyboard(); grabMouse(); @@ -116,23 +190,13 @@ void ConfigureInput::keyPressEvent(QKeyEvent* event) { releaseKeyboard(); releaseMouse(); - if (!current_input_id || !event) + if (!key_setter || !event) return; if (event->key() != Qt::Key_Escape) - setInput(*current_input_id, static_cast(event->key())); + (*key_setter)(event->key()); updateButtonLabels(); - current_input_id = boost::none; + key_setter = boost::none; timer->stop(); } - -void ConfigureInput::setInput(Settings::NativeInput::Values input_id, Qt::Key key_pressed) { - // Remove duplicates - for (auto& pair : key_map) { - if (pair.second == key_pressed) - pair.second = Qt::Key_unknown; - } - - key_map[input_id] = key_pressed; -} diff --git a/src/citra_qt/configure_input.h b/src/citra_qt/configure_input.h index bc343db83..c950fbcb4 100644 --- a/src/citra_qt/configure_input.h +++ b/src/citra_qt/configure_input.h @@ -4,10 +4,14 @@ #pragma once +#include +#include #include +#include #include #include #include +#include "common/param_package.h" #include "core/settings.h" #include "ui_configure_input.h" @@ -31,15 +35,25 @@ public: private: std::unique_ptr ui; - /// This input is currently awaiting configuration. - /// (i.e.: its corresponding QPushButton has been pressed.) - boost::optional current_input_id; std::unique_ptr timer; - /// Each input is represented by a QPushButton. - std::map button_map; - /// Each input is configured to respond to the press of a Qt::Key. - std::map key_map; + /// This will be the the setting function when an input is awaiting configuration. + boost::optional> key_setter; + + std::array buttons_param; + std::array analogs_param; + + static constexpr int ANALOG_SUB_BUTTONS_NUM = 5; + + /// Each button input is represented by a QPushButton. + std::array button_map; + + /// Each analog input is represented by five QPushButtons which represents up, down, left, right + /// and modifier + std::array, Settings::NativeAnalog::NumAnalogs> + analog_map; + + static const std::array analog_sub_buttons; /// Load configuration settings. void loadConfiguration(); @@ -48,10 +62,8 @@ private: /// Update UI to reflect current configuration. void updateButtonLabels(); - /// Called when the button corresponding to input_id was pressed. - void handleClick(Settings::NativeInput::Values input_id); + /// Called when the button was pressed. + void handleClick(QPushButton* button, std::function new_key_setter); /// Handle key press events. void keyPressEvent(QKeyEvent* event) override; - /// Configure input input_id to respond to key key_pressed. - void setInput(Settings::NativeInput::Values input_id, Qt::Key key_pressed); };