From 91c06dae1a68efb2d6ae110d0aa28d7b3aafd573 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Fri, 23 Oct 2020 12:09:28 -0400 Subject: [PATCH] input: Disconnect a controller prior to connecting a new one Some games do not respond to a change in controller type if 1) The controller is not disconnected prior to being reconnected and/or 2) The controller is reconnected instantly after being disconnected. Since it is not possible to change controllers instantly on hardware and requiring a disconnect prior to connecting a new one, we should emulate this as well with a small delay, fixing the aforementioned issue. --- src/yuzu/applets/controller.cpp | 62 ++++++++++-------- .../configuration/configure_input_player.cpp | 63 +++++++++++-------- 2 files changed, 74 insertions(+), 51 deletions(-) diff --git a/src/yuzu/applets/controller.cpp b/src/yuzu/applets/controller.cpp index cdcd3d28d1..552cb7204e 100644 --- a/src/yuzu/applets/controller.cpp +++ b/src/yuzu/applets/controller.cpp @@ -19,6 +19,8 @@ namespace { +constexpr std::size_t HANDHELD_INDEX = 8; + constexpr std::array, 8> led_patterns{{ {true, false, false, false}, {true, true, false, false}, @@ -260,11 +262,6 @@ int QtControllerSelectorDialog::exec() { } void QtControllerSelectorDialog::ApplyConfiguration() { - // Update the controller state once more, just to be sure they are properly applied. - for (std::size_t index = 0; index < NUM_PLAYERS; ++index) { - UpdateControllerState(index); - } - const bool pre_docked_mode = Settings::values.use_docked_mode.GetValue(); Settings::values.use_docked_mode.SetValue(ui->radioDocked->isChecked()); OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode.GetValue()); @@ -275,15 +272,16 @@ void QtControllerSelectorDialog::ApplyConfiguration() { void QtControllerSelectorDialog::LoadConfiguration() { for (std::size_t index = 0; index < NUM_PLAYERS; ++index) { - const auto connected = Settings::values.players.GetValue()[index].connected || - (index == 0 && Settings::values.players.GetValue()[8].connected); + const auto connected = + Settings::values.players.GetValue()[index].connected || + (index == 0 && Settings::values.players.GetValue()[HANDHELD_INDEX].connected); player_groupboxes[index]->setChecked(connected); connected_controller_checkboxes[index]->setChecked(connected); emulated_controllers[index]->setCurrentIndex( GetIndexFromControllerType(Settings::values.players.GetValue()[index].controller_type)); } - UpdateDockedState(Settings::values.players.GetValue()[8].connected); + UpdateDockedState(Settings::values.players.GetValue()[HANDHELD_INDEX].connected); ui->vibrationGroup->setChecked(Settings::values.vibration_enabled.GetValue()); ui->motionGroup->setChecked(Settings::values.motion_enabled.GetValue()); @@ -468,32 +466,46 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) { auto& player = Settings::values.players.GetValue()[player_index]; - player.controller_type = + const auto controller_type = GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex()); - player.connected = player_groupboxes[player_index]->isChecked(); + const auto player_connected = player_groupboxes[player_index]->isChecked() && + controller_type != Settings::ControllerType::Handheld; - // Player 2-8 - if (player_index != 0) { - UpdateController(player.controller_type, player_index, player.connected); + if (player.controller_type == controller_type && player.connected == player_connected) { + // Set vibration devices in the event that the input device has changed. + ConfigureVibration::SetVibrationDevices(player_index); return; } + // Disconnect the controller first. + UpdateController(controller_type, player_index, false); + + player.controller_type = controller_type; + player.connected = player_connected; + ConfigureVibration::SetVibrationDevices(player_index); - // Player 1 and Handheld - auto& handheld = Settings::values.players.GetValue()[8]; - // If Handheld is selected, copy all the settings from Player 1 to Handheld. - if (player.controller_type == Settings::ControllerType::Handheld) { - handheld = player; - handheld.connected = player_groupboxes[player_index]->isChecked(); - player.connected = false; // Disconnect Player 1 - } else { - player.connected = player_groupboxes[player_index]->isChecked(); - handheld.connected = false; // Disconnect Handheld + // Handheld + if (player_index == 0) { + auto& handheld = Settings::values.players.GetValue()[HANDHELD_INDEX]; + if (controller_type == Settings::ControllerType::Handheld) { + handheld = player; + } + handheld.connected = player_groupboxes[player_index]->isChecked() && + controller_type == Settings::ControllerType::Handheld; + UpdateController(Settings::ControllerType::Handheld, 8, handheld.connected); } - UpdateController(player.controller_type, player_index, player.connected); - UpdateController(Settings::ControllerType::Handheld, 8, handheld.connected); + if (!player.connected) { + return; + } + + // This emulates a delay between disconnecting and reconnecting controllers as some games + // do not respond to a change in controller type if it was instantaneous. + using namespace std::chrono_literals; + std::this_thread::sleep_for(20ms); + + UpdateController(controller_type, player_index, player_connected); } void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) { diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 3e785c2243..1ee4725ef4 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -26,8 +26,6 @@ #include "yuzu/configuration/input_profiles.h" #include "yuzu/util/limitable_input_dialog.h" -constexpr std::size_t HANDHELD_INDEX = 8; - const std::array ConfigureInputPlayer::analog_sub_buttons{{ "up", @@ -38,12 +36,10 @@ const std::array namespace { +constexpr std::size_t HANDHELD_INDEX = 8; + void UpdateController(Settings::ControllerType controller_type, std::size_t npad_index, bool connected) { - auto& player = Settings::values.players.GetValue()[npad_index]; - player.controller_type = controller_type; - player.connected = connected; - Core::System& system{Core::System::GetInstance()}; if (!system.IsPoweredOn()) { return; @@ -563,35 +559,50 @@ void ConfigureInputPlayer::ApplyConfiguration() { } auto& motions = player.motions; + std::transform(motions_param.begin(), motions_param.end(), motions.begin(), [](const Common::ParamPackage& param) { return param.Serialize(); }); - player.controller_type = - static_cast(ui->comboControllerType->currentIndex()); - player.connected = ui->groupConnectedController->isChecked(); + const auto controller_type = + GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); + const auto player_connected = ui->groupConnectedController->isChecked() && + controller_type != Settings::ControllerType::Handheld; - ConfigureVibration::SetVibrationDevices(player_index); - - // Player 2-8 - if (player_index != 0) { - UpdateController(player.controller_type, player_index, player.connected); + if (player.controller_type == controller_type && player.connected == player_connected) { + // Set vibration devices in the event that the input device has changed. + ConfigureVibration::SetVibrationDevices(player_index); return; } - // Player 1 and Handheld - auto& handheld = Settings::values.players.GetValue()[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 + // Disconnect the controller first. + UpdateController(controller_type, player_index, false); + + player.controller_type = controller_type; + player.connected = player_connected; + + ConfigureVibration::SetVibrationDevices(player_index); + + // Handheld + if (player_index == 0) { + auto& handheld = Settings::values.players.GetValue()[HANDHELD_INDEX]; + if (controller_type == Settings::ControllerType::Handheld) { + handheld = player; + } + handheld.connected = ui->groupConnectedController->isChecked() && + controller_type == Settings::ControllerType::Handheld; + UpdateController(Settings::ControllerType::Handheld, HANDHELD_INDEX, handheld.connected); } - UpdateController(player.controller_type, player_index, player.connected); - UpdateController(Settings::ControllerType::Handheld, HANDHELD_INDEX, handheld.connected); + if (!player.connected) { + return; + } + + // This emulates a delay between disconnecting and reconnecting controllers as some games + // do not respond to a change in controller type if it was instantaneous. + using namespace std::chrono_literals; + std::this_thread::sleep_for(20ms); + + UpdateController(controller_type, player_index, player_connected); } void ConfigureInputPlayer::showEvent(QShowEvent* event) {