From f1aec256d754ac47d74363eb3f2abfa3db414b12 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Thu, 1 Nov 2018 22:06:48 -0400 Subject: [PATCH] configure_input: Add support for multiplayer and controller types This moves the actual button configuration to a separate dialog and only has the enabled and type controls in the tab. --- src/yuzu/configuration/configure_input.cpp | 438 +++----- src/yuzu/configuration/configure_input.h | 53 +- src/yuzu/configuration/configure_input.ui | 1080 ++++++++------------ 3 files changed, 549 insertions(+), 1022 deletions(-) diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index 42a7beac6..9ae9827fe 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -9,334 +9,164 @@ #include #include #include "common/param_package.h" +#include "configuration/configure_touchscreen_advanced.h" +#include "core/core.h" #include "input_common/main.h" +#include "ui_configure_input.h" +#include "ui_configure_input_player.h" +#include "ui_configure_mouse_advanced.h" +#include "ui_configure_touchscreen_advanced.h" #include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_input.h" - -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"); - case Qt::Key_Control: - return QObject::tr("Ctrl"); - case Qt::Key_Alt: - return QObject::tr("Alt"); - case Qt::Key_Meta: - return ""; - default: - return QKeySequence(key_code).toString(); - } -} - -static void SetAnalogButton(const Common::ParamPackage& input_param, - 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, input_param.Serialize()); -} - -static QString ButtonToText(const Common::ParamPackage& param) { - if (!param.Has("engine")) { - return QObject::tr("[not set]"); - } else if (param.Get("engine", "") == "keyboard") { - return getKeyName(param.Get("code", 0)); - } else if (param.Get("engine", "") == "sdl") { - if (param.Has("hat")) { - return QString(QObject::tr("Hat %1 %2")) - .arg(param.Get("hat", "").c_str(), param.Get("direction", "").c_str()); - } - if (param.Has("axis")) { - return QString(QObject::tr("Axis %1%2")) - .arg(param.Get("axis", "").c_str(), param.Get("direction", "").c_str()); - } - if (param.Has("button")) { - return QString(QObject::tr("Button %1")).arg(param.Get("button", "").c_str()); - } - return QString(); - } else { - return QObject::tr("[unknown]"); - } -}; - -static QString AnalogToText(const Common::ParamPackage& param, const std::string& dir) { - if (!param.Has("engine")) { - return QObject::tr("[not set]"); - } else if (param.Get("engine", "") == "analog_from_button") { - return ButtonToText(Common::ParamPackage{param.Get(dir, "")}); - } else if (param.Get("engine", "") == "sdl") { - if (dir == "modifier") { - return QString(QObject::tr("[unused]")); - } - - if (dir == "left" || dir == "right") { - return QString(QObject::tr("Axis %1")).arg(param.Get("axis_x", "").c_str()); - } else if (dir == "up" || dir == "down") { - return QString(QObject::tr("Axis %1")).arg(param.Get("axis_y", "").c_str()); - } - return QString(); - } else { - return QObject::tr("[unknown]"); - } -}; +#include "yuzu/configuration/configure_input_player.h" +#include "yuzu/configuration/configure_mouse_advanced.h" ConfigureInput::ConfigureInput(QWidget* parent) - : QWidget(parent), ui(std::make_unique()), - timeout_timer(std::make_unique()), poll_timer(std::make_unique()) { - + : QWidget(parent), ui(std::make_unique()) { ui->setupUi(this); - setFocusPolicy(Qt::ClickFocus); - button_map = { - ui->buttonA, ui->buttonB, ui->buttonX, ui->buttonY, - ui->buttonLStick, ui->buttonRStick, ui->buttonL, ui->buttonR, - ui->buttonZL, ui->buttonZR, ui->buttonPlus, ui->buttonMinus, - ui->buttonDpadLeft, ui->buttonDpadUp, ui->buttonDpadRight, ui->buttonDpadDown, - ui->buttonLStickLeft, ui->buttonLStickUp, ui->buttonLStickRight, ui->buttonLStickDown, - ui->buttonRStickLeft, ui->buttonRStickUp, ui->buttonRStickRight, ui->buttonRStickDown, - ui->buttonSL, ui->buttonSR, ui->buttonHome, ui->buttonScreenshot, + players_enabled = { + ui->player1_checkbox, ui->player2_checkbox, ui->player3_checkbox, ui->player4_checkbox, + ui->player5_checkbox, ui->player6_checkbox, ui->player7_checkbox, ui->player8_checkbox, }; - analog_map_buttons = {{ - { - ui->buttonLStickUp, - ui->buttonLStickDown, - ui->buttonLStickLeft, - ui->buttonLStickRight, - ui->buttonLStickMod, - }, - { - ui->buttonRStickUp, - ui->buttonRStickDown, - ui->buttonRStickLeft, - ui->buttonRStickRight, - ui->buttonRStickMod, - }, - }}; + player_controller = { + ui->player1_combobox, ui->player2_combobox, ui->player3_combobox, ui->player4_combobox, + ui->player5_combobox, ui->player6_combobox, ui->player7_combobox, ui->player8_combobox, + }; - analog_map_stick = {ui->buttonLStickAnalog, ui->buttonRStickAnalog}; + player_configure = { + ui->player1_configure, ui->player2_configure, ui->player3_configure, ui->player4_configure, + ui->player5_configure, ui->player6_configure, ui->player7_configure, ui->player8_configure, + }; - for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) { - if (!button_map[button_id]) - continue; - button_map[button_id]->setContextMenuPolicy(Qt::CustomContextMenu); - connect(button_map[button_id], &QPushButton::released, [=]() { - handleClick( - button_map[button_id], - [=](const Common::ParamPackage& params) { buttons_param[button_id] = params; }, - InputCommon::Polling::DeviceType::Button); - }); - connect(button_map[button_id], &QPushButton::customContextMenuRequested, - [=](const QPoint& menu_location) { - QMenu context_menu; - context_menu.addAction(tr("Clear"), [&] { - buttons_param[button_id].Clear(); - button_map[button_id]->setText(tr("[not set]")); - }); - context_menu.addAction(tr("Restore Default"), [&] { - buttons_param[button_id] = Common::ParamPackage{ - InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])}; - button_map[button_id]->setText(ButtonToText(buttons_param[button_id])); - }); - context_menu.exec(button_map[button_id]->mapToGlobal(menu_location)); - }); + for (auto* controller_box : player_controller) { + controller_box->addItems( + {"Pro Controller", "Dual Joycons", "Single Right Joycon", "Single Left Joycon"}); } - 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++) { - if (!analog_map_buttons[analog_id][sub_button_id]) - continue; - analog_map_buttons[analog_id][sub_button_id]->setContextMenuPolicy( - Qt::CustomContextMenu); - connect(analog_map_buttons[analog_id][sub_button_id], &QPushButton::released, [=]() { - handleClick(analog_map_buttons[analog_id][sub_button_id], - [=](const Common::ParamPackage& params) { - SetAnalogButton(params, analogs_param[analog_id], - analog_sub_buttons[sub_button_id]); - }, - InputCommon::Polling::DeviceType::Button); - }); - connect(analog_map_buttons[analog_id][sub_button_id], - &QPushButton::customContextMenuRequested, [=](const QPoint& menu_location) { - QMenu context_menu; - context_menu.addAction(tr("Clear"), [&] { - analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]); - analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]")); - }); - context_menu.addAction(tr("Restore Default"), [&] { - Common::ParamPackage params{InputCommon::GenerateKeyboardParam( - Config::default_analogs[analog_id][sub_button_id])}; - SetAnalogButton(params, analogs_param[analog_id], - analog_sub_buttons[sub_button_id]); - analog_map_buttons[analog_id][sub_button_id]->setText(AnalogToText( - analogs_param[analog_id], analog_sub_buttons[sub_button_id])); - }); - context_menu.exec(analog_map_buttons[analog_id][sub_button_id]->mapToGlobal( - menu_location)); - }); - } - connect(analog_map_stick[analog_id], &QPushButton::released, [=]() { - QMessageBox::information(this, tr("Information"), - tr("After pressing OK, first move your joystick horizontally, " - "and then vertically.")); - handleClick( - analog_map_stick[analog_id], - [=](const Common::ParamPackage& params) { analogs_param[analog_id] = params; }, - InputCommon::Polling::DeviceType::Analog); - }); - } - - connect(ui->buttonClearAll, &QPushButton::released, [this] { ClearAll(); }); - connect(ui->buttonRestoreDefaults, &QPushButton::released, [this]() { restoreDefaults(); }); - - timeout_timer->setSingleShot(true); - connect(timeout_timer.get(), &QTimer::timeout, [this]() { setPollingResult({}, true); }); - - connect(poll_timer.get(), &QTimer::timeout, [this]() { - Common::ParamPackage params; - for (auto& poller : device_pollers) { - params = poller->GetNextInput(); - if (params.Has("engine")) { - setPollingResult(params, false); - return; - } - } - }); - this->loadConfiguration(); + updateUIEnabled(); - // TODO(wwylele): enable this when we actually emulate it - ui->buttonHome->setEnabled(false); + connect(ui->restore_defaults_button, &QPushButton::pressed, this, + &ConfigureInput::restoreDefaults); + + for (auto* enabled : players_enabled) + connect(enabled, &QCheckBox::stateChanged, this, &ConfigureInput::updateUIEnabled); + connect(ui->use_docked_mode, &QCheckBox::stateChanged, this, &ConfigureInput::updateUIEnabled); + connect(ui->handheld_connected, &QCheckBox::stateChanged, this, + &ConfigureInput::updateUIEnabled); + connect(ui->mouse_enabled, &QCheckBox::stateChanged, this, &ConfigureInput::updateUIEnabled); + connect(ui->keyboard_enabled, &QCheckBox::stateChanged, this, &ConfigureInput::updateUIEnabled); + connect(ui->debug_enabled, &QCheckBox::stateChanged, this, &ConfigureInput::updateUIEnabled); + connect(ui->touchscreen_enabled, &QCheckBox::stateChanged, this, + &ConfigureInput::updateUIEnabled); + + for (std::size_t i = 0; i < player_configure.size(); ++i) { + connect(player_configure[i], &QPushButton::pressed, this, + [this, i]() { CallConfigureDialog(i, false); }); + } + + connect(ui->handheld_configure, &QPushButton::pressed, this, + [this]() { CallConfigureDialog(8, false); }); + + connect(ui->debug_configure, &QPushButton::pressed, this, + [this]() { CallConfigureDialog(9, true); }); + + connect(ui->mouse_advanced, &QPushButton::pressed, this, + [this]() { CallConfigureDialog(); }); + + connect(ui->touchscreen_advanced, &QPushButton::pressed, this, + [this]() { CallConfigureDialog(); }); + + ui->use_docked_mode->setEnabled(!Core::System::GetInstance().IsPoweredOn()); +} + +template +void ConfigureInput::CallConfigureDialog(Args... args) { + this->applyConfiguration(); + Dialog dialog(this, args...); + + const auto res = dialog.exec(); + if (res == QDialog::Accepted) { + dialog.applyConfiguration(); + } } void ConfigureInput::applyConfiguration() { - 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(); }); + for (std::size_t i = 0; i < 8; ++i) { + Settings::values.players[i].connected = players_enabled[i]->isChecked(); + Settings::values.players[i].type = + static_cast(player_controller[i]->currentIndex()); + } + + Settings::values.use_docked_mode = ui->use_docked_mode->isChecked(); + Settings::values.players[8].connected = ui->handheld_connected->isChecked(); + Settings::values.debug_pad_enabled = ui->debug_enabled->isChecked(); + Settings::values.mouse_enabled = ui->mouse_enabled->isChecked(); + Settings::values.keyboard_enabled = ui->keyboard_enabled->isChecked(); + Settings::values.touchscreen.enabled = ui->touchscreen_enabled->isChecked(); +} + +void ConfigureInput::updateUIEnabled() { + for (std::size_t i = 0; i < 8; ++i) { + const auto enabled = players_enabled[i]->checkState() == Qt::Checked; + + player_controller[i]->setEnabled(enabled); + player_configure[i]->setEnabled(enabled); + } + + bool hit_disabled = false; + for (auto* player : players_enabled) { + if (hit_disabled) + player->setDisabled(true); + else + player->setEnabled(true); + if (!player->isChecked()) + hit_disabled = true; + } + + ui->handheld_connected->setEnabled(!ui->use_docked_mode->isChecked()); + ui->handheld_configure->setEnabled(ui->handheld_connected->isChecked() && + !ui->use_docked_mode->isChecked()); + ui->mouse_advanced->setEnabled(ui->mouse_enabled->isChecked()); + ui->debug_configure->setEnabled(ui->debug_enabled->isChecked()); + ui->touchscreen_advanced->setEnabled(ui->touchscreen_enabled->isChecked()); } void ConfigureInput::loadConfiguration() { - 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(); + std::stable_partition(Settings::values.players.begin(), Settings::values.players.end(), + [](const auto& player) { return player.connected; }); + + for (std::size_t i = 0; i < 8; ++i) { + players_enabled[i]->setChecked(Settings::values.players[i].connected); + player_controller[i]->setCurrentIndex(static_cast(Settings::values.players[i].type)); + } + + ui->use_docked_mode->setChecked(Settings::values.use_docked_mode); + ui->handheld_connected->setChecked(Settings::values.players[8].connected); + ui->debug_enabled->setChecked(Settings::values.debug_pad_enabled); + ui->mouse_enabled->setChecked(Settings::values.mouse_enabled); + ui->keyboard_enabled->setChecked(Settings::values.keyboard_enabled); + ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled); + + updateUIEnabled(); } void ConfigureInput::restoreDefaults() { - for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) { - buttons_param[button_id] = Common::ParamPackage{ - InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])}; + players_enabled[0]->setCheckState(Qt::Checked); + player_controller[0]->setCurrentIndex(1); + + for (std::size_t i = 1; i < 8; ++i) { + players_enabled[i]->setCheckState(Qt::Unchecked); + player_controller[i]->setCurrentIndex(0); } - 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++) { - Common::ParamPackage params{InputCommon::GenerateKeyboardParam( - Config::default_analogs[analog_id][sub_button_id])}; - SetAnalogButton(params, analogs_param[analog_id], analog_sub_buttons[sub_button_id]); - } - } - updateButtonLabels(); -} - -void ConfigureInput::ClearAll() { - for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) { - if (button_map[button_id] && button_map[button_id]->isEnabled()) - buttons_param[button_id].Clear(); - } - 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++) { - if (analog_map_buttons[analog_id][sub_button_id] && - analog_map_buttons[analog_id][sub_button_id]->isEnabled()) - analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]); - } - } - updateButtonLabels(); -} - -void ConfigureInput::updateButtonLabels() { - for (int button = 0; button < Settings::NativeButton::NumButtons; button++) { - button_map[button]->setText(ButtonToText(buttons_param[button])); - } - - 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++) { - if (analog_map_buttons[analog_id][sub_button_id]) { - analog_map_buttons[analog_id][sub_button_id]->setText( - AnalogToText(analogs_param[analog_id], analog_sub_buttons[sub_button_id])); - } - } - analog_map_stick[analog_id]->setText(tr("Set Analog Stick")); - } -} - -void ConfigureInput::handleClick(QPushButton* button, - std::function new_input_setter, - InputCommon::Polling::DeviceType type) { - button->setText(tr("[press key]")); - button->setFocus(); - - input_setter = new_input_setter; - - device_pollers = InputCommon::Polling::GetPollers(type); - - // Keyboard keys can only be used as button devices - want_keyboard_keys = type == InputCommon::Polling::DeviceType::Button; - - for (auto& poller : device_pollers) { - poller->Start(); - } - - grabKeyboard(); - grabMouse(); - timeout_timer->start(5000); // Cancel after 5 seconds - poll_timer->start(200); // Check for new inputs every 200ms -} - -void ConfigureInput::setPollingResult(const Common::ParamPackage& params, bool abort) { - releaseKeyboard(); - releaseMouse(); - timeout_timer->stop(); - poll_timer->stop(); - for (auto& poller : device_pollers) { - poller->Stop(); - } - - if (!abort) { - (*input_setter)(params); - } - - updateButtonLabels(); - input_setter = {}; -} - -void ConfigureInput::keyPressEvent(QKeyEvent* event) { - if (!input_setter || !event) - return; - - if (event->key() != Qt::Key_Escape) { - if (want_keyboard_keys) { - setPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())}, - false); - } else { - // Escape key wasn't pressed and we don't want any keyboard keys, so don't stop polling - return; - } - } - setPollingResult({}, true); + ui->use_docked_mode->setCheckState(Qt::Unchecked); + ui->handheld_connected->setCheckState(Qt::Unchecked); + ui->mouse_enabled->setCheckState(Qt::Unchecked); + ui->keyboard_enabled->setCheckState(Qt::Unchecked); + ui->debug_enabled->setCheckState(Qt::Unchecked); + ui->touchscreen_enabled->setCheckState(Qt::Checked); + updateUIEnabled(); } diff --git a/src/yuzu/configuration/configure_input.h b/src/yuzu/configuration/configure_input.h index 32c7183f9..0ba77c5ef 100644 --- a/src/yuzu/configuration/configure_input.h +++ b/src/yuzu/configuration/configure_input.h @@ -18,6 +18,7 @@ #include "core/settings.h" #include "input_common/main.h" #include "ui_configure_input.h" +#include "yuzu/configuration/config.h" class QPushButton; class QString; @@ -37,57 +38,19 @@ public: void applyConfiguration(); private: - std::unique_ptr ui; + void updateUIEnabled(); - std::unique_ptr timeout_timer; - std::unique_ptr poll_timer; - - /// This will be the the setting function when an input is awaiting configuration. - std::optional> input_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; - - /// A group of five QPushButtons represent one analog input. The buttons each represent up, - /// down, left, right, and modifier, respectively. - std::array, Settings::NativeAnalog::NumAnalogs> - analog_map_buttons; - - /// Analog inputs are also represented each with a single button, used to configure with an - /// actual analog stick - std::array analog_map_stick; - - static const std::array analog_sub_buttons; - - std::vector> device_pollers; - - /// A flag to indicate if keyboard keys are okay when configuring an input. If this is false, - /// keyboard events are ignored. - bool want_keyboard_keys = false; + template + void CallConfigureDialog(Args... args); /// Load configuration settings. void loadConfiguration(); /// Restore all buttons to their default values. void restoreDefaults(); - /// Clear all input configuration - void ClearAll(); - /// Update UI to reflect current configuration. - void updateButtonLabels(); + std::unique_ptr ui; - /// Called when the button was pressed. - void handleClick(QPushButton* button, - std::function new_input_setter, - InputCommon::Polling::DeviceType type); - - /// Finish polling and configure input using the input_setter - void setPollingResult(const Common::ParamPackage& params, bool abort); - - /// Handle key press events. - void keyPressEvent(QKeyEvent* event) override; + std::array players_enabled; + std::array player_controller; + std::array player_configure; }; diff --git a/src/yuzu/configuration/configure_input.ui b/src/yuzu/configuration/configure_input.ui index 8a019a693..f12896b47 100644 --- a/src/yuzu/configuration/configure_input.ui +++ b/src/yuzu/configuration/configure_input.ui @@ -6,7 +6,7 @@ 0 0 - 343 + 473 677 @@ -15,740 +15,474 @@ - - - + + + - Misc. + Players - - false - - - false - - - - - - - - Minus: - - - - - - - - - - - + + + + + + 110 + 0 + + + - - - - - - Plus: - - - - - - - - - - - + + + + Configure + + - - - - - - Home: - - - - - - - - - - - + + + + Controller Type + + + Qt::AlignCenter + + - - - - - Screen -Capture: - - - - - - - - - - - + + + Player 1 + + + + + + + Player 7 + + + + + + + Player 4 + + + + + + + Player 5 + + + + + + + Player 6 + + + + + + + Player 8 + + + + + + + Player 3 + + - + + + Player 2 + + + + + + + + 110 + 0 + + + + + + + + + 110 + 0 + + + + + + + + + 110 + 0 + + + + + + + + + 110 + 0 + + + + + + + + + 110 + 0 + + + + + + + + + 110 + 0 + + + + + + + + + 110 + 0 + + + + + + + + Configure + + + + + + + Configure + + + + + + + Configure + + + + + + + Configure + + + + + + + Configure + + + + + + + Configure + + + + + + + Configure + + + + + - Qt::Vertical + Qt::Horizontal - 20 - 40 + 40 + 20 - - - - - - - Face Buttons - - - false - - - false - - - - - - - - A: - - - - - - - - - - - + + + + Qt::Horizontal + + + + 40 + 20 + + + - - - - - B: - - - - - - - - - - - - - - - - - - X: - - - - - - - - - - - - - - - - - - Y: - - - - - - - - - - - + + + Enabled + + + Qt::AlignCenter + + - - + + - Directional Pad - - - false - - - false + Handheld + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 72 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Configure + + + - - - - - Up: - - - - - - - - - - - + + + Qt::Horizontal + + + + 40 + 20 + + + - - - - - Down: - - - - - - - - - - - - - - - - - - Left: - - - - - - - - - - - + + + Connected + + - - - - - Right: - - - - - - - - - - - + + + Use Docked Mode + + - - + + - Shoulder Buttons - - - false - - - false + Other - - - - - - L: - - - - - - - - - - - - - - - - - - R: - - - - - - - - - - - - - - - - - - ZL: - - - - - - - - - - - - - - - - - ZR: - - - - - - - - - - - - - - - - - - SL: - - - - - - - - - - - - - - - - - - SR: - - - - - - - - - - - - - - - - - - - Right Stick - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - false - - - false - - - - - - - - Down: - - - - - - - - - - - - - - - - - - Right: - - - - - - - - - - - - - - + + + + 0 + 23 + + - Set Analog Stick + Keyboard - - - - - - Left: - - - - - - - - - - - - - - - - - - Up: - - - - - - - - - - - - - - - - - - Pressed: - - - - - - - - - - - - - - - - - Modifier: - - - - - - - - - - - - - - - - - - - Left Stick - - - false - - - false - - - - - - - - Down: - - - - - - - - - - - - - - + - Set Analog Stick + Debug Controller - - - - - - Right: - - - - - - - - - - - - - - - - - - Left: - - - - - - - - - - - - - - - - - - Up: - - - - - - - - - - - - - - - - - - Modifier: - - - - - - - - - - - - - - - - - Pressed: - - - - - - - - - - - + + + Touchscreen + + + + + + + + 0 + 23 + + + + Mouse + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 76 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Advanced + + + + + + + Configure + + + + + + + Advanced + + - - - - - + - Qt::Horizontal + Qt::Vertical - 40 - 20 + 20 + 40 - - - - 0 - 0 - - - - - 0 - 0 - - - - - 0 - 0 - - - - Qt::LeftToRight - - - Clear All - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 0 - 0 - - - - Qt::LeftToRight - - - Restore Defaults - - + + + + + Restore Defaults + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + +