From f0fac0c7fb6f7dd9fe81747b3369767c8c9e7d01 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Wed, 22 Jul 2020 10:39:53 -0400 Subject: Project Mjölnir: Part 1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: James Rowe Co-authored-by: Its-Rei --- src/yuzu/CMakeLists.txt | 9 +- src/yuzu/configuration/config.cpp | 58 +- src/yuzu/configuration/config.h | 5 +- src/yuzu/configuration/configure.ui | 59 +- .../configuration/configure_debug_controller.cpp | 39 + .../configuration/configure_debug_controller.h | 33 + .../configuration/configure_debug_controller.ui | 97 + src/yuzu/configuration/configure_dialog.cpp | 8 +- src/yuzu/configuration/configure_input.cpp | 265 +- src/yuzu/configuration/configure_input.h | 22 +- src/yuzu/configuration/configure_input.ui | 1039 ++--- .../configuration/configure_input_advanced.cpp | 169 + src/yuzu/configuration/configure_input_advanced.h | 44 + src/yuzu/configuration/configure_input_advanced.ui | 2688 +++++++++++++ src/yuzu/configuration/configure_input_player.cpp | 733 ++-- src/yuzu/configuration/configure_input_player.h | 106 +- src/yuzu/configuration/configure_input_player.ui | 4019 ++++++++++++++------ src/yuzu/configuration/configure_input_simple.cpp | 152 - src/yuzu/configuration/configure_input_simple.h | 43 - src/yuzu/configuration/configure_input_simple.ui | 97 - .../configuration/configure_mouse_advanced.cpp | 8 +- src/yuzu/configuration/configure_mouse_advanced.ui | 252 +- src/yuzu/uisettings.cpp | 1 + src/yuzu/uisettings.h | 5 +- 24 files changed, 7387 insertions(+), 2564 deletions(-) create mode 100644 src/yuzu/configuration/configure_debug_controller.cpp create mode 100644 src/yuzu/configuration/configure_debug_controller.h create mode 100644 src/yuzu/configuration/configure_debug_controller.ui create mode 100644 src/yuzu/configuration/configure_input_advanced.cpp create mode 100644 src/yuzu/configuration/configure_input_advanced.h create mode 100644 src/yuzu/configuration/configure_input_advanced.ui delete mode 100644 src/yuzu/configuration/configure_input_simple.cpp delete mode 100644 src/yuzu/configuration/configure_input_simple.h delete mode 100644 src/yuzu/configuration/configure_input_simple.ui (limited to 'src/yuzu') diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 656096c9f..6987e85e1 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -39,6 +39,9 @@ add_executable(yuzu configuration/configure_debug.cpp configuration/configure_debug.h configuration/configure_debug.ui + configuration/configure_debug_controller.cpp + configuration/configure_debug_controller.h + configuration/configure_debug_controller.ui configuration/configure_dialog.cpp configuration/configure_dialog.h configuration/configure_filesystem.cpp @@ -62,9 +65,9 @@ add_executable(yuzu configuration/configure_input_player.cpp configuration/configure_input_player.h configuration/configure_input_player.ui - configuration/configure_input_simple.cpp - configuration/configure_input_simple.h - configuration/configure_input_simple.ui + configuration/configure_input_advanced.cpp + configuration/configure_input_advanced.h + configuration/configure_input_advanced.ui configuration/configure_mouse_advanced.cpp configuration/configure_mouse_advanced.h configuration/configure_mouse_advanced.ui diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 7af974d8d..489877be9 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -6,7 +6,6 @@ #include #include #include "common/file_util.h" -#include "configure_input_simple.h" #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/hid/controllers/npad.h" #include "input_common/main.h" @@ -32,29 +31,29 @@ Config::~Config() { } const std::array Config::default_buttons = { - Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X, Qt::Key_3, Qt::Key_4, Qt::Key_Q, - Qt::Key_W, Qt::Key_1, Qt::Key_2, Qt::Key_N, Qt::Key_M, Qt::Key_F, Qt::Key_T, - Qt::Key_H, Qt::Key_G, Qt::Key_Left, Qt::Key_Up, Qt::Key_Right, Qt::Key_Down, Qt::Key_J, - Qt::Key_I, Qt::Key_L, Qt::Key_K, Qt::Key_D, Qt::Key_C, Qt::Key_B, Qt::Key_V, + Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X, Qt::Key_3, Qt::Key_4, Qt::Key_Q, + Qt::Key_W, Qt::Key_1, Qt::Key_2, Qt::Key_N, Qt::Key_M, Qt::Key_F, Qt::Key_T, + Qt::Key_H, Qt::Key_G, Qt::Key_D, Qt::Key_C, Qt::Key_B, Qt::Key_V, }; -const std::array, Settings::NativeAnalog::NumAnalogs> Config::default_analogs{{ +const std::array, Settings::NativeAnalog::NumAnalogs> Config::default_analogs{{ { Qt::Key_Up, Qt::Key_Down, Qt::Key_Left, Qt::Key_Right, - Qt::Key_E, }, { Qt::Key_I, Qt::Key_K, Qt::Key_J, Qt::Key_L, - Qt::Key_R, }, }}; +const int Config::default_lstick_mod = Qt::Key_E; +const int Config::default_rstick_mod = Qt::Key_R; + const std::array Config::default_mouse_buttons = { Qt::Key_BracketLeft, Qt::Key_BracketRight, Qt::Key_Apostrophe, Qt::Key_Minus, Qt::Key_Equal, @@ -243,10 +242,10 @@ void Config::ReadPlayerValues() { player.connected = ReadSetting(QStringLiteral("player_%1_connected").arg(p), false).toBool(); - player.type = static_cast( + player.controller_type = static_cast( qt_config ->value(QStringLiteral("player_%1_type").arg(p), - static_cast(Settings::ControllerType::DualJoycon)) + static_cast(Settings::ControllerType::ProController)) .toUInt()); player.body_color_left = qt_config @@ -300,12 +299,6 @@ void Config::ReadPlayerValues() { } } } - - std::stable_partition( - Settings::values.players.begin(), - Settings::values.players.begin() + - Service::HID::Controller_NPad::NPadIdToIndex(Service::HID::NPAD_HANDHELD), - [](const auto& player) { return player.connected; }); } void Config::ReadDebugValues() { @@ -397,13 +390,6 @@ void Config::ReadTouchscreenValues() { ReadSetting(QStringLiteral("touchscreen_diameter_y"), 15).toUInt(); } -void Config::ApplyDefaultProfileIfInputInvalid() { - if (!std::any_of(Settings::values.players.begin(), Settings::values.players.end(), - [](const Settings::PlayerInput& in) { return in.connected; })) { - ApplyInputProfileConfiguration(UISettings::values.profile_index); - } -} - void Config::ReadAudioValues() { qt_config->beginGroup(QStringLiteral("Audio")); @@ -433,6 +419,8 @@ void Config::ReadControlValues() { ReadMouseValues(); ReadTouchscreenValues(); + Settings::values.vibration_enabled = + ReadSetting(QStringLiteral("vibration_enabled"), true).toBool(); Settings::values.motion_device = ReadSetting(QStringLiteral("motion_device"), QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01")) @@ -501,7 +489,7 @@ void Config::ReadDataStorageValues() { Settings::values.gamecard_current_game = ReadSetting(QStringLiteral("gamecard_current_game"), false).toBool(); Settings::values.gamecard_path = - ReadSetting(QStringLiteral("gamecard_path"), QStringLiteral("")).toString().toStdString(); + ReadSetting(QStringLiteral("gamecard_path"), QString{}).toString().toStdString(); qt_config->endGroup(); } @@ -515,7 +503,7 @@ void Config::ReadDebuggingValues() { Settings::values.use_gdbstub = ReadSetting(QStringLiteral("use_gdbstub"), false).toBool(); Settings::values.gdbstub_port = ReadSetting(QStringLiteral("gdbstub_port"), 24689).toInt(); Settings::values.program_args = - ReadSetting(QStringLiteral("program_args"), QStringLiteral("")).toString().toStdString(); + ReadSetting(QStringLiteral("program_args"), QString{}).toString().toStdString(); Settings::values.dump_exefs = ReadSetting(QStringLiteral("dump_exefs"), false).toBool(); Settings::values.dump_nso = ReadSetting(QStringLiteral("dump_nso"), false).toBool(); Settings::values.reporting_services = @@ -548,8 +536,7 @@ void Config::ReadDisabledAddOnValues() { const auto d_size = qt_config->beginReadArray(QStringLiteral("disabled")); for (int j = 0; j < d_size; ++j) { qt_config->setArrayIndex(j); - out.push_back( - ReadSetting(QStringLiteral("d"), QStringLiteral("")).toString().toStdString()); + out.push_back(ReadSetting(QStringLiteral("d"), QString{}).toString().toStdString()); } qt_config->endArray(); Settings::values.disabled_addons.insert_or_assign(title_id, out); @@ -788,14 +775,11 @@ void Config::ReadUIValues() { UISettings::values.first_start = ReadSetting(QStringLiteral("firstStart"), true).toBool(); UISettings::values.callout_flags = ReadSetting(QStringLiteral("calloutFlags"), 0).toUInt(); UISettings::values.show_console = ReadSetting(QStringLiteral("showConsole"), false).toBool(); - UISettings::values.profile_index = ReadSetting(QStringLiteral("profileIndex"), 0).toUInt(); UISettings::values.pause_when_in_background = ReadSetting(QStringLiteral("pauseWhenInBackground"), false).toBool(); UISettings::values.hide_mouse = ReadSetting(QStringLiteral("hideInactiveMouse"), false).toBool(); - ApplyDefaultProfileIfInputInvalid(); - qt_config->endGroup(); } @@ -869,8 +853,9 @@ void Config::SavePlayerValues() { const auto& player = Settings::values.players[p]; WriteSetting(QStringLiteral("player_%1_connected").arg(p), player.connected, false); - WriteSetting(QStringLiteral("player_%1_type").arg(p), static_cast(player.type), - static_cast(Settings::ControllerType::DualJoycon)); + WriteSetting(QStringLiteral("player_%1_type").arg(p), + static_cast(player.controller_type), + static_cast(Settings::ControllerType::ProController)); WriteSetting(QStringLiteral("player_%1_body_color_left").arg(p), player.body_color_left, Settings::JOYCON_BODY_NEON_BLUE); @@ -990,6 +975,7 @@ void Config::SaveControlValues() { SaveMouseValues(); SaveTouchscreenValues(); + WriteSetting(QStringLiteral("vibration_enabled"), Settings::values.vibration_enabled, true); WriteSetting(QStringLiteral("motion_device"), QString::fromStdString(Settings::values.motion_device), QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01")); @@ -1036,7 +1022,7 @@ void Config::SaveDataStorageValues() { WriteSetting(QStringLiteral("gamecard_current_game"), Settings::values.gamecard_current_game, false); WriteSetting(QStringLiteral("gamecard_path"), - QString::fromStdString(Settings::values.gamecard_path), QStringLiteral("")); + QString::fromStdString(Settings::values.gamecard_path), QString{}); qt_config->endGroup(); } @@ -1049,7 +1035,7 @@ void Config::SaveDebuggingValues() { WriteSetting(QStringLiteral("use_gdbstub"), Settings::values.use_gdbstub, false); WriteSetting(QStringLiteral("gdbstub_port"), Settings::values.gdbstub_port, 24689); WriteSetting(QStringLiteral("program_args"), - QString::fromStdString(Settings::values.program_args), QStringLiteral("")); + QString::fromStdString(Settings::values.program_args), QString{}); WriteSetting(QStringLiteral("dump_exefs"), Settings::values.dump_exefs, false); WriteSetting(QStringLiteral("dump_nso"), Settings::values.dump_nso, false); WriteSetting(QStringLiteral("quest_flag"), Settings::values.quest_flag, false); @@ -1076,8 +1062,7 @@ void Config::SaveDisabledAddOnValues() { qt_config->beginWriteArray(QStringLiteral("disabled")); for (std::size_t j = 0; j < elem.second.size(); ++j) { qt_config->setArrayIndex(static_cast(j)); - WriteSetting(QStringLiteral("d"), QString::fromStdString(elem.second[j]), - QStringLiteral("")); + WriteSetting(QStringLiteral("d"), QString::fromStdString(elem.second[j]), QString{}); } qt_config->endArray(); ++i; @@ -1266,7 +1251,6 @@ void Config::SaveUIValues() { WriteSetting(QStringLiteral("firstStart"), UISettings::values.first_start, true); WriteSetting(QStringLiteral("calloutFlags"), UISettings::values.callout_flags, 0); WriteSetting(QStringLiteral("showConsole"), UISettings::values.show_console, false); - WriteSetting(QStringLiteral("profileIndex"), UISettings::values.profile_index, 0); WriteSetting(QStringLiteral("pauseWhenInBackground"), UISettings::values.pause_when_in_background, false); WriteSetting(QStringLiteral("hideInactiveMouse"), UISettings::values.hide_mouse, false); diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h index e5f39b040..9eeaf9d1e 100644 --- a/src/yuzu/configuration/config.h +++ b/src/yuzu/configuration/config.h @@ -23,7 +23,9 @@ public: void Save(); static const std::array default_buttons; - static const std::array, Settings::NativeAnalog::NumAnalogs> default_analogs; + static const std::array, Settings::NativeAnalog::NumAnalogs> default_analogs; + static const int default_lstick_mod; + static const int default_rstick_mod; static const std::array default_mouse_buttons; static const std::array default_keyboard_keys; @@ -37,7 +39,6 @@ private: void ReadKeyboardValues(); void ReadMouseValues(); void ReadTouchscreenValues(); - void ApplyDefaultProfileIfInputInvalid(); // Read functions bases off the respective config section names. void ReadAudioValues(); diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui index 5f5d8e571..fcf42cdcb 100644 --- a/src/yuzu/configuration/configure.ui +++ b/src/yuzu/configuration/configure.ui @@ -6,7 +6,7 @@ 0 0 - 382 + 650 650 @@ -26,13 +26,13 @@ - 150 + 120 0 - 150 + 120 16777215 @@ -44,76 +44,121 @@ 0 + + General + General + + UI + Game List + + System + System + + Profiles + Profiles + + Filesystem + Filesystem - + + + Controls + - Input + Controls + + Hotkeys + Hotkeys + + CPU + CPU + + Debug + Debug + + Graphics + Graphics + + Advanced + GraphicsAdvanced + + Audio + Audio + + Debug + Debug + + Web + Web + + Services + Services @@ -205,9 +250,9 @@ 1 - ConfigureInputSimple + ConfigureInput QWidget -
configuration/configure_input_simple.h
+
configuration/configure_input.h
1
diff --git a/src/yuzu/configuration/configure_debug_controller.cpp b/src/yuzu/configuration/configure_debug_controller.cpp new file mode 100644 index 000000000..45996b73f --- /dev/null +++ b/src/yuzu/configuration/configure_debug_controller.cpp @@ -0,0 +1,39 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "ui_configure_debug_controller.h" +#include "yuzu/configuration/configure_debug_controller.h" + +ConfigureDebugController::ConfigureDebugController(QWidget* parent) + : QDialog(parent), ui(std::make_unique()) { + ui->setupUi(this); + + debug_controller = new ConfigureInputPlayer(this, 9, nullptr, true); + ui->controllerLayout->addWidget(debug_controller); + + connect(ui->clear_all_button, &QPushButton::clicked, this, + [this] { debug_controller->ClearAll(); }); + connect(ui->restore_defaults_button, &QPushButton::clicked, this, + [this] { debug_controller->RestoreDefaults(); }); + + RetranslateUI(); +} + +ConfigureDebugController::~ConfigureDebugController() = default; + +void ConfigureDebugController::ApplyConfiguration() { + debug_controller->ApplyConfiguration(); +} + +void ConfigureDebugController::changeEvent(QEvent* event) { + if (event->type() == QEvent::LanguageChange) { + RetranslateUI(); + } + + QDialog::changeEvent(event); +} + +void ConfigureDebugController::RetranslateUI() { + ui->retranslateUi(this); +} diff --git a/src/yuzu/configuration/configure_debug_controller.h b/src/yuzu/configuration/configure_debug_controller.h new file mode 100644 index 000000000..df359a4f3 --- /dev/null +++ b/src/yuzu/configuration/configure_debug_controller.h @@ -0,0 +1,33 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include "yuzu/configuration/configure_input_player.h" + +class QPushButton; + +namespace Ui { +class ConfigureDebugController; +} + +class ConfigureDebugController : public QDialog { + Q_OBJECT + +public: + explicit ConfigureDebugController(QWidget* parent); + ~ConfigureDebugController() override; + + void ApplyConfiguration(); + +private: + void changeEvent(QEvent* event) override; + void RetranslateUI(); + + ConfigureInputPlayer* debug_controller; + + std::unique_ptr ui; +}; diff --git a/src/yuzu/configuration/configure_debug_controller.ui b/src/yuzu/configuration/configure_debug_controller.ui new file mode 100644 index 000000000..a95ed50ff --- /dev/null +++ b/src/yuzu/configuration/configure_debug_controller.ui @@ -0,0 +1,97 @@ + + + ConfigureDebugController + + + + 0 + 0 + 780 + 500 + + + + Configure Debug Controller + + + + 2 + + + 9 + + + 9 + + + 9 + + + 9 + + + + + + + + + + Clear + + + + + + + Defaults + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + accepted() + ConfigureDebugController + accept() + + + 140 + 318 + + + 140 + 169 + + + + + buttonBox + rejected() + ConfigureDebugController + reject() + + + 140 + 318 + + + 140 + 169 + + + + + diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 4e30dc51e..857577591 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -80,12 +80,12 @@ Q_DECLARE_METATYPE(QList); void ConfigureDialog::PopulateSelectionList() { const std::array>, 6> items{ - {{tr("General"), {ui->generalTab, ui->webTab, ui->debugTab, ui->uiTab}}, + {{tr("General"), {ui->generalTab, ui->hotkeysTab, ui->uiTab, ui->webTab, ui->debugTab}}, {tr("System"), {ui->systemTab, ui->profileManagerTab, ui->serviceTab, ui->filesystemTab}}, {tr("CPU"), {ui->cpuTab, ui->cpuDebugTab}}, {tr("Graphics"), {ui->graphicsTab, ui->graphicsAdvancedTab}}, {tr("Audio"), {ui->audioTab}}, - {tr("Controls"), {ui->inputTab, ui->hotkeysTab}}}, + {tr("Controls"), ui->inputTab->GetSubTabs()}}, }; [[maybe_unused]] const QSignalBlocker blocker(ui->selectorList); @@ -117,7 +117,7 @@ void ConfigureDialog::UpdateVisibleTabs() { {ui->generalTab, tr("General")}, {ui->systemTab, tr("System")}, {ui->profileManagerTab, tr("Profiles")}, - {ui->inputTab, tr("Input")}, + {ui->inputTab, tr("Controls")}, {ui->hotkeysTab, tr("Hotkeys")}, {ui->cpuTab, tr("CPU")}, {ui->cpuDebugTab, tr("Debug")}, @@ -138,6 +138,6 @@ void ConfigureDialog::UpdateVisibleTabs() { const QList tabs = qvariant_cast>(items[0]->data(Qt::UserRole)); for (const auto tab : tabs) { - ui->tabWidget->addTab(tab, widgets.at(tab)); + ui->tabWidget->addTab(tab, tab->accessibleName()); } } diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index f2977719c..5200d2d0e 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -8,18 +8,32 @@ #include #include -#include "configuration/configure_touchscreen_advanced.h" #include "core/core.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_ae.h" #include "core/hle/service/am/applet_oe.h" -#include "core/hle/service/hid/controllers/npad.h" #include "core/hle/service/sm/sm.h" #include "ui_configure_input.h" +#include "ui_configure_input_advanced.h" #include "ui_configure_input_player.h" +#include "yuzu/configuration/configure_debug_controller.h" #include "yuzu/configuration/configure_input.h" +#include "yuzu/configuration/configure_input_advanced.h" #include "yuzu/configuration/configure_input_player.h" #include "yuzu/configuration/configure_mouse_advanced.h" +#include "yuzu/configuration/configure_touchscreen_advanced.h" + +namespace { +template +void CallConfigureDialog(ConfigureInput& parent, Args&&... args) { + Dialog dialog(&parent, std::forward(args)...); + + const auto res = dialog.exec(); + if (res == QDialog::Accepted) { + dialog.ApplyConfiguration(); + } +} +} // Anonymous namespace void OnDockedModeChanged(bool last_state, bool new_state) { if (last_state == new_state) { @@ -48,97 +62,93 @@ void OnDockedModeChanged(bool last_state, bool new_state) { } } -namespace { -template -void CallConfigureDialog(ConfigureInput& parent, Args&&... args) { - parent.ApplyConfiguration(); - Dialog dialog(&parent, std::forward(args)...); - - const auto res = dialog.exec(); - if (res == QDialog::Accepted) { - dialog.ApplyConfiguration(); - } -} -} // Anonymous namespace - ConfigureInput::ConfigureInput(QWidget* parent) - : QDialog(parent), ui(std::make_unique()) { + : QWidget(parent), ui(std::make_unique()) { ui->setupUi(this); - players_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, + player_controllers = { + new ConfigureInputPlayer(this, 0, ui->consoleInputSettings), + new ConfigureInputPlayer(this, 1, ui->consoleInputSettings), + new ConfigureInputPlayer(this, 2, ui->consoleInputSettings), + new ConfigureInputPlayer(this, 3, ui->consoleInputSettings), + new ConfigureInputPlayer(this, 4, ui->consoleInputSettings), + new ConfigureInputPlayer(this, 5, ui->consoleInputSettings), + new ConfigureInputPlayer(this, 6, ui->consoleInputSettings), + new ConfigureInputPlayer(this, 7, ui->consoleInputSettings), }; - players_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, + player_tabs = { + ui->tabPlayer1, ui->tabPlayer2, ui->tabPlayer3, ui->tabPlayer4, + ui->tabPlayer5, ui->tabPlayer6, ui->tabPlayer7, ui->tabPlayer8, }; - RetranslateUI(); - LoadConfiguration(); - UpdateUIEnabled(); - - connect(ui->restore_defaults_button, &QPushButton::clicked, this, - &ConfigureInput::RestoreDefaults); + player_connected = { + ui->checkboxPlayer1Connected, ui->checkboxPlayer2Connected, ui->checkboxPlayer3Connected, + ui->checkboxPlayer4Connected, ui->checkboxPlayer5Connected, ui->checkboxPlayer6Connected, + ui->checkboxPlayer7Connected, ui->checkboxPlayer8Connected, + }; - for (auto* enabled : players_controller) { - connect(enabled, QOverload::of(&QComboBox::currentIndexChanged), this, - &ConfigureInput::UpdateUIEnabled); + for (std::size_t i = 0; i < player_tabs.size(); ++i) { + player_tabs[i]->setLayout(new QHBoxLayout(player_tabs[i])); + player_tabs[i]->layout()->addWidget(player_controllers[i]); + connect(player_controllers[i], &ConfigureInputPlayer::Connected, [&, i](bool is_connected) { + if (is_connected) { + for (std::size_t index = 0; index <= i; ++index) { + player_connected[index]->setChecked(is_connected); + } + } else { + for (std::size_t index = i; index < player_tabs.size(); ++index) { + player_connected[index]->setChecked(is_connected); + } + } + }); + connect(player_controllers[i], &ConfigureInputPlayer::RefreshInputDevices, + [&] { UpdateAllInputDevices(); }); + connect(player_connected[i], &QCheckBox::stateChanged, + [&, i](int state) { player_controllers[i]->ConnectPlayer(state == Qt::Checked); }); } - 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 < players_configure.size(); ++i) { - connect(players_configure[i], &QPushButton::clicked, this, - [this, i] { CallConfigureDialog(*this, i, false); }); - } - - connect(ui->handheld_configure, &QPushButton::clicked, this, - [this] { CallConfigureDialog(*this, 8, false); }); - - connect(ui->debug_configure, &QPushButton::clicked, this, - [this] { CallConfigureDialog(*this, 9, true); }); - - connect(ui->mouse_advanced, &QPushButton::clicked, this, + // Only the first player can choose handheld mode so connect the signal just to player 1 + connect(player_controllers[0], &ConfigureInputPlayer::HandheldStateChanged, + [&](bool is_handheld) { UpdateDockedState(is_handheld); }); + + advanced = new ConfigureInputAdvanced(this); + ui->tabAdvanced->setLayout(new QHBoxLayout(ui->tabAdvanced)); + ui->tabAdvanced->layout()->addWidget(advanced); + connect(advanced, &ConfigureInputAdvanced::CallDebugControllerDialog, + [this] { CallConfigureDialog(*this); }); + connect(advanced, &ConfigureInputAdvanced::CallMouseConfigDialog, [this] { CallConfigureDialog(*this); }); - - connect(ui->touchscreen_advanced, &QPushButton::clicked, this, + connect(advanced, &ConfigureInputAdvanced::CallTouchscreenConfigDialog, [this] { CallConfigureDialog(*this); }); + + connect(ui->buttonClearAll, &QPushButton::clicked, [this] { ClearAll(); }); + connect(ui->buttonRestoreDefaults, &QPushButton::clicked, [this] { RestoreDefaults(); }); + + RetranslateUI(); + LoadConfiguration(); } ConfigureInput::~ConfigureInput() = default; -void ConfigureInput::ApplyConfiguration() { - for (std::size_t i = 0; i < players_controller.size(); ++i) { - const auto controller_type_index = players_controller[i]->currentIndex(); - - Settings::values.players[i].connected = controller_type_index != 0; +QList ConfigureInput::GetSubTabs() const { + return { + ui->tabPlayer1, ui->tabPlayer2, ui->tabPlayer3, ui->tabPlayer4, ui->tabPlayer5, + ui->tabPlayer6, ui->tabPlayer7, ui->tabPlayer8, ui->tabAdvanced, + }; +} - if (controller_type_index > 0) { - Settings::values.players[i].type = - static_cast(controller_type_index - 1); - } else { - Settings::values.players[i].type = Settings::ControllerType::DualJoycon; - } +void ConfigureInput::ApplyConfiguration() { + for (auto controller : player_controllers) { + controller->ApplyConfiguration(); } + advanced->ApplyConfiguration(); + const bool pre_docked_mode = Settings::values.use_docked_mode; - Settings::values.use_docked_mode = ui->use_docked_mode->isChecked(); + Settings::values.use_docked_mode = ui->radioDocked->isChecked(); OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode); - Settings::values - .players[Service::HID::Controller_NPad::NPadIdToIndex(Service::HID::NPAD_HANDHELD)] - .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(); + + Settings::values.vibration_enabled = ui->vibrationGroup->isChecked(); } void ConfigureInput::changeEvent(QEvent* event) { @@ -146,94 +156,63 @@ void ConfigureInput::changeEvent(QEvent* event) { RetranslateUI(); } - QDialog::changeEvent(event); + QWidget::changeEvent(event); } void ConfigureInput::RetranslateUI() { ui->retranslateUi(this); - RetranslateControllerComboBoxes(); } -void ConfigureInput::RetranslateControllerComboBoxes() { - for (auto* controller_box : players_controller) { - [[maybe_unused]] const QSignalBlocker blocker(controller_box); - - controller_box->clear(); - controller_box->addItems({tr("None"), tr("Pro Controller"), tr("Dual Joycons"), - tr("Single Right Joycon"), tr("Single Left Joycon")}); - } - +void ConfigureInput::LoadConfiguration() { LoadPlayerControllerIndices(); -} + UpdateDockedState(Settings::values.players[0].controller_type == + Settings::ControllerType::Handheld); -void ConfigureInput::UpdateUIEnabled() { - bool hit_disabled = false; - for (auto* player : players_controller) { - player->setDisabled(hit_disabled); - if (hit_disabled) { - player->setCurrentIndex(0); - } - if (!hit_disabled && player->currentIndex() == 0) { - hit_disabled = true; - } - } + ui->vibrationGroup->setChecked(Settings::values.vibration_enabled); +} - for (std::size_t i = 0; i < players_controller.size(); ++i) { - players_configure[i]->setEnabled(players_controller[i]->currentIndex() != 0); +void ConfigureInput::LoadPlayerControllerIndices() { + for (std::size_t i = 0; i < player_connected.size(); ++i) { + const auto connected = Settings::values.players[i].connected || + (i == 0 && Settings::values.players[8].connected); + player_connected[i]->setChecked(connected); } +} - ui->handheld_connected->setChecked(ui->handheld_connected->isChecked() && - !ui->use_docked_mode->isChecked()); - 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::ClearAll() { + // We don't have a good way to know what tab is active, but we can find out by getting the + // parent of the consoleInputSettings + auto player_tab = static_cast(ui->consoleInputSettings->parent()); + player_tab->ClearAll(); } -void ConfigureInput::LoadConfiguration() { - std::stable_partition( - Settings::values.players.begin(), - Settings::values.players.begin() + - Service::HID::Controller_NPad::NPadIdToIndex(Service::HID::NPAD_HANDHELD), - [](const auto& player) { return player.connected; }); +void ConfigureInput::RestoreDefaults() { + // We don't have a good way to know what tab is active, but we can find out by getting the + // parent of the consoleInputSettings + auto player_tab = static_cast(ui->consoleInputSettings->parent()); + player_tab->RestoreDefaults(); + + ui->radioDocked->setChecked(true); + ui->radioUndocked->setChecked(false); + ui->vibrationGroup->setChecked(true); +} - LoadPlayerControllerIndices(); +void ConfigureInput::UpdateDockedState(bool is_handheld) { + // If the controller type is handheld only, disallow changing docked mode + ui->radioDocked->setEnabled(!is_handheld); + ui->radioUndocked->setEnabled(!is_handheld); - ui->use_docked_mode->setChecked(Settings::values.use_docked_mode); - ui->handheld_connected->setChecked( - Settings::values - .players[Service::HID::Controller_NPad::NPadIdToIndex(Service::HID::NPAD_HANDHELD)] - .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(); -} + ui->radioDocked->setChecked(Settings::values.use_docked_mode); + ui->radioUndocked->setChecked(!Settings::values.use_docked_mode); -void ConfigureInput::LoadPlayerControllerIndices() { - for (std::size_t i = 0; i < players_controller.size(); ++i) { - const auto connected = Settings::values.players[i].connected; - players_controller[i]->setCurrentIndex( - connected ? static_cast(Settings::values.players[i].type) + 1 : 0); + // If its handheld only, force docked mode off (since you can't play handheld in a dock) + if (is_handheld) { + ui->radioUndocked->setChecked(true); } } -void ConfigureInput::RestoreDefaults() { - players_controller[0]->setCurrentIndex(2); - - for (std::size_t i = 1; i < players_controller.size(); ++i) { - players_controller[i]->setCurrentIndex(0); +void ConfigureInput::UpdateAllInputDevices() { + for (const auto& player : player_controllers) { + player->UpdateInputDevices(); } - - 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 2f70cb3ca..8241d23ef 100644 --- a/src/yuzu/configuration/configure_input.h +++ b/src/yuzu/configuration/configure_input.h @@ -10,11 +10,14 @@ #include #include +#include "yuzu/configuration/configure_input_advanced.h" +#include "yuzu/configuration/configure_input_player.h" + #include "ui_configure_input.h" -class QPushButton; class QString; class QTimer; +class QCheckBox; namespace Ui { class ConfigureInput; @@ -22,22 +25,25 @@ class ConfigureInput; void OnDockedModeChanged(bool last_state, bool new_state); -class ConfigureInput : public QDialog { +class ConfigureInput : public QWidget { Q_OBJECT public: explicit ConfigureInput(QWidget* parent = nullptr); ~ConfigureInput() override; - /// Save all button configurations to settings file + /// Save all button configurations to settings file. void ApplyConfiguration(); + QList GetSubTabs() const; + private: void changeEvent(QEvent* event) override; void RetranslateUI(); - void RetranslateControllerComboBoxes(); + void ClearAll(); - void UpdateUIEnabled(); + void UpdateDockedState(bool is_handheld); + void UpdateAllInputDevices(); /// Load configuration settings. void LoadConfiguration(); @@ -48,6 +54,8 @@ private: std::unique_ptr ui; - std::array players_controller; - std::array players_configure; + std::array player_controllers; + std::array player_tabs; + std::array player_connected; + ConfigureInputAdvanced* advanced; }; diff --git a/src/yuzu/configuration/configure_input.ui b/src/yuzu/configuration/configure_input.ui index efffd8487..136955224 100644 --- a/src/yuzu/configuration/configure_input.ui +++ b/src/yuzu/configuration/configure_input.ui @@ -1,529 +1,554 @@ ConfigureInput - + 0 0 - 384 - 576 + 700 + 540 - Custom Input Settings + ConfigureInput + + 2 + + + 3 + + + 3 + + + 3 + + + 3 + - - - - - Players - - - - - - - 110 - 0 - - - - - - - - Configure - - - - - - - Controller Type - - - Qt::AlignCenter - - - - - - - - 110 - 0 - - - - - - - - - 110 - 0 - - - - - - - - - 110 - 0 - - - - - - - - - 110 - 0 - - - - - - - - - 110 - 0 - - - - - - - - - 110 - 0 - - - - - - - - - 110 - 0 - - - - - - - - Configure - - - - - - - Configure - - - - - - - Configure - - - - - - - Configure - - - - - - - Configure - - - - - - - Configure - - - - - - - Configure - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 55 - 0 - - - - Player 1 - - - - - - - Player 2 - - - - - - - Player 3 - - - - - - - Player 4 - - - - - - - Player 5 - - - - - - - Player 6 - - - - - - - Player 7 - - - - - - - Player 8 - - - - - - - - - - Handheld - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 72 - 20 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Configure - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Joycons Docked - - - - - - - Use Docked Mode - - - - - - - - - - Other - - - - - - - 0 - 23 - - - - Keyboard - - - - - - - Debug Controller - - - - - - - Touchscreen - - - - - - - - 0 - 23 - - - - Mouse - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 76 - 20 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Advanced - - - - - - - Configure - - - - - - - Advanced - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - Restore Defaults + + + 0 + + + + Player 1 + + + Player 1 + + + + + Player 2 + + + Player 2 + + + + + Player 3 + + + Player 3 + + + + + Player 4 + + + Player 4 + + + + + Player 5 + + + Player 5 + + + + + Player 6 + + + Player 6 + + + + + Player 7 + + + Player 7 + + + + + Player 8 + + + Player 8 + + + + + Advanced + + + Advanced + + + + + + + + + 3 + + + 0 + + + 3 + + + 0 + + + 0 + + + + + + 16777215 + 16777215 + + + + Console Mode + + + + 6 + + + 3 + + + 6 + + + 3 + + + 6 + + + + + Docked + + + true + + + + + + + Undocked + + + + + + + + + + Vibration + + + true + + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 65 + 21 + + + + + 65 + 16777215 + + + + % + + + 1 + + + 200 + + + 100 + + + + + + + + + + Motion + + + true + + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + Configure + + + + + + + + + + + 5 + + + 0 - - - - - - Qt::Horizontal + + 0 - - - 40 - 20 - + + 0 - - - - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + 3 - - - - - + + + + + + + + + + + Controllers + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + Qt::AlignCenter + + + + + + + + + + + + + + + + + + + + + Qt::LeftToRight + + + true + + + + + + + + + + + + + + 2 + + + Qt::AlignCenter + + + + + + + 3 + + + Qt::AlignCenter + + + + + + + 4 + + + Qt::AlignCenter + + + + + + + 5 + + + Qt::AlignCenter + + + + + + + 6 + + + Qt::AlignCenter + + + + + + + 7 + + + Qt::AlignCenter + + + + + + + 8 + + + Qt::AlignCenter + + + + + + + Connected + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + + 0 + 0 + + + + + 0 + 0 + + + + Qt::LeftToRight + + + min-width: 55px; + + + Defaults + + + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + + 0 + 0 + + + + + 0 + 0 + + + + Qt::LeftToRight + + + min-width: 55px; + + + Clear + + + + +
- - - buttonBox - accepted() - ConfigureInput - accept() - - - 294 - 553 - - - 191 - 287 - - - - - buttonBox - rejected() - ConfigureInput - reject() - - - 294 - 553 - - - 191 - 287 - - - - + diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp new file mode 100644 index 000000000..18db04e7e --- /dev/null +++ b/src/yuzu/configuration/configure_input_advanced.cpp @@ -0,0 +1,169 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include "core/core.h" +#include "core/settings.h" +#include "ui_configure_input_advanced.h" +#include "yuzu/configuration/configure_input_advanced.h" + +ConfigureInputAdvanced::ConfigureInputAdvanced(QWidget* parent) + : QWidget(parent), ui(new Ui::ConfigureInputAdvanced) { + ui->setupUi(this); + + controllers_color_buttons = {{ + { + ui->player1_left_body_button, + ui->player1_left_buttons_button, + ui->player1_right_body_button, + ui->player1_right_buttons_button, + }, + { + ui->player2_left_body_button, + ui->player2_left_buttons_button, + ui->player2_right_body_button, + ui->player2_right_buttons_button, + }, + { + ui->player3_left_body_button, + ui->player3_left_buttons_button, + ui->player3_right_body_button, + ui->player3_right_buttons_button, + }, + { + ui->player4_left_body_button, + ui->player4_left_buttons_button, + ui->player4_right_body_button, + ui->player4_right_buttons_button, + }, + { + ui->player5_left_body_button, + ui->player5_left_buttons_button, + ui->player5_right_body_button, + ui->player5_right_buttons_button, + }, + { + ui->player6_left_body_button, + ui->player6_left_buttons_button, + ui->player6_right_body_button, + ui->player6_right_buttons_button, + }, + { + ui->player7_left_body_button, + ui->player7_left_buttons_button, + ui->player7_right_body_button, + ui->player7_right_buttons_button, + }, + { + ui->player8_left_body_button, + ui->player8_left_buttons_button, + ui->player8_right_body_button, + ui->player8_right_buttons_button, + }, + }}; + + for (std::size_t player_idx = 0; player_idx < controllers_color_buttons.size(); ++player_idx) { + auto& color_buttons = controllers_color_buttons[player_idx]; + for (std::size_t button_idx = 0; button_idx < color_buttons.size(); ++button_idx) { + connect(color_buttons[button_idx], &QPushButton::clicked, this, + [this, player_idx, button_idx] { + OnControllerButtonClick(static_cast(player_idx), + static_cast(button_idx)); + }); + } + } + + connect(ui->mouse_enabled, &QCheckBox::stateChanged, this, + &ConfigureInputAdvanced::UpdateUIEnabled); + connect(ui->debug_enabled, &QCheckBox::stateChanged, this, + &ConfigureInputAdvanced::UpdateUIEnabled); + connect(ui->touchscreen_enabled, &QCheckBox::stateChanged, this, + &ConfigureInputAdvanced::UpdateUIEnabled); + + connect(ui->debug_configure, &QPushButton::clicked, this, + [this] { CallDebugControllerDialog(); }); + connect(ui->mouse_advanced, &QPushButton::clicked, this, [this] { CallMouseConfigDialog(); }); + connect(ui->touchscreen_advanced, &QPushButton::clicked, this, + [this] { CallTouchscreenConfigDialog(); }); + + LoadConfiguration(); +} + +ConfigureInputAdvanced::~ConfigureInputAdvanced() = default; + +void ConfigureInputAdvanced::OnControllerButtonClick(int player_idx, int button_idx) { + const QColor new_bg_color = QColorDialog::getColor(controllers_colors[player_idx][button_idx]); + if (!new_bg_color.isValid()) { + return; + } + controllers_colors[player_idx][button_idx] = new_bg_color; + controllers_color_buttons[player_idx][button_idx]->setStyleSheet( + QStringLiteral("background-color: %1; min-width: 55px;") + .arg(controllers_colors[player_idx][button_idx].name())); +} + +void ConfigureInputAdvanced::ApplyConfiguration() { + for (std::size_t player_idx = 0; player_idx < controllers_color_buttons.size(); ++player_idx) { + auto& player = Settings::values.players[player_idx]; + std::array colors{}; + std::transform(controllers_colors[player_idx].begin(), controllers_colors[player_idx].end(), + colors.begin(), [](QColor color) { return color.rgb(); }); + + player.body_color_left = colors[0]; + player.button_color_left = colors[1]; + player.body_color_right = colors[2]; + player.button_color_right = colors[3]; + } + + 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 ConfigureInputAdvanced::LoadConfiguration() { + for (std::size_t player_idx = 0; player_idx < controllers_color_buttons.size(); ++player_idx) { + auto& player = Settings::values.players[player_idx]; + std::array colors = { + player.body_color_left, + player.button_color_left, + player.body_color_right, + player.button_color_right, + }; + + std::transform(colors.begin(), colors.end(), controllers_colors[player_idx].begin(), + [](u32 rgb) { return QColor::fromRgb(rgb); }); + + for (std::size_t button_idx = 0; button_idx < colors.size(); ++button_idx) { + controllers_color_buttons[player_idx][button_idx]->setStyleSheet( + QStringLiteral("background-color: %1; min-width: 55px;") + .arg(controllers_colors[player_idx][button_idx].name())); + } + } + + 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 ConfigureInputAdvanced::changeEvent(QEvent* event) { + if (event->type() == QEvent::LanguageChange) { + RetranslateUI(); + } + + QWidget::changeEvent(event); +} + +void ConfigureInputAdvanced::RetranslateUI() { + ui->retranslateUi(this); +} + +void ConfigureInputAdvanced::UpdateUIEnabled() { + ui->mouse_advanced->setEnabled(ui->mouse_enabled->isChecked()); + ui->debug_configure->setEnabled(ui->debug_enabled->isChecked()); + ui->touchscreen_advanced->setEnabled(ui->touchscreen_enabled->isChecked()); +} diff --git a/src/yuzu/configuration/configure_input_advanced.h b/src/yuzu/configuration/configure_input_advanced.h new file mode 100644 index 000000000..d6e913675 --- /dev/null +++ b/src/yuzu/configuration/configure_input_advanced.h @@ -0,0 +1,44 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +class QColor; +class QPushButton; + +namespace Ui { +class ConfigureInputAdvanced; +} + +class ConfigureInputAdvanced : public QWidget { + Q_OBJECT + +public: + explicit ConfigureInputAdvanced(QWidget* parent = nullptr); + ~ConfigureInputAdvanced() override; + + void ApplyConfiguration(); + +signals: + void CallDebugControllerDialog(); + void CallMouseConfigDialog(); + void CallTouchscreenConfigDialog(); + +private: + void changeEvent(QEvent* event) override; + void RetranslateUI(); + void UpdateUIEnabled(); + + void OnControllerButtonClick(int player_idx, int button_idx); + + void LoadConfiguration(); + + std::unique_ptr ui; + + std::array, 8> controllers_colors; + std::array, 8> controllers_color_buttons; +}; diff --git a/src/yuzu/configuration/configure_input_advanced.ui b/src/yuzu/configuration/configure_input_advanced.ui new file mode 100644 index 000000000..5958435fc --- /dev/null +++ b/src/yuzu/configuration/configure_input_advanced.ui @@ -0,0 +1,2688 @@ + + + ConfigureInputAdvanced + + + + 0 + 0 + 710 + 580 + + + + Configure Input + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 9 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 3 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Joycon Colors + + + + 9 + + + 9 + + + 9 + + + 9 + + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Player 1 + + + + 6 + + + 6 + + + 0 + + + 6 + + + 6 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + L Body + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + L Button + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + R Body + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + R Button + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + + + + + + + Player 2 + + + + 6 + + + 6 + + + 0 + + + 6 + + + 6 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + L Body + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + L Button + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + R Body + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + R Button + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Player 3 + + + + 6 + + + 6 + + + 0 + + + 6 + + + 6 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + L Body + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + L Button + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + R Body + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + R Button + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + + + + + + + Player 4 + + + + 6 + + + 6 + + + 0 + + + 6 + + + 6 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + L Body + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + L Button + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + R Body + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + R Button + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + + + + + + + + + + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Player 5 + + + + 6 + + + 6 + + + 0 + + + 6 + + + 6 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + L Body + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + L Button + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + R Body + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + R Button + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + + + + + + + Player 6 + + + + 6 + + + 6 + + + 0 + + + 6 + + + 6 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + L Body + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + L Button + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + R Body + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + R Button + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Player 7 + + + + 6 + + + 6 + + + 0 + + + 6 + + + 6 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + L Body + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + L Button + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + R Body + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + R Button + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + + + + + + + Player 8 + + + + 6 + + + 6 + + + 0 + + + 6 + + + 6 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + L Body + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + L Button + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + R Body + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + R Button + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Other + + + + + + + 0 + 23 + + + + Keyboard + + + + + + + Advanced + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 76 + 20 + + + + + + + + Advanced + + + + + + + Touchscreen + + + + + + + + 0 + 23 + + + + Mouse + + + + + + + Motion / Touch + + + + + + + Configure + + + + + + + Debug Controller + + + + + + + Configure + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + + + + + diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 597defe8c..4d79a51f3 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -5,38 +5,86 @@ #include #include #include -#include #include +#include #include #include #include #include #include "common/assert.h" #include "common/param_package.h" +#include "core/core.h" +#include "core/hle/service/hid/controllers/npad.h" +#include "core/hle/service/hid/hid.h" +#include "core/hle/service/sm/sm.h" #include "input_common/main.h" #include "ui_configure_input_player.h" #include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_input_player.h" +constexpr std::size_t HANDHELD_INDEX = 8; + const std::array ConfigureInputPlayer::analog_sub_buttons{{ "up", "down", "left", "right", - "modifier", }}; -static void LayerGridElements(QGridLayout* grid, QWidget* item, QWidget* onTopOf) { - const int index1 = grid->indexOf(item); - const int index2 = grid->indexOf(onTopOf); - int row, column, rowSpan, columnSpan; - grid->getItemPosition(index2, &row, &column, &rowSpan, &columnSpan); - grid->takeAt(index1); - grid->addWidget(item, row, column, rowSpan, columnSpan); +namespace { + +void UpdateController(Settings::ControllerType controller_type, std::size_t npad_index, + bool connected) { + Core::System& system{Core::System::GetInstance()}; + if (!system.IsPoweredOn()) { + return; + } + Service::SM::ServiceManager& sm = system.ServiceManager(); + + auto& npad = + sm.GetService("hid") + ->GetAppletResource() + ->GetController(Service::HID::HidController::NPad); + + npad.UpdateControllerAt(npad.MapSettingsTypeToNPad(controller_type), npad_index, connected); +} + +/// Maps the controller type combobox index to Controller Type enum +constexpr Settings::ControllerType GetControllerTypeFromIndex(int index) { + switch (index) { + case 0: + default: + return Settings::ControllerType::ProController; + case 1: + return Settings::ControllerType::DualJoyconDetached; + case 2: + return Settings::ControllerType::LeftJoycon; + case 3: + return Settings::ControllerType::RightJoycon; + case 4: + return Settings::ControllerType::Handheld; + } +} + +/// Maps the Controller Type enum to controller type combobox index +constexpr int GetIndexFromControllerType(Settings::ControllerType type) { + switch (type) { + case Settings::ControllerType::ProController: + default: + return 0; + case Settings::ControllerType::DualJoyconDetached: + return 1; + case Settings::ControllerType::LeftJoycon: + return 2; + case Settings::ControllerType::RightJoycon: + return 3; + case Settings::ControllerType::Handheld: + return 4; + } } -static QString GetKeyName(int key_code) { +QString GetKeyName(int key_code) { switch (key_code) { case Qt::Key_Shift: return QObject::tr("Shift"); @@ -51,9 +99,16 @@ static QString GetKeyName(int key_code) { } } -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") { +void SetAnalogParam(const Common::ParamPackage& input_param, Common::ParamPackage& analog_param, + const std::string& button_name) { + // The poller returned a complete axis, so set all the buttons + if (input_param.Has("axis_x") && input_param.Has("axis_y")) { + analog_param = input_param; + return; + } + // Check if the current configuration has either no engine or an axis binding. + // Clears out the old binding and adds one with analog_from_button. + if (!analog_param.Has("engine") || analog_param.Has("axis_x") || analog_param.Has("axis_y")) { analog_param = { {"engine", "analog_from_button"}, }; @@ -61,7 +116,7 @@ static void SetAnalogButton(const Common::ParamPackage& input_param, analog_param.Set(button_name, input_param.Serialize()); } -static QString ButtonToText(const Common::ParamPackage& param) { +QString ButtonToText(const Common::ParamPackage& param) { if (!param.Has("engine")) { return QObject::tr("[not set]"); } @@ -111,7 +166,7 @@ static QString ButtonToText(const Common::ParamPackage& param) { return QObject::tr("[unknown]"); } -static QString AnalogToText(const Common::ParamPackage& param, const std::string& dir) { +QString AnalogToText(const Common::ParamPackage& param, const std::string& dir) { if (!param.Has("engine")) { return QObject::tr("[not set]"); } @@ -161,22 +216,24 @@ static QString AnalogToText(const Common::ParamPackage& param, const std::string } return QObject::tr("[unknown]"); } +} // namespace -ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_index, bool debug) - : QDialog(parent), ui(std::make_unique()), player_index(player_index), +ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_index, + QWidget* bottom_row, bool debug) + : QWidget(parent), ui(std::make_unique()), player_index(player_index), debug(debug), timeout_timer(std::make_unique()), - poll_timer(std::make_unique()) { + poll_timer(std::make_unique()), bottom_row(bottom_row) { 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, + 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->buttonSL, ui->buttonSR, ui->buttonHome, ui->buttonScreenshot, + ui->buttonLStickMod, ui->buttonRStickMod, }; analog_map_buttons = {{ @@ -185,208 +242,159 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i ui->buttonLStickDown, ui->buttonLStickLeft, ui->buttonLStickRight, - ui->buttonLStickMod, }, { ui->buttonRStickUp, ui->buttonRStickDown, ui->buttonRStickLeft, ui->buttonRStickRight, - ui->buttonRStickMod, }, }}; - debug_hidden = { - ui->buttonSL, ui->labelSL, - ui->buttonSR, ui->labelSR, - ui->buttonLStick, ui->labelLStickPressed, - ui->buttonRStick, ui->labelRStickPressed, - ui->buttonHome, ui->labelHome, - ui->buttonScreenshot, ui->labelScreenshot, - }; - - auto layout = Settings::values.players[player_index].type; - if (debug) - layout = Settings::ControllerType::DualJoycon; - - switch (layout) { - case Settings::ControllerType::ProController: - case Settings::ControllerType::DualJoycon: - layout_hidden = { - ui->buttonSL, - ui->labelSL, - ui->buttonSR, - ui->labelSR, - }; - break; - case Settings::ControllerType::LeftJoycon: - layout_hidden = { - ui->right_body_button, - ui->right_buttons_button, - ui->right_body_label, - ui->right_buttons_label, - ui->buttonR, - ui->labelR, - ui->buttonZR, - ui->labelZR, - ui->labelHome, - ui->buttonHome, - ui->buttonPlus, - ui->labelPlus, - ui->RStick, - ui->faceButtons, - }; - break; - case Settings::ControllerType::RightJoycon: - layout_hidden = { - ui->left_body_button, ui->left_buttons_button, - ui->left_body_label, ui->left_buttons_label, - ui->buttonL, ui->labelL, - ui->buttonZL, ui->labelZL, - ui->labelScreenshot, ui->buttonScreenshot, - ui->buttonMinus, ui->labelMinus, - ui->LStick, ui->Dpad, - }; - break; - } - - if (debug || layout == Settings::ControllerType::ProController) { - ui->controller_color->hide(); - } else { - if (layout == Settings::ControllerType::LeftJoycon || - layout == Settings::ControllerType::RightJoycon) { - ui->horizontalSpacer_4->setGeometry({0, 0, 0, 0}); - - LayerGridElements(ui->buttons, ui->shoulderButtons, ui->Dpad); - LayerGridElements(ui->buttons, ui->misc, ui->RStick); - LayerGridElements(ui->buttons, ui->Dpad, ui->faceButtons); - LayerGridElements(ui->buttons, ui->RStick, ui->LStick); - } - } - - for (auto* widget : layout_hidden) - widget->setVisible(false); - - analog_map_stick = {ui->buttonLStickAnalog, ui->buttonRStickAnalog}; - analog_map_deadzone_and_modifier_slider = {ui->sliderLStickDeadzoneAndModifier, - ui->sliderRStickDeadzoneAndModifier}; - analog_map_deadzone_and_modifier_slider_label = {ui->labelLStickDeadzoneAndModifier, - ui->labelRStickDeadzoneAndModifier}; - - for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) { - auto* const button = button_map[button_id]; - if (button == nullptr) { - continue; - } - - button->setContextMenuPolicy(Qt::CustomContextMenu); + analog_map_deadzone_label = {ui->labelLStickDeadzone, ui->labelRStickDeadzone}; + analog_map_deadzone_slider = {ui->sliderLStickDeadzone, ui->sliderRStickDeadzone}; + analog_map_modifier_groupbox = {ui->buttonLStickModGroup, ui->buttonRStickModGroup}; + analog_map_modifier_button = {ui->buttonLStickMod, ui->buttonRStickMod}; + analog_map_modifier_label = {ui->labelLStickModifierRange, ui->labelRStickModifierRange}; + analog_map_modifier_slider = {ui->sliderLStickModifierRange, ui->sliderRStickModifierRange}; + analog_map_range_groupbox = {ui->buttonLStickRangeGroup, ui->buttonRStickRangeGroup}; + analog_map_range_spinbox = {ui->spinboxLStickRange, ui->spinboxRStickRange}; + + const auto ConfigureButtonClick = [&](QPushButton* button, Common::ParamPackage* param, + int default_val) { connect(button, &QPushButton::clicked, [=, this] { HandleClick( - button_map[button_id], + button, [=, this](Common::ParamPackage params) { - // Workaround for ZL & ZR for analog triggers like on XBOX controllors. - // Analog triggers (from controllers like the XBOX controller) would not - // work due to a different range of their signals (from 0 to 255 on - // analog triggers instead of -32768 to 32768 on analog joysticks). The - // SDL driver misinterprets analog triggers as analog joysticks. + // Workaround for ZL & ZR for analog triggers like on XBOX + // controllers. Analog triggers (from controllers like the XBOX + // controller) would not work due to a different range of their + // signals (from 0 to 255 on analog triggers instead of -32768 to + // 32768 on analog joysticks). The SDL driver misinterprets analog + // triggers as analog joysticks. // TODO: reinterpret the signal range for analog triggers to map the - // values correctly. This is required for the correct emulation of the - // analog triggers of the GameCube controller. - if (button_id == Settings::NativeButton::ZL || - button_id == Settings::NativeButton::ZR) { + // values correctly. This is required for the correct emulation of + // the analog triggers of the GameCube controller. + if (button == ui->buttonZL || button == ui->buttonZR) { params.Set("direction", "+"); params.Set("threshold", "0.5"); } - buttons_param[button_id] = std::move(params); + (*param) = std::move(params); }, InputCommon::Polling::DeviceType::Button); }); - connect(button, &QPushButton::customContextMenuRequested, - [=, this](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 (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) { + auto* const button = button_map[button_id]; + if (button == nullptr) { + continue; + } + ConfigureButtonClick(button_map[button_id], &buttons_param[button_id], + Config::default_buttons[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++) { + // Handle clicks for the modifier buttons as well. + ConfigureButtonClick(ui->buttonLStickMod, &lstick_mod, Config::default_lstick_mod); + ConfigureButtonClick(ui->buttonRStickMod, &rstick_mod, Config::default_rstick_mod); + + 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) { auto* const analog_button = analog_map_buttons[analog_id][sub_button_id]; + if (analog_button == nullptr) { continue; } - analog_button->setContextMenuPolicy(Qt::CustomContextMenu); connect(analog_button, &QPushButton::clicked, [=, this] { HandleClick( analog_map_buttons[analog_id][sub_button_id], [=, this](const Common::ParamPackage& params) { - SetAnalogButton(params, analogs_param[analog_id], - analog_sub_buttons[sub_button_id]); + SetAnalogParam(params, analogs_param[analog_id], + analog_sub_buttons[sub_button_id]); }, - InputCommon::Polling::DeviceType::Button); + InputCommon::Polling::DeviceType::AnalogPreferred); }); - connect(analog_button, &QPushButton::customContextMenuRequested, - [=, this](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::clicked, [=, this] { - if (QMessageBox::information( - this, tr("Information"), - tr("After pressing OK, first move your joystick horizontally, " - "and then vertically."), - QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) { - HandleClick( - analog_map_stick[analog_id], - [=, this](const Common::ParamPackage& params) { - analogs_param[analog_id] = params; - }, - InputCommon::Polling::DeviceType::Analog); - } + + connect(analog_map_modifier_button[analog_id], &QPushButton::clicked, [=, this] { + HandleClick( + analog_map_modifier_button[analog_id], + [=, this](const Common::ParamPackage& params) { + SetAnalogParam(params, analogs_param[analog_id], "modifier"); + }, + InputCommon::Polling::DeviceType::AnalogPreferred); }); - connect(analog_map_deadzone_and_modifier_slider[analog_id], &QSlider::valueChanged, + connect(analog_map_range_spinbox[analog_id], qOverload(&QSpinBox::valueChanged), [=, this] { - const float slider_value = - analog_map_deadzone_and_modifier_slider[analog_id]->value(); - if (analogs_param[analog_id].Get("engine", "") == "sdl" || - analogs_param[analog_id].Get("engine", "") == "gcpad") { - analog_map_deadzone_and_modifier_slider_label[analog_id]->setText( - tr("Deadzone: %1%").arg(slider_value)); - analogs_param[analog_id].Set("deadzone", slider_value / 100.0f); - } else { - analog_map_deadzone_and_modifier_slider_label[analog_id]->setText( - tr("Modifier Scale: %1%").arg(slider_value)); - analogs_param[analog_id].Set("modifier_scale", slider_value / 100.0f); - } + const auto spinbox_value = analog_map_range_spinbox[analog_id]->value(); + analogs_param[analog_id].Set("range", spinbox_value / 100.0f); }); + + connect(analog_map_deadzone_slider[analog_id], &QSlider::valueChanged, [=, this] { + const auto slider_value = analog_map_deadzone_slider[analog_id]->value(); + analog_map_deadzone_label[analog_id]->setText(tr("Deadzone: %1%").arg(slider_value)); + analogs_param[analog_id].Set("deadzone", slider_value / 100.0f); + }); + + connect(analog_map_modifier_slider[analog_id], &QSlider::valueChanged, [=, this] { + const auto slider_value = analog_map_modifier_slider[analog_id]->value(); + analog_map_modifier_label[analog_id]->setText( + tr("Modifier Range: %1%").arg(slider_value)); + analogs_param[analog_id].Set("modifier_scale", slider_value / 100.0f); + }); } - connect(ui->buttonClearAll, &QPushButton::clicked, [this] { ClearAll(); }); - connect(ui->buttonRestoreDefaults, &QPushButton::clicked, [this] { RestoreDefaults(); }); + // Player Connected checkbox + connect(ui->groupConnectedController, &QGroupBox::toggled, + [&](bool checked) { emit Connected(checked); }); + + // Set up controller type. Only Player 1 can choose Handheld. + ui->comboControllerType->clear(); + + QStringList controller_types = { + QStringLiteral("Pro Controller"), + QStringLiteral("Dual Joycons"), + QStringLiteral("Left Joycon"), + QStringLiteral("Right Joycon"), + }; + + if (player_index == 0) { + controller_types.append(QStringLiteral("Handheld")); + connect(ui->comboControllerType, qOverload(&QComboBox::currentIndexChanged), + [&](int index) { + emit HandheldStateChanged(GetControllerTypeFromIndex(index) == + Settings::ControllerType::Handheld); + }); + } + + // The Debug Controller can only choose the Pro Controller. + if (debug) { + ui->buttonScreenshot->setEnabled(false); + ui->buttonHome->setEnabled(false); + ui->groupConnectedController->setCheckable(false); + QStringList debug_controller_types = { + QStringLiteral("Pro Controller"), + }; + ui->comboControllerType->addItems(debug_controller_types); + } else { + ui->comboControllerType->addItems(controller_types); + } + + UpdateControllerIcon(); + UpdateControllerAvailableButtons(); + connect(ui->comboControllerType, qOverload(&QComboBox::currentIndexChanged), [&](int) { + UpdateControllerIcon(); + UpdateControllerAvailableButtons(); + }); + + connect(ui->comboDevices, qOverload(&QComboBox::currentIndexChanged), + [&] { UpdateMappingWithDefaults(); }); + + ui->buttonRefreshDevices->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh"))); + UpdateInputDevices(); + connect(ui->buttonRefreshDevices, &QPushButton::clicked, [&] { emit RefreshInputDevices(); }); timeout_timer->setSingleShot(true); connect(timeout_timer.get(), &QTimer::timeout, [this] { SetPollingResult({}, true); }); @@ -416,20 +424,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i } }); - controller_color_buttons = { - ui->left_body_button, - ui->left_buttons_button, - ui->right_body_button, - ui->right_buttons_button, - }; - - for (std::size_t i = 0; i < controller_color_buttons.size(); ++i) { - connect(controller_color_buttons[i], &QPushButton::clicked, this, - [this, i] { OnControllerButtonClick(static_cast(i)); }); - } - LoadConfiguration(); - resize(0, 0); // TODO(wwylele): enable this when we actually emulate it ui->buttonHome->setEnabled(false); @@ -438,27 +433,43 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i ConfigureInputPlayer::~ConfigureInputPlayer() = default; void ConfigureInputPlayer::ApplyConfiguration() { - auto& buttons = - debug ? Settings::values.debug_pad_buttons : Settings::values.players[player_index].buttons; - auto& analogs = - debug ? Settings::values.debug_pad_analogs : Settings::values.players[player_index].analogs; + auto& player = Settings::values.players[player_index]; + auto& buttons = debug ? Settings::values.debug_pad_buttons : player.buttons; + auto& analogs = debug ? Settings::values.debug_pad_analogs : player.analogs; std::transform(buttons_param.begin(), buttons_param.end(), buttons.begin(), [](const Common::ParamPackage& param) { return param.Serialize(); }); std::transform(analogs_param.begin(), analogs_param.end(), analogs.begin(), [](const Common::ParamPackage& param) { return param.Serialize(); }); - if (debug) + if (debug) { return; + } - std::array colors{}; - std::transform(controller_colors.begin(), controller_colors.end(), colors.begin(), - [](QColor color) { return color.rgb(); }); + player.controller_type = + static_cast(ui->comboControllerType->currentIndex()); + player.connected = ui->groupConnectedController->isChecked(); - Settings::values.players[player_index].body_color_left = colors[0]; - Settings::values.players[player_index].button_color_left = colors[1]; - Settings::values.players[player_index].body_color_right = colors[2]; - Settings::values.players[player_index].button_color_right = colors[3]; + // Player 2-8 + if (player_index != 0) { + UpdateController(player.controller_type, player_index, player.connected); + return; + } + + // Player 1 and Handheld + auto& handheld = Settings::values.players[HANDHELD_INDEX]; + // If Handheld is selected, copy all the settings from Player 1 to Handheld. + if (player.controller_type == Settings::ControllerType::Handheld) { + handheld = player; + handheld.connected = ui->groupConnectedController->isChecked(); + player.connected = false; // Disconnect Player 1 + } else { + player.connected = ui->groupConnectedController->isChecked(); + handheld.connected = false; // Disconnect Handheld + } + + UpdateController(player.controller_type, player_index, player.connected); + UpdateController(Settings::ControllerType::Handheld, HANDHELD_INDEX, handheld.connected); } void ConfigureInputPlayer::changeEvent(QEvent* event) { @@ -466,24 +477,16 @@ void ConfigureInputPlayer::changeEvent(QEvent* event) { RetranslateUI(); } - QDialog::changeEvent(event); + QWidget::changeEvent(event); } void ConfigureInputPlayer::RetranslateUI() { ui->retranslateUi(this); - UpdateButtonLabels(); -} - -void ConfigureInputPlayer::OnControllerButtonClick(int i) { - const QColor new_bg_color = QColorDialog::getColor(controller_colors[i]); - if (!new_bg_color.isValid()) - return; - controller_colors[i] = new_bg_color; - controller_color_buttons[i]->setStyleSheet( - QStringLiteral("QPushButton { background-color: %1 }").arg(controller_colors[i].name())); + UpdateUI(); } void ConfigureInputPlayer::LoadConfiguration() { + auto& player = Settings::values.players[player_index]; if (debug) { std::transform(Settings::values.debug_pad_buttons.begin(), Settings::values.debug_pad_buttons.end(), buttons_param.begin(), @@ -492,56 +495,53 @@ void ConfigureInputPlayer::LoadConfiguration() { Settings::values.debug_pad_analogs.end(), analogs_param.begin(), [](const std::string& str) { return Common::ParamPackage(str); }); } else { - std::transform(Settings::values.players[player_index].buttons.begin(), - Settings::values.players[player_index].buttons.end(), buttons_param.begin(), + std::transform(player.buttons.begin(), player.buttons.end(), buttons_param.begin(), [](const std::string& str) { return Common::ParamPackage(str); }); - std::transform(Settings::values.players[player_index].analogs.begin(), - Settings::values.players[player_index].analogs.end(), analogs_param.begin(), + std::transform(player.analogs.begin(), player.analogs.end(), analogs_param.begin(), [](const std::string& str) { return Common::ParamPackage(str); }); } - UpdateButtonLabels(); + UpdateUI(); - if (debug) + if (debug) { return; + } - std::array colors = { - Settings::values.players[player_index].body_color_left, - Settings::values.players[player_index].button_color_left, - Settings::values.players[player_index].body_color_right, - Settings::values.players[player_index].button_color_right, - }; - - std::transform(colors.begin(), colors.end(), controller_colors.begin(), - [](u32 rgb) { return QColor::fromRgb(rgb); }); + ui->comboControllerType->setCurrentIndex(static_cast(player.controller_type)); + ui->groupConnectedController->setChecked( + player.connected || + (player_index == 0 && Settings::values.players[HANDHELD_INDEX].connected)); +} - for (std::size_t i = 0; i < colors.size(); ++i) { - controller_color_buttons[i]->setStyleSheet( - QStringLiteral("QPushButton { background-color: %1 }") - .arg(controller_colors[i].name())); +void ConfigureInputPlayer::UpdateInputDevices() { + input_devices = InputCommon::GetInputDevices(); + ui->comboDevices->clear(); + for (auto device : input_devices) { + ui->comboDevices->addItem(QString::fromStdString(device.Get("display", "Unknown")), {}); } } void ConfigureInputPlayer::RestoreDefaults() { - for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) { + // Reset Buttons + 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])}; } - - 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++) { + // Reset Analogs + 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]); + SetAnalogParam(params, analogs_param[analog_id], analog_sub_buttons[sub_button_id]); } } - - UpdateButtonLabels(); - ApplyConfiguration(); + UpdateUI(); + UpdateInputDevices(); + ui->comboControllerType->setCurrentIndex(0); } void ConfigureInputPlayer::ClearAll() { - for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) { + for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) { const auto* const button = button_map[button_id]; if (button == nullptr || !button->isEnabled()) { continue; @@ -550,8 +550,8 @@ void ConfigureInputPlayer::ClearAll() { 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++) { + 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) { const auto* const analog_button = analog_map_buttons[analog_id][sub_button_id]; if (analog_button == nullptr || !analog_button->isEnabled()) { continue; @@ -561,17 +561,17 @@ void ConfigureInputPlayer::ClearAll() { } } - UpdateButtonLabels(); - ApplyConfiguration(); + UpdateUI(); + UpdateInputDevices(); } -void ConfigureInputPlayer::UpdateButtonLabels() { - for (int button = 0; button < Settings::NativeButton::NumButtons; button++) { +void ConfigureInputPlayer::UpdateUI() { + 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++) { + 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) { auto* const analog_button = analog_map_buttons[analog_id][sub_button_id]; if (analog_button == nullptr) { @@ -581,52 +581,75 @@ void ConfigureInputPlayer::UpdateButtonLabels() { analog_button->setText( AnalogToText(analogs_param[analog_id], analog_sub_buttons[sub_button_id])); } - analog_map_stick[analog_id]->setText(tr("Set Analog Stick")); + const auto deadzone_label = analog_map_deadzone_label[analog_id]; + const auto deadzone_slider = analog_map_deadzone_slider[analog_id]; + const auto modifier_groupbox = analog_map_modifier_groupbox[analog_id]; + const auto modifier_label = analog_map_modifier_label[analog_id]; + const auto modifier_slider = analog_map_modifier_slider[analog_id]; + const auto range_groupbox = analog_map_range_groupbox[analog_id]; + const auto range_spinbox = analog_map_range_spinbox[analog_id]; + + int slider_value; auto& param = analogs_param[analog_id]; - auto* const analog_stick_slider = analog_map_deadzone_and_modifier_slider[analog_id]; - auto* const analog_stick_slider_label = - analog_map_deadzone_and_modifier_slider_label[analog_id]; - - if (param.Has("engine")) { - if (param.Get("engine", "") == "sdl" || param.Get("engine", "") == "gcpad") { - if (!param.Has("deadzone")) { - param.Set("deadzone", 0.1f); - } - - analog_stick_slider->setValue(static_cast(param.Get("deadzone", 0.1f) * 100)); - if (analog_stick_slider->value() == 0) { - analog_stick_slider_label->setText(tr("Deadzone: 0%")); - } - } else { - if (!param.Has("modifier_scale")) { - param.Set("modifier_scale", 0.5f); - } - - analog_stick_slider->setValue( - static_cast(param.Get("modifier_scale", 0.5f) * 100)); - if (analog_stick_slider->value() == 0) { - analog_stick_slider_label->setText(tr("Modifier Scale: 0%")); - } + const bool is_controller = + param.Get("engine", "") == "sdl" || param.Get("engine", "") == "gcpad"; + + if (is_controller) { + if (!param.Has("deadzone")) { + param.Set("deadzone", 0.1f); } + slider_value = static_cast(param.Get("deadzone", 0.1f) * 100); + deadzone_label->setText(tr("Deadzone: %1%").arg(slider_value)); + deadzone_slider->setValue(slider_value); + if (!param.Has("range")) { + param.Set("range", 1.0f); + } + range_spinbox->setValue(static_cast(param.Get("range", 1.0f) * 100)); + } else { + if (!param.Has("modifier_scale")) { + param.Set("modifier_scale", 0.5f); + } + slider_value = static_cast(param.Get("modifier_scale", 0.5f) * 100); + modifier_label->setText(tr("Modifier Range: %1%").arg(slider_value)); + modifier_slider->setValue(slider_value); } + + deadzone_label->setVisible(is_controller); + deadzone_slider->setVisible(is_controller); + modifier_groupbox->setVisible(!is_controller); + modifier_label->setVisible(!is_controller); + modifier_slider->setVisible(!is_controller); + range_groupbox->setVisible(is_controller); } } +void ConfigureInputPlayer::UpdateMappingWithDefaults() { + if (ui->comboDevices->currentIndex() < 2) { + return; + } + const auto& device = input_devices[ui->comboDevices->currentIndex()]; + auto button_mapping = InputCommon::GetButtonMappingForDevice(device); + auto analog_mapping = InputCommon::GetAnalogMappingForDevice(device); + for (int i = 0; i < buttons_param.size(); ++i) { + buttons_param[i] = button_mapping[static_cast(i)]; + } + for (int i = 0; i < analogs_param.size(); ++i) { + analogs_param[i] = analog_mapping[static_cast(i)]; + } + + UpdateUI(); +} + void ConfigureInputPlayer::HandleClick( QPushButton* button, std::function new_input_setter, InputCommon::Polling::DeviceType type) { - button->setText(tr("[press key]")); + button->setText(tr("[waiting]")); button->setFocus(); - // Keyboard keys can only be used as button devices - want_keyboard_keys = type == InputCommon::Polling::DeviceType::Button; - if (want_keyboard_keys) { - const auto iter = std::find(button_map.begin(), button_map.end(), button); - ASSERT(iter != button_map.end()); - const auto index = std::distance(button_map.begin(), iter); - ASSERT(index < Settings::NativeButton::NumButtons && index >= 0); - } + // The first two input devices are always Any and Keyboard. If the user filtered to a + // controller, then they don't want keyboard input + want_keyboard_keys = ui->comboDevices->currentIndex() < 2; input_setter = new_input_setter; @@ -636,20 +659,17 @@ void ConfigureInputPlayer::HandleClick( poller->Start(); } - grabKeyboard(); - grabMouse(); if (type == InputCommon::Polling::DeviceType::Button) { InputCommon::GetGCButtons()->BeginConfiguration(); } else { InputCommon::GetGCAnalogs()->BeginConfiguration(); } - timeout_timer->start(5000); // Cancel after 5 seconds - poll_timer->start(200); // Check for new inputs every 200ms + + timeout_timer->start(2500); // Cancel after 2.5 seconds + poll_timer->start(50); // Check for new inputs every 50ms } void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params, bool abort) { - releaseKeyboard(); - releaseMouse(); timeout_timer->stop(); poll_timer->stop(); for (auto& poller : device_pollers) { @@ -663,7 +683,7 @@ void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params, (*input_setter)(params); } - UpdateButtonLabels(); + UpdateUI(); input_setter = std::nullopt; } @@ -683,3 +703,114 @@ void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) { } SetPollingResult({}, true); } + +void ConfigureInputPlayer::UpdateControllerIcon() { + // We aren't using Qt's built in theme support here since we aren't drawing an icon (and its + // "nonstandard" to use an image through the icon support) + QString stylesheet{}; + switch (GetControllerTypeFromIndex(ui->comboControllerType->currentIndex())) { + case Settings::ControllerType::ProController: + stylesheet = QStringLiteral("image: url(:/controller/pro_controller%0)"); + break; + case Settings::ControllerType::DualJoyconDetached: + stylesheet = QStringLiteral("image: url(:/controller/dual_joycon%0)"); + break; + case Settings::ControllerType::LeftJoycon: + stylesheet = QStringLiteral("image: url(:/controller/single_joycon_left_vertical%0)"); + break; + case Settings::ControllerType::RightJoycon: + stylesheet = QStringLiteral("image: url(:/controller/single_joycon_right_vertical%0)"); + break; + case Settings::ControllerType::Handheld: + stylesheet = QStringLiteral("image: url(:/controller/handheld%0)"); + break; + default: + break; + } + + const QString theme = [this] { + if (QIcon::themeName().contains(QStringLiteral("dark"))) { + return QStringLiteral("_dark"); + } else if (QIcon::themeName().contains(QStringLiteral("midnight"))) { + return QStringLiteral("_midnight"); + } else { + return QString{}; + } + }(); + + ui->controllerFrame->setStyleSheet(stylesheet.arg(theme)); +} + +void ConfigureInputPlayer::UpdateControllerAvailableButtons() { + auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); + if (debug) { + layout = Settings::ControllerType::DualJoyconDetached; + } + + // List of all the widgets that will be hidden by any of the following layouts that need + // "unhidden" after the controller type changes + const std::vector layout_show = { + ui->buttonShoulderButtonsSLSR, + ui->horizontalSpacerShoulderButtonsWidget, + ui->horizontalSpacerShoulderButtonsWidget2, + ui->buttonShoulderButtonsLeft, + ui->buttonMiscButtonsMinusScreenshot, + ui->bottomLeft, + ui->buttonShoulderButtonsRight, + ui->buttonMiscButtonsPlusHome, + ui->bottomRight, + }; + + for (auto* widget : layout_show) { + widget->show(); + } + + std::vector layout_hidden; + switch (layout) { + case Settings::ControllerType::ProController: + layout_hidden = { + ui->buttonShoulderButtonsSLSR, + ui->horizontalSpacerShoulderButtonsWidget2, + }; + break; + case Settings::ControllerType::DualJoyconDetached: + case Settings::ControllerType::Handheld: + layout_hidden = { + ui->buttonShoulderButtonsSLSR, + ui->horizontalSpacerShoulderButtonsWidget2, + }; + break; + case Settings::ControllerType::LeftJoycon: + layout_hidden = { + ui->horizontalSpacerShoulderButtonsWidget2, + ui->buttonShoulderButtonsRight, + ui->buttonMiscButtonsPlusHome, + ui->bottomRight, + }; + break; + case Settings::ControllerType::RightJoycon: + layout_hidden = { + ui->horizontalSpacerShoulderButtonsWidget, + ui->buttonShoulderButtonsLeft, + ui->buttonMiscButtonsMinusScreenshot, + ui->bottomLeft, + }; + break; + } + + for (auto* widget : layout_hidden) { + widget->hide(); + } +} + +void ConfigureInputPlayer::showEvent(QShowEvent* event) { + if (bottom_row == nullptr) { + return; + } + QWidget::showEvent(event); + ui->main->addWidget(bottom_row); +} + +void ConfigureInputPlayer::ConnectPlayer(bool connected) { + ui->groupConnectedController->setChecked(connected); +} diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h index 95afa5375..a86db8200 100644 --- a/src/yuzu/configuration/configure_input_player.h +++ b/src/yuzu/configuration/configure_input_player.h @@ -15,11 +15,17 @@ #include "common/param_package.h" #include "core/settings.h" #include "ui_configure_input.h" +#include "yuzu/uisettings.h" +class QCheckBox; class QKeyEvent; +class QLabel; class QPushButton; +class QSlider; +class QSpinBox; class QString; class QTimer; +class QWidget; namespace InputCommon::Polling { class DevicePoller; @@ -30,43 +36,73 @@ namespace Ui { class ConfigureInputPlayer; } -class ConfigureInputPlayer : public QDialog { +class ConfigureInputPlayer : public QWidget { Q_OBJECT public: - explicit ConfigureInputPlayer(QWidget* parent, std::size_t player_index, bool debug = false); + explicit ConfigureInputPlayer(QWidget* parent, std::size_t player_index, QWidget* bottom_row, + bool debug = false); ~ConfigureInputPlayer() override; - /// Save all button configurations to settings file + /// Save all button configurations to settings file. void ApplyConfiguration(); + /// Update the input devices combobox. + void UpdateInputDevices(); + + /// Restore all buttons to their default values. + void RestoreDefaults(); + + /// Clear all input configuration. + void ClearAll(); + + /// Set the connection state checkbox (used to sync state). + void ConnectPlayer(bool connected); + +signals: + /// Emitted when this controller is connected by the user. + void Connected(bool connected); + /// Emitted when the Handheld mode is selected (undocked with dual joycons attached). + void HandheldStateChanged(bool is_handheld); + /// Emitted when the input devices combobox is being refreshed. + void RefreshInputDevices(); + +protected: + void showEvent(QShowEvent* event) override; + private: void changeEvent(QEvent* event) override; void RetranslateUI(); - void OnControllerButtonClick(int i); - /// 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(); /// 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 + /// 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; + /// Update UI to reflect current configuration. + void UpdateUI(); + + /// Update the controller selection combobox + void UpdateControllerCombobox(); + + /// Update the current controller icon. + void UpdateControllerIcon(); + + /// Hides and disables controller settings based on the current controller type. + void UpdateControllerAvailableButtons(); + + /// Gets the default controller mapping for this device and auto configures the input to match. + void UpdateMappingWithDefaults(); + std::unique_ptr ui; std::size_t player_index; @@ -75,32 +111,38 @@ private: std::unique_ptr timeout_timer; std::unique_ptr poll_timer; + static constexpr int PLAYER_COUNT = 8; + std::array player_connected_checkbox; + /// 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; + static constexpr int ANALOG_SUB_BUTTONS_NUM = 4; + // Adds room for two extra push buttons LStick Modifier and RStick Modifier. + static constexpr int BUTTON_MAP_COUNT = Settings::NativeButton::NumButtons + 2; /// Each button input is represented by a QPushButton. - std::array button_map; - - std::vector debug_hidden; - std::vector layout_hidden; + std::array button_map; + /// Extra buttons for the modifiers. + Common::ParamPackage lstick_mod; + Common::ParamPackage rstick_mod; - /// A group of five QPushButtons represent one analog input. The buttons each represent up, - /// down, left, right, and modifier, respectively. + /// A group of four QPushButtons represent one analog input. The buttons each represent up, + /// down, left, right, 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; - std::array - analog_map_deadzone_and_modifier_slider; - std::array - analog_map_deadzone_and_modifier_slider_label; + std::array analog_map_deadzone_label; + std::array analog_map_deadzone_slider; + std::array analog_map_modifier_groupbox; + std::array analog_map_modifier_button; + std::array analog_map_modifier_label; + std::array analog_map_modifier_slider; + std::array analog_map_range_groupbox; + std::array analog_map_range_spinbox; static const std::array analog_sub_buttons; @@ -110,6 +152,12 @@ private: /// keyboard events are ignored. bool want_keyboard_keys = false; - std::array controller_color_buttons; - std::array controller_colors; + /// List of physical devices users can map with. If a SDL backed device is selected, then you + /// can usue this device to get a default mapping. + std::vector input_devices; + + /// Bottom row is where console wide settings are held, and its "owned" by the parent + /// ConfigureInput widget. On show, add this widget to the main layout. This will change the + /// parent of the widget to this widget (but thats fine). + QWidget* bottom_row; }; diff --git a/src/yuzu/configuration/configure_input_player.ui b/src/yuzu/configuration/configure_input_player.ui index f27a77180..eb826a935 100644 --- a/src/yuzu/configuration/configure_input_player.ui +++ b/src/yuzu/configuration/configure_input_player.ui @@ -1,1243 +1,2974 @@ ConfigureInputPlayer - + 0 0 - 408 - 731 + 780 + 487 Configure Input - + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + - - - - - Right Stick - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - false + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 3 - - false + + 0 - - - + + + + Qt::LeftToRight + + + Connect Controller + + + false + + + true + + + + 5 + + + 5 + + + 5 + + + 5 + - + - - - Down: - - + + Pro Controller + - - - - - - - - - - - - - - - - - - Right: - - + + Dual Joycons + - - - - - - - - - - - - - - - Set Analog Stick - - - - - - - - - - Left: - - + + Left Joycon + - - - - - - - - - - - - - - - - - - Up: - - + + Right Joycon + - - - - - - - - - - - - - - - - - - Pressed: - - + + Handheld + - - - - - - - - - - + + + + + + Input Device + + + + 3 + + + 5 + + + 5 + + + 5 + + + 5 + - + - - - Modifier: - - + + Any + - - - - - - - - - - - - - - - - - - Deadzone: 0 - - - Qt::AlignHCenter - - + + Keyboard + - + - - - Qt::Horizontal + + + + 24 + 22 + + + + + 24 + 22 + + + + - - - - - Qt::Vertical + + + + + + + 0 + 0 + + + + Profile + + + + 3 - - - 0 - 0 - + + 5 + + + 5 + + + 5 + + + 5 - - - -
- - - - - Directional Pad - - - false - - - false - - - - - - - - - Up: - - - - + - - - + + + + 55 + 16777215 + + + + min-width: 55px; - - - - - - - - - - - - Down: - - - - - - - - + Save - - - - - - - - - - - 80 - 0 - - - - Left: - - - - - - + + + + 55 + 16777215 + + + + min-width: 55px; + - + New - - - - - - - - - - - 80 - 0 - - - - Right: - - - - - - + + + + 55 + 16777215 + + + + min-width: 55px; + - + Delete - - - +
+ + - - - - Face Buttons - - - false - - - false + + + + + 0 + 0 + - - - - - - - - - - 80 - 0 - + + + QLayout::SetMinimumSize + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + QLayout::SetDefaultConstraint + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + Left Stick + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + 0 - - A: + + QLayout::SetDefaultConstraint - - - - - - - - - - - - - - - - - - - - - - 80 - 0 - + + 3 - - B: + + 0 - - - - - - - - - - - - - - - - - - - - - X: + + 3 - - - - - - - - - - - - - - - - - - - - - Y: + + 0 - - - - - - - - - - - - - - - - - - - - Controller Color - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Left Body - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 90 - 0 - - - - Left Buttons - - - - - - - - 0 - 0 - - - - - 32 - 0 - - - - - 40 - 16777215 - - - - - - - - - - - Right Body - - - - - - - - 90 - 0 - - - - Right Buttons - - - - - - - - 0 - 0 - - - - - 32 - 0 - - - - - 40 - 16777215 - - - - - - - - - - - - 0 - 0 - - - - - 32 - 0 - - - - - 40 - 16777215 - - - - - - - - - - - - 0 - 0 - - - - - 32 - 0 - - - - - 40 - 16777215 - - - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 20 - 20 - - - - - - - - - - - Left Stick - - - false - - - false - - - - - - - - - - Up: + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + Up + + + Qt::AlignCenter + + + false + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + Up + + + + + + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + + + + 3 + + + + + Left + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + Left + + + + + + + + + + Right + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + Right + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + Down + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + Down + + + + + + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + + + + 3 + + + + + Pressed + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + Pressed + + + + + + + + + + Modifier + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + Modifier + + + + + + + + + + Range + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 55 + 21 + + + + + 55 + 16777215 + + + + % + + + 50 + + + 150 + + + 100 + + + + + + + + + + + + 3 + + + QLayout::SetDefaultConstraint + + + 0 + + + 2 + + + 0 + + + 3 + + + + + + + Deadzone: 0% + + + Qt::AlignHCenter + + + + + + + + + 100 + + + Qt::Horizontal + + + + + + + + + Modifier Range: 0% + + + Qt::AlignHCenter + + + + + + + + + 100 + + + Qt::Horizontal + + + + + + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + + 0 + 0 + + + + D-Pad + + + false + + + false + + + + 0 - - - - - - - - - - - - - - - - - - - - - Right: + + 3 - - - - - - - - - - - - - - - - - Set Analog Stick - - - - - - - - - - - Left: + + 0 - - - - - - - - - - - - - - - - - - - - - Down: + + 3 - - - - - - - - - - - - - - - - - - - - - Modifier: + + 3 - - - - - - - - - - - - + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + Up + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + Up + + + + + + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + + + + 3 + + + + + Left + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + Left + + + + + + + + + + Right + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + Right + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + Down + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + Down + + + + + + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + - - - - - - - - Pressed: + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 3 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + L + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + L + + + + + + + + + + ZL + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + ZL + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 0 + 20 + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Minus + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + Minus + + + + + + + + + + Capture + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + Capture + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Plus + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + Plus + + + + + + + + + + Home + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + Home + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 0 + 20 + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + R + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + R + + + + + + + + + + ZR + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + ZR + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 0 + 20 + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + SL + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + SL + + + + + + + + + + SR + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + SR + + + + + + + + + + + + + + + + 0 + 0 + + + + + 75 + true + + + + image: url(:/controller/pro); + + + + 0 - - - - - - - - - - - - - - - - - QLayout::SetDefaultConstraint - - - - - - - Deadzone: 0 + + 0 - - Qt::AlignHCenter + + 0 - - - - - - - - Qt::Horizontal - - - - - - - - - Qt::Vertical - - - - 0 - 0 - - - - - - - - - - - Shoulder Buttons - - - false - - - false - - - - - - - - - - L: + + 0 - - - - - - - - - - - - + + + + + + + 3 + + + + + Qt::Horizontal + + + + 40 + 0 + + + + + + + + Qt::Horizontal + + + + 40 + 0 + + + + + + + + - - - - - - - - R: + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + Face Buttons + + + false + + + false + + + + 0 - - - - - - - - - - - - - - - - - - - - - ZL: + + 3 - - - - - - - - - - - - - - - - - - - - - ZR: + + 0 - - - - - - - - - - - - - - - - - - - - - SL: + + 3 - - - - - - - - - - - - - - - - - - - - - SR: + + 3 - - - - - - - - - - - - - - - - - - - - Misc. - - - false - - - false - - - - - - - - - - Minus: + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + X + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + X + + + + + + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + + + + 3 + + + + + Y + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + Y + + + + + + + + + + A + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + A + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + B + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + B + + + + + + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + + 0 + 0 + + + + Right Stick + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + false + + + false + + + + 0 - - - - - - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - Plus: + + 3 - - - - - - - - - - - - - - - - - - - - - Home: + + 0 - - - - - - - - - - - - - - - - - - - - - Screen Capture: + + 3 - - false + + 0 - - - - - - - - - 0 - 0 - - - - - 80 - 16777215 - - - - - - - - + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + Up + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + Up + + + + + + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + + + + 3 + + + + + Left + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + Left + + + + + + + + + + Right + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + Right + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + Down + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + Down + + + + + + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + + + + 3 + + + + + Pressed + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + Pressed + + + + + + + + + + Modifier + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 57 + 0 + + + + + 55 + 16777215 + + + + min-width: 55px; + + + Modifier + + + + + + + + + + Range + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 55 + 21 + + + + + 55 + 16777215 + + + + % + + + 50 + + + 150 + + + 100 + + + + + + + + + + + + 3 + + + 0 + + + 2 + + + 0 + + + 3 + + + + + + + Deadzone: 0% + + + Qt::AlignHCenter + + + + + + + + + 100 + + + Qt::Horizontal + + + + + + + + + Modifier Range: 0% + + + Qt::AlignHCenter + + + + + + + + + 100 + + + Qt::Horizontal + + + + + + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 0 - 0 - - - - Qt::LeftToRight - - - Clear All - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 0 - 0 - - - - Qt::LeftToRight - - - Restore Defaults - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - buttonBox - accepted() - ConfigureInputPlayer - accept() - - - 371 - 730 - - - 229 - 375 - - - - - buttonBox - rejected() - ConfigureInputPlayer - reject() - - - 371 - 730 - - - 229 - 375 - - - - + + + + diff --git a/src/yuzu/configuration/configure_input_simple.cpp b/src/yuzu/configuration/configure_input_simple.cpp deleted file mode 100644 index 0e0e8f113..000000000 --- a/src/yuzu/configuration/configure_input_simple.cpp +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include - -#include "ui_configure_input_simple.h" -#include "yuzu/configuration/configure_input.h" -#include "yuzu/configuration/configure_input_player.h" -#include "yuzu/configuration/configure_input_simple.h" -#include "yuzu/uisettings.h" - -namespace { - -template -void CallConfigureDialog(ConfigureInputSimple* caller, Args&&... args) { - caller->ApplyConfiguration(); - Dialog dialog(caller, std::forward(args)...); - - const auto res = dialog.exec(); - if (res == QDialog::Accepted) { - dialog.ApplyConfiguration(); - } -} - -// OnProfileSelect functions should (when applicable): -// - Set controller types -// - Set controller enabled -// - Set docked mode -// - Set advanced controller config/enabled (i.e. debug, kbd, mouse, touch) -// -// OnProfileSelect function should NOT however: -// - Reset any button mappings -// - Open any dialogs -// - Block in any way - -constexpr std::size_t PLAYER_0_INDEX = 0; -constexpr std::size_t HANDHELD_INDEX = 8; - -void HandheldOnProfileSelect() { - Settings::values.players[HANDHELD_INDEX].connected = true; - Settings::values.players[HANDHELD_INDEX].type = Settings::ControllerType::DualJoycon; - - for (std::size_t player = 0; player < HANDHELD_INDEX; ++player) { - Settings::values.players[player].connected = false; - } - - Settings::values.use_docked_mode = false; - Settings::values.keyboard_enabled = false; - Settings::values.mouse_enabled = false; - Settings::values.debug_pad_enabled = false; - Settings::values.touchscreen.enabled = true; -} - -void DualJoyconsDockedOnProfileSelect() { - Settings::values.players[PLAYER_0_INDEX].connected = true; - Settings::values.players[PLAYER_0_INDEX].type = Settings::ControllerType::DualJoycon; - - for (std::size_t player = 1; player <= HANDHELD_INDEX; ++player) { - Settings::values.players[player].connected = false; - } - - Settings::values.use_docked_mode = true; - Settings::values.keyboard_enabled = false; - Settings::values.mouse_enabled = false; - Settings::values.debug_pad_enabled = false; - Settings::values.touchscreen.enabled = true; -} - -// Name, OnProfileSelect (called when selected in drop down), OnConfigure (called when configure -// is clicked) -using InputProfile = std::tuple; - -constexpr std::array INPUT_PROFILES{{ - {QT_TR_NOOP("Single Player - Handheld - Undocked"), HandheldOnProfileSelect, - [](ConfigureInputSimple* caller) { - CallConfigureDialog(caller, HANDHELD_INDEX, false); - }}, - {QT_TR_NOOP("Single Player - Dual Joycons - Docked"), DualJoyconsDockedOnProfileSelect, - [](ConfigureInputSimple* caller) { - CallConfigureDialog(caller, PLAYER_0_INDEX, false); - }}, - {QT_TR_NOOP("Custom"), [] {}, CallConfigureDialog}, -}}; - -} // namespace - -void ApplyInputProfileConfiguration(int profile_index) { - std::get<1>( - INPUT_PROFILES.at(std::min(profile_index, static_cast(INPUT_PROFILES.size() - 1))))(); -} - -ConfigureInputSimple::ConfigureInputSimple(QWidget* parent) - : QWidget(parent), ui(std::make_unique()) { - ui->setupUi(this); - - for (const auto& profile : INPUT_PROFILES) { - const QString label = tr(std::get<0>(profile)); - ui->profile_combobox->addItem(label, label); - } - - connect(ui->profile_combobox, QOverload::of(&QComboBox::currentIndexChanged), this, - &ConfigureInputSimple::OnSelectProfile); - connect(ui->profile_configure, &QPushButton::clicked, this, &ConfigureInputSimple::OnConfigure); - - LoadConfiguration(); -} - -ConfigureInputSimple::~ConfigureInputSimple() = default; - -void ConfigureInputSimple::ApplyConfiguration() { - auto index = ui->profile_combobox->currentIndex(); - // Make the stored index for "Custom" very large so that if new profiles are added it - // doesn't change. - if (index >= static_cast(INPUT_PROFILES.size() - 1)) { - index = std::numeric_limits::max(); - } - - UISettings::values.profile_index = index; -} - -void ConfigureInputSimple::changeEvent(QEvent* event) { - if (event->type() == QEvent::LanguageChange) { - RetranslateUI(); - } - - QWidget::changeEvent(event); -} - -void ConfigureInputSimple::RetranslateUI() { - ui->retranslateUi(this); -} - -void ConfigureInputSimple::LoadConfiguration() { - const auto index = UISettings::values.profile_index; - if (index >= static_cast(INPUT_PROFILES.size()) || index < 0) { - ui->profile_combobox->setCurrentIndex(static_cast(INPUT_PROFILES.size() - 1)); - } else { - ui->profile_combobox->setCurrentIndex(index); - } -} - -void ConfigureInputSimple::OnSelectProfile(int index) { - const auto old_docked = Settings::values.use_docked_mode; - ApplyInputProfileConfiguration(index); - OnDockedModeChanged(old_docked, Settings::values.use_docked_mode); -} - -void ConfigureInputSimple::OnConfigure() { - std::get<2>(INPUT_PROFILES.at(ui->profile_combobox->currentIndex()))(this); -} diff --git a/src/yuzu/configuration/configure_input_simple.h b/src/yuzu/configuration/configure_input_simple.h deleted file mode 100644 index bb5050224..000000000 --- a/src/yuzu/configuration/configure_input_simple.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include - -#include - -class QPushButton; -class QString; -class QTimer; - -namespace Ui { -class ConfigureInputSimple; -} - -// Used by configuration loader to apply a profile if the input is invalid. -void ApplyInputProfileConfiguration(int profile_index); - -class ConfigureInputSimple : public QWidget { - Q_OBJECT - -public: - explicit ConfigureInputSimple(QWidget* parent = nullptr); - ~ConfigureInputSimple() override; - - /// Save all button configurations to settings file - void ApplyConfiguration(); - -private: - void changeEvent(QEvent* event) override; - void RetranslateUI(); - - /// Load configuration settings. - void LoadConfiguration(); - - void OnSelectProfile(int index); - void OnConfigure(); - - std::unique_ptr ui; -}; diff --git a/src/yuzu/configuration/configure_input_simple.ui b/src/yuzu/configuration/configure_input_simple.ui deleted file mode 100644 index c4889caa9..000000000 --- a/src/yuzu/configuration/configure_input_simple.ui +++ /dev/null @@ -1,97 +0,0 @@ - - - ConfigureInputSimple - - - - 0 - 0 - 473 - 685 - - - - ConfigureInputSimple - - - - - - - - Profile - - - - - - Configure - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 250 - 0 - - - - - - - - Choose a controller configuration: - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - diff --git a/src/yuzu/configuration/configure_mouse_advanced.cpp b/src/yuzu/configuration/configure_mouse_advanced.cpp index 5bcf5ffa8..95e1ae873 100644 --- a/src/yuzu/configuration/configure_mouse_advanced.cpp +++ b/src/yuzu/configuration/configure_mouse_advanced.cpp @@ -205,15 +205,11 @@ void ConfigureMouseAdvanced::HandleClick( poller->Start(); } - grabKeyboard(); - grabMouse(); - timeout_timer->start(5000); // Cancel after 5 seconds - poll_timer->start(200); // Check for new inputs every 200ms + timeout_timer->start(2500); // Cancel after 2.5 seconds + poll_timer->start(50); // Check for new inputs every 50ms } void ConfigureMouseAdvanced::SetPollingResult(const Common::ParamPackage& params, bool abort) { - releaseKeyboard(); - releaseMouse(); timeout_timer->stop(); poll_timer->stop(); for (auto& poller : device_pollers) { diff --git a/src/yuzu/configuration/configure_mouse_advanced.ui b/src/yuzu/configuration/configure_mouse_advanced.ui index 08245ecf0..74552fdbd 100644 --- a/src/yuzu/configuration/configure_mouse_advanced.ui +++ b/src/yuzu/configuration/configure_mouse_advanced.ui @@ -6,13 +6,18 @@ 0 0 - 250 - 261 + 310 + 193 Configure Mouse + + QPushButton { + min-width: 55px; +} + @@ -20,81 +25,33 @@ Mouse Buttons - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 20 - 20 - - - - - - + + - + - + - Right: + Forward: - + - 75 + 57 0 - - + + + 16777215 + 16777215 + - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 20 - 20 - - - - - - - - - - - - Middle: - - - - - - - @@ -123,6 +80,12 @@ + + + 57 + 0 + + @@ -147,7 +110,7 @@ - 75 + 57 0 @@ -158,21 +121,99 @@ - - + + - + - + - Forward: + Middle: - + + + + 57 + 0 + + + + + 16777215 + 16777215 + + + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 0 + 20 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 0 + 20 + + + + + + + + + + + + Right: + + + + + + + + + + 57 + 0 + + + + + 16777215 + 16777215 + + @@ -180,6 +221,32 @@ + + + + Qt::Horizontal + + + + 0 + 20 + + + + + + + + Qt::Horizontal + + + + 0 + 20 + + + + @@ -187,15 +254,39 @@ + + + 57 + 0 + + + + + 16777215 + 16777215 + + - Clear All + Clear + + + 57 + 0 + + + + + 16777215 + 16777215 + + - Restore Defaults + Defaults @@ -206,21 +297,24 @@ - 40 + 0 20 + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + - - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - diff --git a/src/yuzu/uisettings.cpp b/src/yuzu/uisettings.cpp index a51175f36..37499fc85 100644 --- a/src/yuzu/uisettings.cpp +++ b/src/yuzu/uisettings.cpp @@ -16,4 +16,5 @@ const Themes themes{{ }}; Values values = {}; + } // namespace UISettings diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index 2d2e82f15..533815098 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h @@ -13,6 +13,7 @@ #include #include #include "common/common_types.h" +#include "core/settings.h" namespace UISettings { @@ -87,9 +88,6 @@ struct Values { // logging bool show_console; - // Controllers - int profile_index; - // Game List bool show_add_ons; uint32_t icon_size; @@ -100,6 +98,7 @@ struct Values { }; extern Values values; + } // namespace UISettings Q_DECLARE_METATYPE(UISettings::GameDir*); -- cgit v1.2.3