diff --git a/src/citra_qt/bootmanager.h b/src/citra_qt/bootmanager.h index af52f369b..e2dea262a 100644 --- a/src/citra_qt/bootmanager.h +++ b/src/citra_qt/bootmanager.h @@ -126,8 +126,6 @@ public: void mouseMoveEvent(QMouseEvent* event) override; void mouseReleaseEvent(QMouseEvent* event) override; - void ReloadSetKeymaps() override; - void OnClientAreaResized(unsigned width, unsigned height); void InitRenderTarget(); diff --git a/src/citra_qt/configure_input.cpp b/src/citra_qt/configure_input.cpp index 4163b35bc..96017f933 100644 --- a/src/citra_qt/configure_input.cpp +++ b/src/citra_qt/configure_input.cpp @@ -2,144 +2,161 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include #include -#include -#include "citra_qt/config.h" -#include "citra_qt/configure_input.h" -static QString getKeyName(Qt::Key key_code) { - switch (key_code) { - case Qt::Key_Shift: - return QObject::tr("Shift"); - case Qt::Key_Control: - return QObject::tr("Ctrl"); - case Qt::Key_Alt: - return QObject::tr("Alt"); - case Qt::Key_Meta: - case -1: - return ""; - default: - return QKeySequence(key_code).toString(); - } -} +#include "citra_qt/configure_input.h" +#include "citra_qt/keybinding_names.h" +#include "common/string_util.h" + +#include "input_core/devices/keyboard.h" +#include "input_core/input_core.h" ConfigureInput::ConfigureInput(QWidget* parent) - : QWidget(parent), ui(std::make_unique()), - timer(std::make_unique()) { + : QWidget(parent), ui(std::make_unique()) { ui->setupUi(this); + + // Initialize mapping of input enum to UI button. + qt_buttons = { + {std::make_pair(Settings::NativeInput::Values::A, ui->buttonA)}, + {std::make_pair(Settings::NativeInput::Values::B, ui->buttonB)}, + {std::make_pair(Settings::NativeInput::Values::X, ui->buttonX)}, + {std::make_pair(Settings::NativeInput::Values::Y, ui->buttonY)}, + {std::make_pair(Settings::NativeInput::Values::L, ui->buttonL)}, + {std::make_pair(Settings::NativeInput::Values::R, ui->buttonR)}, + {std::make_pair(Settings::NativeInput::Values::ZL, ui->buttonZL)}, + {std::make_pair(Settings::NativeInput::Values::ZR, ui->buttonZR)}, + {std::make_pair(Settings::NativeInput::Values::START, ui->buttonStart)}, + {std::make_pair(Settings::NativeInput::Values::SELECT, ui->buttonSelect)}, + {std::make_pair(Settings::NativeInput::Values::HOME, ui->buttonHome)}, + {std::make_pair(Settings::NativeInput::Values::DUP, ui->buttonDpadUp)}, + {std::make_pair(Settings::NativeInput::Values::DDOWN, ui->buttonDpadDown)}, + {std::make_pair(Settings::NativeInput::Values::DLEFT, ui->buttonDpadLeft)}, + {std::make_pair(Settings::NativeInput::Values::DRIGHT, ui->buttonDpadRight)}, + {std::make_pair(Settings::NativeInput::Values::CUP, ui->buttonCStickUp)}, + {std::make_pair(Settings::NativeInput::Values::CDOWN, ui->buttonCStickDown)}, + {std::make_pair(Settings::NativeInput::Values::CLEFT, ui->buttonCStickLeft)}, + {std::make_pair(Settings::NativeInput::Values::CRIGHT, ui->buttonCStickRight)}, + {std::make_pair(Settings::NativeInput::Values::CIRCLE_UP, ui->buttonCircleUp)}, + {std::make_pair(Settings::NativeInput::Values::CIRCLE_DOWN, ui->buttonCircleDown)}, + {std::make_pair(Settings::NativeInput::Values::CIRCLE_LEFT, ui->buttonCircleLeft)}, + {std::make_pair(Settings::NativeInput::Values::CIRCLE_RIGHT, ui->buttonCircleRight)}}; + + // Attach handle click method to each button click. + for (const auto& entry : qt_buttons) { + connect(entry.second, SIGNAL(released()), this, SLOT(handleClick())); + } + connect(ui->buttonCircleMod, SIGNAL(released()), this, SLOT(handleClick())); + connect(ui->buttonRestoreDefaults, SIGNAL(released()), this, SLOT(restoreDefaults())); + 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}, - }; - - 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); }); - } - //connect(ui->buttonCircleMod, SIGNAL(released()), this, SLOT(handleClick())); - connect(ui->buttonRestoreDefaults, &QPushButton::released, [this]() { restoreDefaults(); }); - - timer->setSingleShot(true); - connect(timer.get(), &QTimer::timeout, [this]() { - releaseKeyboard(); - releaseMouse(); - current_input_id = boost::none; - updateButtonLabels(); - }); - - this->loadConfiguration(); + this->setConfiguration(); } -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]); - } - 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]); - } - updateButtonLabels(); -} - -void ConfigureInput::restoreDefaults() { - for (const auto& input_id : Settings::NativeInput::All) { - const size_t index = static_cast(input_id); - key_map[input_id] = static_cast(Config::defaults[index].toInt()); - } - updateButtonLabels(); - applyConfiguration(); -} - -void ConfigureInput::updateButtonLabels() { - for (const auto& input_id : Settings::NativeInput::All) { - button_map[input_id]->setText(getKeyName(key_map[input_id])); - } -} - -void ConfigureInput::handleClick(Settings::NativeInput::Values input_id) { - QPushButton* button = button_map[input_id]; - button->setText(tr("[press key]")); - button->setFocus(); - - current_input_id = input_id; - +void ConfigureInput::handleClick() { + QPushButton* sender = qobject_cast(QObject::sender()); + previous_mapping = sender->text(); + sender->setText(tr("[waiting]")); + sender->setFocus(); grabKeyboard(); grabMouse(); - timer->start(5000); // Cancel after 5 seconds + changing_button = sender; + auto update = []() { QCoreApplication::processEvents(); }; + auto input_device = InputCore::DetectInput(5000, update); + + setKey(input_device); } void ConfigureInput::keyPressEvent(QKeyEvent* event) { - releaseKeyboard(); - releaseMouse(); - - if (!current_input_id || !event) + if (!changing_button) + return; + if (!event || event->key() == Qt::Key_unknown) return; - if (event->key() != Qt::Key_Escape) - setInput(*current_input_id, static_cast(event->key())); - - updateButtonLabels(); - current_input_id = boost::none; - timer->stop(); + auto keyboard = InputCore::GetKeyboard(); + KeyboardKey param = + KeyboardKey(event->key(), QKeySequence(event->key()).toString().toStdString()); + keyboard->KeyPressed(param); } -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; +void ConfigureInput::applyConfiguration() { + for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { + Settings::values.input_mappings[Settings::NativeInput::All[i]] = + button_mapping[qt_buttons[Settings::NativeInput::Values(i)]]; } - - key_map[input_id] = key_pressed; + Settings::values.pad_circle_modifier = button_mapping[ui->buttonCircleMod]; + Settings::Apply(); +} + +void ConfigureInput::setConfiguration() { + for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { + Settings::InputDeviceMapping mapping = Settings::values.input_mappings[i]; + button_mapping[qt_buttons[Settings::NativeInput::Values(i)]] = mapping; + + qt_buttons[Settings::NativeInput::Values(i)]->setText(getKeyName(mapping)); + } + button_mapping[ui->buttonCircleMod] = Settings::values.pad_circle_modifier; + ui->buttonCircleMod->setText(getKeyName(Settings::values.pad_circle_modifier)); +} + +void ConfigureInput::setKey(Settings::InputDeviceMapping keyPressed) { + if (keyPressed.key == -1 || keyPressed.key == Qt::Key_Escape) + changing_button->setText(previous_mapping); + else { + changing_button->setText(getKeyName(keyPressed)); + button_mapping[changing_button] = keyPressed; + removeDuplicates(keyPressed); + } + releaseKeyboard(); + releaseMouse(); + changing_button = nullptr; + previous_mapping = nullptr; +} + +QString ConfigureInput::getKeyName(Settings::InputDeviceMapping mapping) const { + if (mapping.key == -1) + return ""; + if (mapping.device == Settings::Device::Gamepad) { + if (KeyBindingNames::sdl_gamepad_names.size() > mapping.key && mapping.key >= 0) + return KeyBindingNames::sdl_gamepad_names[mapping.key]; + else + return ""; + } + if (mapping.key == Qt::Key_Shift) + return tr("Shift"); + if (mapping.key == Qt::Key_Control) + return tr("Ctrl"); + if (mapping.key == Qt::Key_Alt) + return tr("Alt"); + if (mapping.key == Qt::Key_Meta) + return ""; + if (mapping.key < 0) + return ""; + + return QKeySequence(mapping.key).toString(); +} + +void ConfigureInput::removeDuplicates(const Settings::InputDeviceMapping newValue) { + for (auto& entry : button_mapping) { + if (changing_button != entry.first) { + if (newValue == entry.second && newValue.key == entry.second.key) { + entry.first->setText(""); + entry.second = Settings::InputDeviceMapping(); + } + } + } +} + +void ConfigureInput::restoreDefaults() { + for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { + Settings::InputDeviceMapping mapping = + Settings::InputDeviceMapping(Config::defaults[i].toInt()); + button_mapping[qt_buttons[Settings::NativeInput::Values(i)]] = mapping; + const QString keyValue = + getKeyName(Settings::InputDeviceMapping(Config::defaults[i].toInt())); + qt_buttons[Settings::NativeInput::Values(i)]->setText(keyValue); + } + button_mapping[ui->buttonCircleMod] = Settings::InputDeviceMapping(Qt::Key_F); + ui->buttonCircleMod->setText(getKeyName(Settings::InputDeviceMapping(Qt::Key_F))); } diff --git a/src/citra_qt/configure_input.h b/src/citra_qt/configure_input.h index bc343db83..cedd6f532 100644 --- a/src/citra_qt/configure_input.h +++ b/src/citra_qt/configure_input.h @@ -3,17 +3,17 @@ // Refer to the license.txt file included. #pragma once - #include #include #include -#include +#include +#include "citra_qt/config.h" #include "core/settings.h" +#include "input_core/devices/device.h" #include "ui_configure_input.h" class QPushButton; class QString; -class QTimer; namespace Ui { class ConfigureInput; @@ -30,28 +30,31 @@ public: private: std::unique_ptr ui; + std::map qt_buttons; + std::map button_mapping; + QPushButton* changing_button = nullptr; ///< button currently waiting for key press. + QString previous_mapping; - /// This input is currently awaiting configuration. - /// (i.e.: its corresponding QPushButton has been pressed.) - boost::optional current_input_id; - std::unique_ptr timer; + /// Load configuration settings into button text + void setConfiguration(); - /// 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; + /// Check all inputs for duplicate keys. Clears out any other button with the same value as this + /// button's new value. + void removeDuplicates(const Settings::InputDeviceMapping newValue); + + /// Handle keykoard key press event for input tab when a button is 'waiting'. + void keyPressEvent(QKeyEvent* event) override; + + /// Convert key ASCII value to its' letter/name + QString getKeyName(Settings::InputDeviceMapping mapping) const; + + /// Set button text to name of key pressed. + void setKey(Settings::InputDeviceMapping keyPressed); + +private slots: + /// Event handler for all button released() event. + void handleClick(); - /// Load configuration settings. - void loadConfiguration(); /// Restore all buttons to their default values. void restoreDefaults(); - /// 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); - /// 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); };