diff --git a/src/citra/config.cpp b/src/citra/config.cpp index bb7b0325f..3372f2d7a 100644 --- a/src/citra/config.cpp +++ b/src/citra/config.cpp @@ -71,33 +71,35 @@ static const std::array, Settings::NativeAnalog::NumAnalogs> void Config::ReadValues() { // Controls + // TODO: add multiple input profile support for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); - Settings::values.buttons[i] = + Settings::values.current_input_profile.buttons[i] = sdl2_config->GetString("Controls", Settings::NativeButton::mapping[i], default_param); - if (Settings::values.buttons[i].empty()) - Settings::values.buttons[i] = default_param; + if (Settings::values.current_input_profile.buttons[i].empty()) + Settings::values.current_input_profile.buttons[i] = default_param; } for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { std::string default_param = InputCommon::GenerateAnalogParamFromKeys( default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], default_analogs[i][3], default_analogs[i][4], 0.5f); - Settings::values.analogs[i] = + Settings::values.current_input_profile.analogs[i] = sdl2_config->GetString("Controls", Settings::NativeAnalog::mapping[i], default_param); - if (Settings::values.analogs[i].empty()) - Settings::values.analogs[i] = default_param; + if (Settings::values.current_input_profile.analogs[i].empty()) + Settings::values.current_input_profile.analogs[i] = default_param; } - Settings::values.motion_device = sdl2_config->GetString( + Settings::values.current_input_profile.motion_device = sdl2_config->GetString( "Controls", "motion_device", "engine:motion_emu,update_period:100,sensitivity:0.01,tilt_clamp:90.0"); - Settings::values.touch_device = + Settings::values.current_input_profile.touch_device = sdl2_config->GetString("Controls", "touch_device", "engine:emu_window"); - Settings::values.udp_input_address = sdl2_config->GetString( + Settings::values.current_input_profile.udp_input_address = sdl2_config->GetString( "Controls", "udp_input_address", InputCommon::CemuhookUDP::DEFAULT_ADDR); - Settings::values.udp_input_port = static_cast(sdl2_config->GetInteger( - "Controls", "udp_input_port", InputCommon::CemuhookUDP::DEFAULT_PORT)); + Settings::values.current_input_profile.udp_input_port = + static_cast(sdl2_config->GetInteger("Controls", "udp_input_port", + InputCommon::CemuhookUDP::DEFAULT_PORT)); // Core Settings::values.use_cpu_jit = sdl2_config->GetBoolean("Core", "use_cpu_jit", true); diff --git a/src/citra_qt/configuration/config.cpp b/src/citra_qt/configuration/config.cpp index f597a5fa5..19e94715c 100644 --- a/src/citra_qt/configuration/config.cpp +++ b/src/citra_qt/configuration/config.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include #include #include "citra_qt/configuration/config.h" @@ -51,43 +52,69 @@ const std::array, Settings::NativeAnalog::NumAnalogs> Config: void Config::ReadValues() { qt_config->beginGroup("Controls"); - for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { - std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); - Settings::values.buttons[i] = - ReadSetting(Settings::NativeButton::mapping[i], QString::fromStdString(default_param)) + + Settings::values.current_input_profile_index = ReadSetting("profile", 0).toInt(); + + const auto append_profile = [this] { + Settings::InputProfile profile; + profile.name = ReadSetting("name", "default").toString().toStdString(); + for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { + std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); + profile.buttons[i] = ReadSetting(Settings::NativeButton::mapping[i], + QString::fromStdString(default_param)) + .toString() + .toStdString(); + if (profile.buttons[i].empty()) + profile.buttons[i] = default_param; + } + for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { + std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], + default_analogs[i][3], default_analogs[i][4], 0.5f); + profile.analogs[i] = ReadSetting(Settings::NativeAnalog::mapping[i], + QString::fromStdString(default_param)) + .toString() + .toStdString(); + if (profile.analogs[i].empty()) + profile.analogs[i] = default_param; + } + profile.motion_device = + ReadSetting("motion_device", + "engine:motion_emu,update_period:100,sensitivity:0.01,tilt_clamp:90.0") .toString() .toStdString(); - if (Settings::values.buttons[i].empty()) - Settings::values.buttons[i] = default_param; - } - - for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { - std::string default_param = InputCommon::GenerateAnalogParamFromKeys( - default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], - default_analogs[i][3], default_analogs[i][4], 0.5f); - Settings::values.analogs[i] = - ReadSetting(Settings::NativeAnalog::mapping[i], QString::fromStdString(default_param)) + profile.touch_device = + ReadSetting("touch_device", "engine:emu_window").toString().toStdString(); + profile.udp_input_address = + ReadSetting("udp_input_address", InputCommon::CemuhookUDP::DEFAULT_ADDR) .toString() .toStdString(); - if (Settings::values.analogs[i].empty()) - Settings::values.analogs[i] = default_param; + profile.udp_input_port = static_cast( + ReadSetting("udp_input_port", InputCommon::CemuhookUDP::DEFAULT_PORT).toInt()); + profile.udp_pad_index = static_cast(ReadSetting("udp_pad_index", 0).toUInt()); + Settings::values.input_profiles.emplace_back(std::move(profile)); + }; + + int num_input_profiles = qt_config->beginReadArray("profiles"); + + for (int i = 0; i < num_input_profiles; ++i) { + qt_config->setArrayIndex(i); + append_profile(); } - Settings::values.motion_device = - ReadSetting("motion_device", - "engine:motion_emu,update_period:100,sensitivity:0.01,tilt_clamp:90.0") - .toString() - .toStdString(); - Settings::values.touch_device = - ReadSetting("touch_device", "engine:emu_window").toString().toStdString(); + qt_config->endArray(); - Settings::values.udp_input_address = - ReadSetting("udp_input_address", InputCommon::CemuhookUDP::DEFAULT_ADDR) - .toString() - .toStdString(); - Settings::values.udp_input_port = static_cast( - ReadSetting("udp_input_port", InputCommon::CemuhookUDP::DEFAULT_PORT).toInt()); - Settings::values.udp_pad_index = static_cast(ReadSetting("udp_pad_index", 0).toUInt()); + // create a input profile if no input profiles exist, with the default or old settings + if (num_input_profiles == 0) { + append_profile(); + num_input_profiles = 1; + } + + // ensure that the current input profile index is valid. + Settings::values.current_input_profile_index = + std::clamp(Settings::values.current_input_profile_index, 0, num_input_profiles - 1); + + Settings::LoadProfile(Settings::values.current_input_profile_index); qt_config->endGroup(); @@ -271,8 +298,8 @@ void Config::ReadValues() { UISettings::values.game_dirs.append(game_dir); } qt_config->endArray(); - // create NAND and SD card directories if empty, these are not removable through the UI, also - // carries over old game list settings if present + // create NAND and SD card directories if empty, these are not removable through the UI, + // also carries over old game list settings if present if (UISettings::values.game_dirs.isEmpty()) { UISettings::GameDir game_dir; game_dir.path = "INSTALLED"; @@ -356,29 +383,36 @@ void Config::ReadValues() { void Config::SaveValues() { qt_config->beginGroup("Controls"); - for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { - std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); - WriteSetting(QString::fromStdString(Settings::NativeButton::mapping[i]), - QString::fromStdString(Settings::values.buttons[i]), - QString::fromStdString(default_param)); + WriteSetting("profile", Settings::values.current_input_profile_index, 0); + qt_config->beginWriteArray("profiles"); + for (std::size_t p = 0; p < Settings::values.input_profiles.size(); ++p) { + qt_config->setArrayIndex(static_cast(p)); + const auto& profile = Settings::values.input_profiles[p]; + for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { + std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); + WriteSetting(QString::fromStdString(Settings::NativeButton::mapping[i]), + QString::fromStdString(profile.buttons[i]), + QString::fromStdString(default_param)); + } + for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { + std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], + default_analogs[i][3], default_analogs[i][4], 0.5f); + WriteSetting(QString::fromStdString(Settings::NativeAnalog::mapping[i]), + QString::fromStdString(profile.analogs[i]), + QString::fromStdString(default_param)); + } + WriteSetting("motion_device", QString::fromStdString(profile.motion_device), + "engine:motion_emu,update_period:100,sensitivity:0.01,tilt_clamp:90.0"); + WriteSetting("touch_device", QString::fromStdString(profile.touch_device), + "engine:emu_window"); + WriteSetting("udp_input_address", QString::fromStdString(profile.udp_input_address), + InputCommon::CemuhookUDP::DEFAULT_ADDR); + WriteSetting("udp_input_port", profile.udp_input_port, + InputCommon::CemuhookUDP::DEFAULT_PORT); + WriteSetting("udp_pad_index", profile.udp_pad_index, 0); } - for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { - std::string default_param = InputCommon::GenerateAnalogParamFromKeys( - default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], - default_analogs[i][3], default_analogs[i][4], 0.5f); - WriteSetting(QString::fromStdString(Settings::NativeAnalog::mapping[i]), - QString::fromStdString(Settings::values.analogs[i]), - QString::fromStdString(default_param)); - } - WriteSetting("motion_device", QString::fromStdString(Settings::values.motion_device), - "engine:motion_emu,update_period:100,sensitivity:0.01,tilt_clamp:90.0"); - WriteSetting("touch_device", QString::fromStdString(Settings::values.touch_device), - "engine:emu_window"); - WriteSetting("udp_input_address", QString::fromStdString(Settings::values.udp_input_address), - InputCommon::CemuhookUDP::DEFAULT_ADDR); - WriteSetting("udp_input_port", Settings::values.udp_input_port, - InputCommon::CemuhookUDP::DEFAULT_PORT); - WriteSetting("udp_pad_index", Settings::values.udp_pad_index, 0); + qt_config->endArray(); qt_config->endGroup(); qt_config->beginGroup("Core"); diff --git a/src/citra_qt/configuration/configure_dialog.cpp b/src/citra_qt/configuration/configure_dialog.cpp index 3f13401f1..3527b8589 100644 --- a/src/citra_qt/configuration/configure_dialog.cpp +++ b/src/citra_qt/configuration/configure_dialog.cpp @@ -42,6 +42,7 @@ void ConfigureDialog::applyConfiguration() { ui->generalTab->applyConfiguration(); ui->systemTab->applyConfiguration(); ui->inputTab->applyConfiguration(); + ui->inputTab->ApplyProfile(); ui->graphicsTab->applyConfiguration(); ui->audioTab->applyConfiguration(); ui->cameraTab->applyConfiguration(); diff --git a/src/citra_qt/configuration/configure_input.cpp b/src/citra_qt/configuration/configure_input.cpp index 50487d084..c0df64bc9 100644 --- a/src/citra_qt/configuration/configure_input.cpp +++ b/src/citra_qt/configuration/configure_input.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -95,10 +96,15 @@ static QString AnalogToText(const Common::ParamPackage& param, const std::string ConfigureInput::ConfigureInput(QWidget* parent) : QWidget(parent), ui(std::make_unique()), timeout_timer(std::make_unique()), poll_timer(std::make_unique()) { - ui->setupUi(this); setFocusPolicy(Qt::ClickFocus); + for (const auto& profile : Settings::values.input_profiles) { + ui->profile->addItem(QString::fromStdString(profile.name)); + } + + ui->profile->setCurrentIndex(Settings::values.current_input_profile_index); + button_map = { ui->buttonA, ui->buttonB, ui->buttonX, ui->buttonY, ui->buttonDpadUp, ui->buttonDpadDown, ui->buttonDpadLeft, ui->buttonDpadRight, @@ -131,10 +137,15 @@ ConfigureInput::ConfigureInput(QWidget* parent) continue; button_map[button_id]->setContextMenuPolicy(Qt::CustomContextMenu); connect(button_map[button_id], &QPushButton::released, [=]() { - handleClick( - button_map[button_id], - [=](const Common::ParamPackage& params) { buttons_param[button_id] = params; }, - InputCommon::Polling::DeviceType::Button); + handleClick(button_map[button_id], + [=](const Common::ParamPackage& params) { + buttons_param[button_id] = params; + // If the user closes the dialog, the changes are reverted in + // `GMainWindow::OnConfigure()` + applyConfiguration(); + Settings::SaveProfile(ui->profile->currentIndex()); + }, + InputCommon::Polling::DeviceType::Button); }); connect(button_map[button_id], &QPushButton::customContextMenuRequested, [=](const QPoint& menu_location) { @@ -142,11 +153,15 @@ ConfigureInput::ConfigureInput(QWidget* parent) context_menu.addAction(tr("Clear"), [&] { buttons_param[button_id].Clear(); button_map[button_id]->setText(tr("[not set]")); + applyConfiguration(); + Settings::SaveProfile(ui->profile->currentIndex()); }); 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])); + applyConfiguration(); + Settings::SaveProfile(ui->profile->currentIndex()); }); context_menu.exec(button_map[button_id]->mapToGlobal(menu_location)); }); @@ -163,6 +178,8 @@ ConfigureInput::ConfigureInput(QWidget* parent) [=](const Common::ParamPackage& params) { SetAnalogButton(params, analogs_param[analog_id], analog_sub_buttons[sub_button_id]); + applyConfiguration(); + Settings::SaveProfile(ui->profile->currentIndex()); }, InputCommon::Polling::DeviceType::Button); }); @@ -172,6 +189,8 @@ ConfigureInput::ConfigureInput(QWidget* parent) 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]")); + applyConfiguration(); + Settings::SaveProfile(ui->profile->currentIndex()); }); context_menu.addAction(tr("Restore Default"), [&] { Common::ParamPackage params{InputCommon::GenerateKeyboardParam( @@ -180,6 +199,8 @@ ConfigureInput::ConfigureInput(QWidget* parent) 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])); + applyConfiguration(); + Settings::SaveProfile(ui->profile->currentIndex()); }); context_menu.exec(analog_map_buttons[analog_id][sub_button_id]->mapToGlobal( menu_location)); @@ -189,10 +210,13 @@ ConfigureInput::ConfigureInput(QWidget* parent) QMessageBox::information(this, tr("Information"), tr("After pressing OK, first move your joystick horizontally, " "and then vertically.")); - handleClick( - analog_map_stick[analog_id], - [=](const Common::ParamPackage& params) { analogs_param[analog_id] = params; }, - InputCommon::Polling::DeviceType::Analog); + handleClick(analog_map_stick[analog_id], + [=](const Common::ParamPackage& params) { + analogs_param[analog_id] = params; + applyConfiguration(); + Settings::SaveProfile(ui->profile->currentIndex()); + }, + InputCommon::Polling::DeviceType::Analog); }); } @@ -200,8 +224,22 @@ ConfigureInput::ConfigureInput(QWidget* parent) QDialog* motion_touch_dialog = new ConfigureMotionTouch(this); return motion_touch_dialog->exec(); }); + + ui->buttonDelete->setEnabled(ui->profile->count() > 1); + connect(ui->buttonClearAll, &QPushButton::released, [this] { ClearAll(); }); connect(ui->buttonRestoreDefaults, &QPushButton::released, [this]() { restoreDefaults(); }); + connect(ui->buttonNew, &QPushButton::released, [this] { NewProfile(); }); + connect(ui->buttonDelete, &QPushButton::released, [this] { DeleteProfile(); }); + connect(ui->buttonRename, &QPushButton::released, [this] { RenameProfile(); }); + + connect(ui->profile, static_cast(&QComboBox::currentIndexChanged), + [this](int i) { + applyConfiguration(); + Settings::SaveProfile(Settings::values.current_input_profile_index); + Settings::LoadProfile(i); + loadConfiguration(); + }); timeout_timer->setSingleShot(true); connect(timeout_timer.get(), &QTimer::timeout, [this]() { setPollingResult({}, true); }); @@ -226,18 +264,24 @@ ConfigureInput::ConfigureInput(QWidget* parent) ConfigureInput::~ConfigureInput() = default; void ConfigureInput::applyConfiguration() { - std::transform(buttons_param.begin(), buttons_param.end(), Settings::values.buttons.begin(), + std::transform(buttons_param.begin(), buttons_param.end(), + Settings::values.current_input_profile.buttons.begin(), [](const Common::ParamPackage& param) { return param.Serialize(); }); - std::transform(analogs_param.begin(), analogs_param.end(), Settings::values.analogs.begin(), + std::transform(analogs_param.begin(), analogs_param.end(), + Settings::values.current_input_profile.analogs.begin(), [](const Common::ParamPackage& param) { return param.Serialize(); }); } +void ConfigureInput::ApplyProfile() { + Settings::values.current_input_profile_index = ui->profile->currentIndex(); +} + void ConfigureInput::loadConfiguration() { - std::transform(Settings::values.buttons.begin(), Settings::values.buttons.end(), - buttons_param.begin(), + std::transform(Settings::values.current_input_profile.buttons.begin(), + Settings::values.current_input_profile.buttons.end(), buttons_param.begin(), [](const std::string& str) { return Common::ParamPackage(str); }); - std::transform(Settings::values.analogs.begin(), Settings::values.analogs.end(), - analogs_param.begin(), + std::transform(Settings::values.current_input_profile.analogs.begin(), + Settings::values.current_input_profile.analogs.end(), analogs_param.begin(), [](const std::string& str) { return Common::ParamPackage(str); }); updateButtonLabels(); } @@ -349,3 +393,41 @@ void ConfigureInput::keyPressEvent(QKeyEvent* event) { void ConfigureInput::retranslateUi() { ui->retranslateUi(this); } + +void ConfigureInput::NewProfile() { + const QString name = + QInputDialog::getText(this, tr("New Profile"), tr("Enter the name for the new profile.")); + if (name.isEmpty()) { + return; + } + applyConfiguration(); + Settings::SaveProfile(ui->profile->currentIndex()); + Settings::CreateProfile(name.toStdString()); + ui->profile->addItem(name); + ui->profile->setCurrentIndex(Settings::values.current_input_profile_index); + loadConfiguration(); + ui->buttonDelete->setEnabled(ui->profile->count() > 1); +} + +void ConfigureInput::DeleteProfile() { + const auto answer = QMessageBox::question( + this, tr("Delete Profile"), tr("Delete profile %1?").arg(ui->profile->currentText())); + if (answer != QMessageBox::Yes) { + return; + } + const int index = ui->profile->currentIndex(); + ui->profile->removeItem(index); + ui->profile->setCurrentIndex(0); + Settings::DeleteProfile(index); + loadConfiguration(); + ui->buttonDelete->setEnabled(ui->profile->count() > 1); +} + +void ConfigureInput::RenameProfile() { + const QString new_name = QInputDialog::getText(this, tr("Rename Profile"), tr("New name:")); + if (new_name.isEmpty()) { + return; + } + ui->profile->setItemText(ui->profile->currentIndex(), new_name); + Settings::RenameCurrentProfile(new_name.toStdString()); +} diff --git a/src/citra_qt/configuration/configure_input.h b/src/citra_qt/configuration/configure_input.h index aa3cce7a5..1e55fd272 100644 --- a/src/citra_qt/configuration/configure_input.h +++ b/src/citra_qt/configuration/configure_input.h @@ -39,6 +39,9 @@ public: /// Load configuration settings. void loadConfiguration(); + // Save the current input profile index + void ApplyProfile(); + private: std::unique_ptr ui; @@ -91,4 +94,9 @@ private: /// Handle key press events. void keyPressEvent(QKeyEvent* event) override; + + /// input profiles + void NewProfile(); + void DeleteProfile(); + void RenameProfile(); }; diff --git a/src/citra_qt/configuration/configure_input.ui b/src/citra_qt/configuration/configure_input.ui index 581223274..6d0cb8ac7 100644 --- a/src/citra_qt/configuration/configure_input.ui +++ b/src/citra_qt/configuration/configure_input.ui @@ -6,7 +6,7 @@ 0 0 - 370 + 374 595 @@ -14,6 +14,54 @@ ConfigureInput + + + + + + Profile + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + New + + + + + + + Delete + + + + + + + Rename + + + + + @@ -28,35 +76,17 @@ false - - + + - + - A: + Y: - - - - - - - - - - - - - - B: - - - - - + @@ -82,17 +112,35 @@ - - + + - + - Y: + B: - + + + + + + + + + + + + + + A: + + + + + @@ -289,50 +337,7 @@ false - - - - Set Analog Stick - - - - - - - - - Left: - - - - - - - - - - - - - - - - - - Right: - - - - - - - - - - - - - + @@ -350,7 +355,7 @@ - + @@ -368,6 +373,49 @@ + + + + + + Right: + + + + + + + + + + + + + + + + Set Analog Stick + + + + + + + + + Left: + + + + + + + + + + + + @@ -591,103 +639,107 @@ - + - - - - 0 - 0 - - - - - 0 - 0 - - - - - 0 - 0 - - - - Qt::LeftToRight - - - Motion / Touch... - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 0 - 0 - - - - Qt::LeftToRight - - - Clear All - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 0 - 0 - - - - Qt::LeftToRight - - - Restore Defaults - - + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 0 + 0 + + + + Qt::LeftToRight + + + Motion / Touch... + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 0 + 0 + + + + Qt::LeftToRight + + + Clear All + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 0 + 0 + + + + Qt::LeftToRight + + + Restore Defaults + + + + diff --git a/src/citra_qt/configuration/configure_motion_touch.cpp b/src/citra_qt/configuration/configure_motion_touch.cpp index b1d04f0d2..80bf6a148 100644 --- a/src/citra_qt/configuration/configure_motion_touch.cpp +++ b/src/citra_qt/configuration/configure_motion_touch.cpp @@ -102,8 +102,8 @@ ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent) ConfigureMotionTouch::~ConfigureMotionTouch() = default; void ConfigureMotionTouch::setConfiguration() { - Common::ParamPackage motion_param(Settings::values.motion_device); - Common::ParamPackage touch_param(Settings::values.touch_device); + Common::ParamPackage motion_param(Settings::values.current_input_profile.motion_device); + Common::ParamPackage touch_param(Settings::values.current_input_profile.touch_device); std::string motion_engine = motion_param.Get("engine", "motion_emu"); std::string touch_engine = touch_param.Get("engine", "emu_window"); @@ -118,9 +118,10 @@ void ConfigureMotionTouch::setConfiguration() { max_x = touch_param.Get("max_x", 1800); max_y = touch_param.Get("max_y", 850); - ui->udp_server->setText(QString::fromStdString(Settings::values.udp_input_address)); - ui->udp_port->setText(QString::number(Settings::values.udp_input_port)); - ui->udp_pad_index->setCurrentIndex(Settings::values.udp_pad_index); + ui->udp_server->setText( + QString::fromStdString(Settings::values.current_input_profile.udp_input_address)); + ui->udp_port->setText(QString::number(Settings::values.current_input_profile.udp_input_port)); + ui->udp_pad_index->setCurrentIndex(Settings::values.current_input_profile.udp_pad_index); } void ConfigureMotionTouch::updateUiDisplay() { @@ -265,11 +266,14 @@ void ConfigureMotionTouch::applyConfiguration() { touch_param.Set("max_y", max_y); } - Settings::values.motion_device = motion_param.Serialize(); - Settings::values.touch_device = touch_param.Serialize(); - Settings::values.udp_input_address = ui->udp_server->text().toStdString(); - Settings::values.udp_input_port = static_cast(ui->udp_port->text().toInt()); - Settings::values.udp_pad_index = static_cast(ui->udp_pad_index->currentIndex()); + Settings::values.current_input_profile.motion_device = motion_param.Serialize(); + Settings::values.current_input_profile.touch_device = touch_param.Serialize(); + Settings::values.current_input_profile.udp_input_address = ui->udp_server->text().toStdString(); + Settings::values.current_input_profile.udp_input_port = + static_cast(ui->udp_port->text().toInt()); + Settings::values.current_input_profile.udp_pad_index = + static_cast(ui->udp_pad_index->currentIndex()); + Settings::SaveProfile(Settings::values.current_input_profile_index); InputCommon::ReloadInputDevices(); accept(); diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 69d8636dc..a62e23260 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -1326,6 +1326,8 @@ void GMainWindow::OnConfigure() { connect(&configureDialog, &ConfigureDialog::languageChanged, this, &GMainWindow::OnLanguageChanged); auto old_theme = UISettings::values.theme; + const int old_input_profile_index = Settings::values.current_input_profile_index; + const auto old_input_profiles = Settings::values.input_profiles; const bool old_discord_presence = UISettings::values.enable_discord_presence; auto result = configureDialog.exec(); if (result == QDialog::Accepted) { @@ -1338,6 +1340,9 @@ void GMainWindow::OnConfigure() { SyncMenuUISettings(); game_list->RefreshGameDirectory(); config->Save(); + } else { + Settings::values.input_profiles = old_input_profiles; + Settings::LoadProfile(old_input_profile_index); } } diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 7393ad684..39ae4c43e 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -59,13 +59,17 @@ DirectionState GetStickDirectionState(s16 circle_pad_x, s16 circle_pad_y) { } void Module::LoadInputDevices() { - std::transform(Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, - Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_END, + std::transform(Settings::values.current_input_profile.buttons.begin() + + Settings::NativeButton::BUTTON_HID_BEGIN, + Settings::values.current_input_profile.buttons.begin() + + Settings::NativeButton::BUTTON_HID_END, buttons.begin(), Input::CreateDevice); circle_pad = Input::CreateDevice( - Settings::values.analogs[Settings::NativeAnalog::CirclePad]); - motion_device = Input::CreateDevice(Settings::values.motion_device); - touch_device = Input::CreateDevice(Settings::values.touch_device); + Settings::values.current_input_profile.analogs[Settings::NativeAnalog::CirclePad]); + motion_device = Input::CreateDevice( + Settings::values.current_input_profile.motion_device); + touch_device = Input::CreateDevice( + Settings::values.current_input_profile.touch_device); } void Module::UpdatePadCallback(u64 userdata, s64 cycles_late) { diff --git a/src/core/hle/service/ir/extra_hid.cpp b/src/core/hle/service/ir/extra_hid.cpp index 8568f15a1..e5332cc76 100644 --- a/src/core/hle/service/ir/extra_hid.cpp +++ b/src/core/hle/service/ir/extra_hid.cpp @@ -263,11 +263,11 @@ void ExtraHID::RequestInputDevicesReload() { void ExtraHID::LoadInputDevices() { zl = Input::CreateDevice( - Settings::values.buttons[Settings::NativeButton::ZL]); + Settings::values.current_input_profile.buttons[Settings::NativeButton::ZL]); zr = Input::CreateDevice( - Settings::values.buttons[Settings::NativeButton::ZR]); + Settings::values.current_input_profile.buttons[Settings::NativeButton::ZR]); c_stick = Input::CreateDevice( - Settings::values.analogs[Settings::NativeAnalog::CStick]); + Settings::values.current_input_profile.analogs[Settings::NativeAnalog::CStick]); } } // namespace Service::IR diff --git a/src/core/hle/service/ir/ir_rst.cpp b/src/core/hle/service/ir/ir_rst.cpp index 7b7849afd..71d16a1ce 100644 --- a/src/core/hle/service/ir/ir_rst.cpp +++ b/src/core/hle/service/ir/ir_rst.cpp @@ -35,11 +35,11 @@ static_assert(sizeof(SharedMem) == 0x98, "SharedMem has wrong size!"); void IR_RST::LoadInputDevices() { zl_button = Input::CreateDevice( - Settings::values.buttons[Settings::NativeButton::ZL]); + Settings::values.current_input_profile.buttons[Settings::NativeButton::ZL]); zr_button = Input::CreateDevice( - Settings::values.buttons[Settings::NativeButton::ZR]); + Settings::values.current_input_profile.buttons[Settings::NativeButton::ZR]); c_stick = Input::CreateDevice( - Settings::values.analogs[Settings::NativeAnalog::CStick]); + Settings::values.current_input_profile.analogs[Settings::NativeAnalog::CStick]); } void IR_RST::UnloadInputDevices() { diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 2141d57bd..ae2ed5cf2 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include "audio_core/dsp_interface.h" #include "core/core.h" #include "core/gdbstub/gdbstub.h" @@ -101,4 +102,32 @@ void LogSettings() { LogSetting("Debugging_GdbstubPort", Settings::values.gdbstub_port); } +void LoadProfile(int index) { + Settings::values.current_input_profile = Settings::values.input_profiles[index]; + Settings::values.current_input_profile_index = index; +} + +void SaveProfile(int index) { + Settings::values.input_profiles[index] = Settings::values.current_input_profile; +} + +void CreateProfile(std::string name) { + Settings::InputProfile profile = values.current_input_profile; + profile.name = std::move(name); + Settings::values.input_profiles.push_back(std::move(profile)); + Settings::values.current_input_profile_index = + static_cast(Settings::values.input_profiles.size()) - 1; + Settings::LoadProfile(Settings::values.current_input_profile_index); +} + +void DeleteProfile(int index) { + Settings::values.input_profiles.erase(Settings::values.input_profiles.begin() + index); + Settings::LoadProfile(0); +} + +void RenameCurrentProfile(std::string new_name) { + Settings::values.input_profiles[Settings::values.current_input_profile_index].name = + std::move(new_name); +} + } // namespace Settings diff --git a/src/core/settings.h b/src/core/settings.h index e3bf77a40..907e58c97 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -7,6 +7,7 @@ #include #include #include +#include #include "common/common_types.h" #include "core/hle/service/cam/cam.h" @@ -96,11 +97,8 @@ static const std::array mapping = {{ }}; } // namespace NativeAnalog -struct Values { - // CheckNew3DS - bool is_new_3ds; - - // Controls +struct InputProfile { + std::string name; std::array buttons; std::array analogs; std::string motion_device; @@ -108,6 +106,16 @@ struct Values { std::string udp_input_address; u16 udp_input_port; u8 udp_pad_index; +}; + +struct Values { + // CheckNew3DS + bool is_new_3ds; + + // Controls + InputProfile current_input_profile; ///< The current input profile + int current_input_profile_index; ///< The current input profile index + std::vector input_profiles; ///< The list of input profiles // Core bool use_cpu_jit; @@ -182,4 +190,11 @@ static constexpr int REGION_VALUE_AUTO_SELECT = -1; void Apply(); void LogSettings(); + +// Input profiles +void LoadProfile(int index); +void SaveProfile(int index); +void CreateProfile(std::string name); +void DeleteProfile(int index); +void RenameCurrentProfile(std::string new_name); } // namespace Settings diff --git a/src/input_common/udp/udp.cpp b/src/input_common/udp/udp.cpp index d94278def..239cf25ed 100644 --- a/src/input_common/udp/udp.cpp +++ b/src/input_common/udp/udp.cpp @@ -71,8 +71,9 @@ private: State::State() { auto status = std::make_shared(); client = - std::make_unique(status, Settings::values.udp_input_address, - Settings::values.udp_input_port, Settings::values.udp_pad_index); + std::make_unique(status, Settings::values.current_input_profile.udp_input_address, + Settings::values.current_input_profile.udp_input_port, + Settings::values.current_input_profile.udp_pad_index); Input::RegisterFactory("cemuhookudp", std::make_shared(status)); @@ -86,8 +87,9 @@ State::~State() { } void State::ReloadUDPClient() { - client->ReloadSocket(Settings::values.udp_input_address, Settings::values.udp_input_port, - Settings::values.udp_pad_index); + client->ReloadSocket(Settings::values.current_input_profile.udp_input_address, + Settings::values.current_input_profile.udp_input_port, + Settings::values.current_input_profile.udp_pad_index); } std::unique_ptr Init() {