From 38110dd485e329fa39e2e4c02b91a89dfebcbc88 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Sat, 17 Oct 2020 09:38:12 -0400 Subject: [PATCH] configure_input: Add per-player vibration Allows for enabling and modifying vibration and vibration strength per player. Also adds a toggle for enabling/disabling accurate vibrations. Co-authored-by: Its-Rei --- dist/qt_themes/qdarkstyle/style.qss | 11 +- .../qdarkstyle_midnight_blue/style.qss | 12 +- src/core/hle/service/hid/controllers/npad.cpp | 13 +- src/core/settings.h | 1 + src/input_common/settings.h | 3 + src/yuzu/CMakeLists.txt | 3 + src/yuzu/applets/controller.cpp | 16 + src/yuzu/applets/controller.h | 3 + src/yuzu/applets/controller.ui | 18 +- src/yuzu/configuration/config.cpp | 16 + src/yuzu/configuration/configure_input.cpp | 4 + src/yuzu/configuration/configure_input.ui | 22 +- .../configuration/configure_vibration.cpp | 66 +++ src/yuzu/configuration/configure_vibration.h | 40 ++ src/yuzu/configuration/configure_vibration.ui | 546 ++++++++++++++++++ src/yuzu_cmd/config.cpp | 2 + src/yuzu_cmd/default_ini.h | 4 + src/yuzu_tester/config.cpp | 1 + 18 files changed, 751 insertions(+), 30 deletions(-) create mode 100644 src/yuzu/configuration/configure_vibration.cpp create mode 100644 src/yuzu/configuration/configure_vibration.h create mode 100644 src/yuzu/configuration/configure_vibration.ui diff --git a/dist/qt_themes/qdarkstyle/style.qss b/dist/qt_themes/qdarkstyle/style.qss index aca6531ace..2a1e8ddebe 100644 --- a/dist/qt_themes/qdarkstyle/style.qss +++ b/dist/qt_themes/qdarkstyle/style.qss @@ -1293,15 +1293,24 @@ QPushButton#buttonRefreshDevices { QSpinBox#spinboxLStickRange, QSpinBox#spinboxRStickRange, -QSpinBox#vibrationSpin { +QSpinBox#vibrationSpinPlayer1, +QSpinBox#vibrationSpinPlayer2, +QSpinBox#vibrationSpinPlayer3, +QSpinBox#vibrationSpinPlayer4, +QSpinBox#vibrationSpinPlayer5, +QSpinBox#vibrationSpinPlayer6, +QSpinBox#vibrationSpinPlayer7, +QSpinBox#vibrationSpinPlayer8 { min-width: 68px; } +QDialog#ConfigureVibration QGroupBox::indicator, QGroupBox#motionGroup::indicator, QGroupBox#vibrationGroup::indicator { margin-left: 0px; } +QDialog#ConfigureVibration QGroupBox::title, QGroupBox#motionGroup::title, QGroupBox#vibrationGroup::title { spacing: 2px; diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss index ad032a9669..70e540b068 100644 --- a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss +++ b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss @@ -2200,21 +2200,31 @@ QPushButton#buttonRefreshDevices { QSpinBox#spinboxLStickRange, QSpinBox#spinboxRStickRange, -QSpinBox#vibrationSpin { +QSpinBox#vibrationSpinPlayer1, +QSpinBox#vibrationSpinPlayer2, +QSpinBox#vibrationSpinPlayer3, +QSpinBox#vibrationSpinPlayer4, +QSpinBox#vibrationSpinPlayer5, +QSpinBox#vibrationSpinPlayer6, +QSpinBox#vibrationSpinPlayer7, +QSpinBox#vibrationSpinPlayer8 { min-width: 68px; } +QDialog#ConfigureVibration QGroupBox::indicator, QGroupBox#motionGroup::indicator, QGroupBox#vibrationGroup::indicator { margin-left: 0px; } +QDialog#ConfigureVibration QGroupBox, QWidget#bottomPerGameInput QGroupBox#motionGroup, QWidget#bottomPerGameInput QGroupBox#vibrationGroup, QWidget#bottomPerGameInput QGroupBox#inputConfigGroup { padding: 0px; } +QDialog#ConfigureVibration QGroupBox::title, QGroupBox#motionGroup::title, QGroupBox#vibrationGroup::title { spacing: 2px; diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index ba20d3f596..dc9954377f 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -680,11 +680,19 @@ bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index, return false; } + const auto& player = Settings::values.players.GetValue()[npad_index]; + + if (!player.vibration_enabled) { + return false; + } + using namespace Settings::NativeButton; const auto& button_state = buttons[npad_index]; return button_state[A - BUTTON_HID_BEGIN]->SetRumblePlay( - vibration_value.amp_low, vibration_value.freq_low, vibration_value.amp_high, + std::min(vibration_value.amp_low * player.vibration_strength / 100.0f, 1.0f), + vibration_value.freq_low, + std::min(vibration_value.amp_high * player.vibration_strength / 100.0f, 1.0f), vibration_value.freq_high); } @@ -728,7 +736,8 @@ void Controller_NPad::VibrateControllers(const std::vector& vibrat } // Filter out non-zero vibrations that are within 0.015625 absolute amplitude of each other. - if ((vibration_values[i].amp_low != 0.0f || vibration_values[i].amp_high != 0.0f) && + if (!Settings::values.enable_accurate_vibrations.GetValue() && + (vibration_values[i].amp_low != 0.0f || vibration_values[i].amp_high != 0.0f) && (latest_vibration_values[npad_index][device_index].amp_low != 0.0f || latest_vibration_values[npad_index][device_index].amp_high != 0.0f) && (abs(vibration_values[i].amp_low - diff --git a/src/core/settings.h b/src/core/settings.h index edd2a00ca4..476c3fdf3d 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -170,6 +170,7 @@ struct Values { Setting use_docked_mode; Setting vibration_enabled; + Setting enable_accurate_vibrations; Setting motion_enabled; std::string motion_device; diff --git a/src/input_common/settings.h b/src/input_common/settings.h index f52d285407..2763ed9915 100644 --- a/src/input_common/settings.h +++ b/src/input_common/settings.h @@ -332,6 +332,9 @@ struct PlayerInput { AnalogsRaw analogs; MotionRaw motions; + bool vibration_enabled; + int vibration_strength; + u32 body_color_left; u32 body_color_right; u32 button_color_left; diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 22fe0a2a6b..bf1fae9fa5 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -105,6 +105,9 @@ add_executable(yuzu configuration/configure_ui.cpp configuration/configure_ui.h configuration/configure_ui.ui + configuration/configure_vibration.cpp + configuration/configure_vibration.h + configuration/configure_vibration.ui configuration/configure_web.cpp configuration/configure_web.h configuration/configure_web.ui diff --git a/src/yuzu/applets/controller.cpp b/src/yuzu/applets/controller.cpp index 0fc713a6e0..c5e671309a 100644 --- a/src/yuzu/applets/controller.cpp +++ b/src/yuzu/applets/controller.cpp @@ -14,6 +14,7 @@ #include "ui_controller.h" #include "yuzu/applets/controller.h" #include "yuzu/configuration/configure_input_dialog.h" +#include "yuzu/configuration/configure_vibration.h" #include "yuzu/main.h" namespace { @@ -223,6 +224,9 @@ QtControllerSelectorDialog::QtControllerSelectorDialog( } } + connect(ui->vibrationButton, &QPushButton::clicked, this, + &QtControllerSelectorDialog::CallConfigureVibrationDialog); + connect(ui->inputConfigButton, &QPushButton::clicked, this, &QtControllerSelectorDialog::CallConfigureInputDialog); @@ -285,6 +289,18 @@ void QtControllerSelectorDialog::LoadConfiguration() { ui->motionGroup->setChecked(Settings::values.motion_enabled.GetValue()); } +void QtControllerSelectorDialog::CallConfigureVibrationDialog() { + ConfigureVibration dialog(this); + + dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | + Qt::WindowSystemMenuHint); + dialog.setWindowModality(Qt::WindowModal); + + if (dialog.exec() == QDialog::Accepted) { + dialog.ApplyConfiguration(); + } +} + void QtControllerSelectorDialog::CallConfigureInputDialog() { const auto max_supported_players = parameters.enable_single_mode ? 1 : parameters.max_players; diff --git a/src/yuzu/applets/controller.h b/src/yuzu/applets/controller.h index 8fefecf053..a2ce03c8fd 100644 --- a/src/yuzu/applets/controller.h +++ b/src/yuzu/applets/controller.h @@ -42,6 +42,9 @@ private: // Loads the current input configuration into the frontend applet. void LoadConfiguration(); + // Initializes the "Configure Vibration" Dialog. + void CallConfigureVibrationDialog(); + // Initializes the "Configure Input" Dialog. void CallConfigureInputDialog(); diff --git a/src/yuzu/applets/controller.ui b/src/yuzu/applets/controller.ui index cc27b8ef45..8e571ba8fe 100644 --- a/src/yuzu/applets/controller.ui +++ b/src/yuzu/applets/controller.ui @@ -2329,11 +2329,11 @@ 3 - + 68 - 21 + 0 @@ -2342,17 +2342,11 @@ 16777215 - - % + + min-width: 68px; - - 1 - - - 100 - - - 100 + + Configure diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 296c58f58b..7f66f29aa9 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -300,6 +300,14 @@ void Config::ReadPlayerValue(std::size_t player_index) { static_cast(Settings::ControllerType::ProController)) .toUInt()); + player.vibration_enabled = + qt_config->value(QStringLiteral("%1vibration_enabled").arg(player_prefix), true) + .toBool(); + + player.vibration_strength = + qt_config->value(QStringLiteral("%1vibration_strength").arg(player_prefix), 100) + .toInt(); + player.body_color_left = qt_config ->value(QStringLiteral("%1body_color_left").arg(player_prefix), Settings::JOYCON_BODY_NEON_BLUE) @@ -493,6 +501,8 @@ void Config::ReadControlValues() { ReadSettingGlobal(Settings::values.use_docked_mode, QStringLiteral("use_docked_mode"), false); ReadSettingGlobal(Settings::values.vibration_enabled, QStringLiteral("vibration_enabled"), true); + ReadSettingGlobal(Settings::values.enable_accurate_vibrations, + QStringLiteral("enable_accurate_vibrations"), false); ReadSettingGlobal(Settings::values.motion_enabled, QStringLiteral("motion_enabled"), true); qt_config->endGroup(); @@ -983,6 +993,10 @@ void Config::SavePlayerValue(std::size_t player_index) { if (!player_prefix.isEmpty()) { WriteSetting(QStringLiteral("%1connected").arg(player_prefix), player.connected, false); + WriteSetting(QStringLiteral("%1vibration_enabled").arg(player_prefix), + player.vibration_enabled, true); + WriteSetting(QStringLiteral("%1vibration_strength").arg(player_prefix), + player.vibration_strength, 100); WriteSetting(QStringLiteral("%1body_color_left").arg(player_prefix), player.body_color_left, Settings::JOYCON_BODY_NEON_BLUE); WriteSetting(QStringLiteral("%1body_color_right").arg(player_prefix), @@ -1150,6 +1164,8 @@ void Config::SaveControlValues() { WriteSettingGlobal(QStringLiteral("use_docked_mode"), Settings::values.use_docked_mode, false); WriteSettingGlobal(QStringLiteral("vibration_enabled"), Settings::values.vibration_enabled, true); + WriteSettingGlobal(QStringLiteral("enable_accurate_vibrations"), + Settings::values.enable_accurate_vibrations, false); WriteSettingGlobal(QStringLiteral("motion_enabled"), Settings::values.motion_enabled, true); WriteSetting(QStringLiteral("motion_device"), QString::fromStdString(Settings::values.motion_device), diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index 9a4de4c5d5..600cc03aef 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -23,6 +23,7 @@ #include "yuzu/configuration/configure_motion_touch.h" #include "yuzu/configuration/configure_mouse_advanced.h" #include "yuzu/configuration/configure_touchscreen_advanced.h" +#include "yuzu/configuration/configure_vibration.h" #include "yuzu/configuration/input_profiles.h" namespace { @@ -156,6 +157,9 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem, CallConfigureDialog(*this, input_subsystem); }); + connect(ui->vibrationButton, &QPushButton::clicked, + [this] { CallConfigureDialog(*this); }); + connect(ui->motionButton, &QPushButton::clicked, [this, input_subsystem] { CallConfigureDialog(*this, input_subsystem); }); diff --git a/src/yuzu/configuration/configure_input.ui b/src/yuzu/configuration/configure_input.ui index cbd67d4c71..2707025e7f 100644 --- a/src/yuzu/configuration/configure_input.ui +++ b/src/yuzu/configuration/configure_input.ui @@ -6,7 +6,7 @@ 0 0 - 700 + 680 540 @@ -195,11 +195,11 @@ 3 - + 68 - 21 + 0 @@ -208,17 +208,11 @@ 16777215 - - % + + min-width: 68px; - - 1 - - - 100 - - - 100 + + Configure @@ -272,7 +266,7 @@ - + 5 diff --git a/src/yuzu/configuration/configure_vibration.cpp b/src/yuzu/configuration/configure_vibration.cpp new file mode 100644 index 0000000000..1c68f28f32 --- /dev/null +++ b/src/yuzu/configuration/configure_vibration.cpp @@ -0,0 +1,66 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/settings.h" +#include "ui_configure_vibration.h" +#include "yuzu/configuration/configure_vibration.h" + +ConfigureVibration::ConfigureVibration(QWidget* parent) + : QDialog(parent), ui(std::make_unique()) { + ui->setupUi(this); + + vibration_groupboxes = { + ui->vibrationGroupPlayer1, ui->vibrationGroupPlayer2, ui->vibrationGroupPlayer3, + ui->vibrationGroupPlayer4, ui->vibrationGroupPlayer5, ui->vibrationGroupPlayer6, + ui->vibrationGroupPlayer7, ui->vibrationGroupPlayer8, + }; + + vibration_spinboxes = { + ui->vibrationSpinPlayer1, ui->vibrationSpinPlayer2, ui->vibrationSpinPlayer3, + ui->vibrationSpinPlayer4, ui->vibrationSpinPlayer5, ui->vibrationSpinPlayer6, + ui->vibrationSpinPlayer7, ui->vibrationSpinPlayer8, + }; + + const auto& players = Settings::values.players.GetValue(); + + for (std::size_t i = 0; i < NUM_PLAYERS; ++i) { + vibration_groupboxes[i]->setChecked(players[i].vibration_enabled); + vibration_spinboxes[i]->setValue(players[i].vibration_strength); + } + + ui->checkBoxAccurateVibration->setChecked( + Settings::values.enable_accurate_vibrations.GetValue()); + + if (!Settings::IsConfiguringGlobal()) { + ui->checkBoxAccurateVibration->setDisabled(true); + } + + RetranslateUI(); +} + +ConfigureVibration::~ConfigureVibration() = default; + +void ConfigureVibration::ApplyConfiguration() { + auto& players = Settings::values.players.GetValue(); + + for (std::size_t i = 0; i < NUM_PLAYERS; ++i) { + players[i].vibration_enabled = vibration_groupboxes[i]->isChecked(); + players[i].vibration_strength = vibration_spinboxes[i]->value(); + } + + Settings::values.enable_accurate_vibrations.SetValue( + ui->checkBoxAccurateVibration->isChecked()); +} + +void ConfigureVibration::changeEvent(QEvent* event) { + if (event->type() == QEvent::LanguageChange) { + RetranslateUI(); + } + + QDialog::changeEvent(event); +} + +void ConfigureVibration::RetranslateUI() { + ui->retranslateUi(this); +} diff --git a/src/yuzu/configuration/configure_vibration.h b/src/yuzu/configuration/configure_vibration.h new file mode 100644 index 0000000000..37bbc26536 --- /dev/null +++ b/src/yuzu/configuration/configure_vibration.h @@ -0,0 +1,40 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include + +class QGroupBox; +class QSpinBox; + +namespace Ui { +class ConfigureVibration; +} + +class ConfigureVibration : public QDialog { + Q_OBJECT + +public: + explicit ConfigureVibration(QWidget* parent); + ~ConfigureVibration() override; + + void ApplyConfiguration(); + +private: + void changeEvent(QEvent* event) override; + void RetranslateUI(); + + std::unique_ptr ui; + + static constexpr std::size_t NUM_PLAYERS = 8; + + // Groupboxes encapsulating the vibration strength spinbox. + std::array vibration_groupboxes; + + // Spinboxes representing the vibration strength percentage. + std::array vibration_spinboxes; +}; diff --git a/src/yuzu/configuration/configure_vibration.ui b/src/yuzu/configuration/configure_vibration.ui new file mode 100644 index 0000000000..efdf317a95 --- /dev/null +++ b/src/yuzu/configuration/configure_vibration.ui @@ -0,0 +1,546 @@ + + + ConfigureVibration + + + + 0 + 0 + 364 + 242 + + + + Configure Vibration + + + + + + + + + Vibration + + + + 9 + + + 9 + + + 9 + + + 9 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Player 1 + + + true + + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 68 + 21 + + + + + 68 + 16777215 + + + + % + + + 1 + + + 150 + + + 100 + + + + + + + + + + Player 2 + + + true + + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 68 + 21 + + + + + 68 + 16777215 + + + + % + + + 1 + + + 150 + + + 100 + + + + + + + + + + Player 3 + + + true + + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 68 + 21 + + + + + 68 + 16777215 + + + + % + + + 1 + + + 150 + + + 100 + + + + + + + + + + Player 4 + + + true + + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 68 + 21 + + + + + 68 + 16777215 + + + + % + + + 1 + + + 150 + + + 100 + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Player 5 + + + true + + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 68 + 21 + + + + + 68 + 16777215 + + + + % + + + 1 + + + 150 + + + 100 + + + + + + + + + + Player 6 + + + true + + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 68 + 21 + + + + + 68 + 16777215 + + + + % + + + 1 + + + 150 + + + 100 + + + + + + + + + + Player 7 + + + true + + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 68 + 21 + + + + + 68 + 16777215 + + + + % + + + 1 + + + 150 + + + 100 + + + + + + + + + + Player 8 + + + true + + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 68 + 21 + + + + + 68 + 16777215 + + + + % + + + 1 + + + 150 + + + 100 + + + + + + + + + + + + + + + + Settings + + + + + + Enable Accurate Vibration + + + + + + + + + + Qt::Vertical + + + + 167 + 55 + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBoxVibration + accepted() + ConfigureVibration + accept() + + + buttonBoxVibration + rejected() + ConfigureVibration + reject() + + + diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index feee02fcdc..e1adbbf2b4 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp @@ -290,6 +290,8 @@ void Config::ReadValues() { Settings::values.vibration_enabled.SetValue( sdl2_config->GetBoolean("ControlsGeneral", "vibration_enabled", true)); + Settings::values.enable_accurate_vibrations.SetValue( + sdl2_config->GetBoolean("ControlsGeneral", "enable_accurate_vibrations", false)); Settings::values.motion_enabled.SetValue( sdl2_config->GetBoolean("ControlsGeneral", "motion_enabled", true)); Settings::values.touchscreen.enabled = diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h index b6f6a3bb02..bcbbcd4cad 100644 --- a/src/yuzu_cmd/default_ini.h +++ b/src/yuzu_cmd/default_ini.h @@ -69,6 +69,10 @@ rstick= # 0: Disabled, 1 (default): Enabled vibration_enabled= +# Whether to enable or disable accurate vibrations +# 0 (default): Disabled, 1: Enabled +enable_accurate_vibrations= + # for motion input, the following devices are available: # - "motion_emu" (default) for emulating motion input from mouse input. Required parameters: # - "update_period": update period in milliseconds (default to 100) diff --git a/src/yuzu_tester/config.cpp b/src/yuzu_tester/config.cpp index 3a8a333f01..b6cdc7c1c4 100644 --- a/src/yuzu_tester/config.cpp +++ b/src/yuzu_tester/config.cpp @@ -76,6 +76,7 @@ void Config::ReadValues() { } Settings::values.vibration_enabled.SetValue(true); + Settings::values.enable_accurate_vibrations.SetValue(false); Settings::values.motion_enabled.SetValue(true); Settings::values.touchscreen.enabled = ""; Settings::values.touchscreen.device = "";