From 904ac1daec186a98c33f2e8ac140d919ca8fe0a7 Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Mon, 21 Dec 2020 10:46:19 -0500
Subject: [PATCH] configure_input: Modify controller connection delay

Increases the controller connection delay to 60ms and refactors it to attempt to disconnect all controllers prior to connecting all controllers in HID.
---
 src/yuzu/applets/controller.cpp               |  2 +-
 src/yuzu/configuration/configure_input.cpp    | 13 +++++++-
 .../configuration/configure_input_player.cpp  | 32 +++++++++++++------
 .../configuration/configure_input_player.h    | 12 +++++++
 4 files changed, 47 insertions(+), 12 deletions(-)

diff --git a/src/yuzu/applets/controller.cpp b/src/yuzu/applets/controller.cpp
index a15e8ca2a..c680fd2c2 100644
--- a/src/yuzu/applets/controller.cpp
+++ b/src/yuzu/applets/controller.cpp
@@ -535,7 +535,7 @@ void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index)
     // 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);
+    std::this_thread::sleep_for(60ms);
 
     UpdateController(controller_type, player_index, player_connected);
 }
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index d9009091b..567a36d9b 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -4,6 +4,7 @@
 
 #include <algorithm>
 #include <memory>
+#include <thread>
 
 #include <QSignalBlocker>
 #include <QTimer>
@@ -181,8 +182,18 @@ QList<QWidget*> ConfigureInput::GetSubTabs() const {
 }
 
 void ConfigureInput::ApplyConfiguration() {
-    for (auto controller : player_controllers) {
+    for (auto* controller : player_controllers) {
         controller->ApplyConfiguration();
+        controller->TryDisconnectSelectedController();
+    }
+
+    // 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(60ms);
+
+    for (auto* controller : player_controllers) {
+        controller->TryConnectSelectedController();
     }
 
     advanced->ApplyConfiguration();
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 3c7500ee3..46ea026e4 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -4,7 +4,6 @@
 
 #include <algorithm>
 #include <memory>
-#include <thread>
 #include <utility>
 #include <QGridLayout>
 #include <QInputDialog>
@@ -576,6 +575,10 @@ void ConfigureInputPlayer::ApplyConfiguration() {
 
     std::transform(motions_param.begin(), motions_param.end(), motions.begin(),
                    [](const Common::ParamPackage& param) { return param.Serialize(); });
+}
+
+void ConfigureInputPlayer::TryConnectSelectedController() {
+    auto& player = Settings::values.players.GetValue()[player_index];
 
     const auto controller_type =
         GetControllerTypeFromIndex(ui->comboControllerType->currentIndex());
@@ -588,15 +591,12 @@ void ConfigureInputPlayer::ApplyConfiguration() {
         return;
     }
 
-    // Disconnect the controller first.
-    UpdateController(controller_type, player_index, false);
-
     player.controller_type = controller_type;
     player.connected = player_connected;
 
     ConfigureVibration::SetVibrationDevices(player_index);
 
-    // Handheld
+    // Connect/Disconnect Handheld depending on Player 1's controller configuration.
     if (player_index == 0) {
         auto& handheld = Settings::values.players.GetValue()[HANDHELD_INDEX];
         if (controller_type == Settings::ControllerType::Handheld) {
@@ -611,14 +611,26 @@ void ConfigureInputPlayer::ApplyConfiguration() {
         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::TryDisconnectSelectedController() {
+    const auto& player = Settings::values.players.GetValue()[player_index];
+
+    const auto controller_type =
+        GetControllerTypeFromIndex(ui->comboControllerType->currentIndex());
+    const auto player_connected = ui->groupConnectedController->isChecked() &&
+                                  controller_type != Settings::ControllerType::Handheld;
+
+    // Do not do anything if the controller configuration has not changed.
+    if (player.controller_type == controller_type && player.connected == player_connected) {
+        return;
+    }
+
+    // Disconnect the controller first.
+    UpdateController(controller_type, player_index, false);
+}
+
 void ConfigureInputPlayer::showEvent(QShowEvent* event) {
     if (bottom_row == nullptr) {
         return;
diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h
index 9c30879a2..c4ae50de7 100644
--- a/src/yuzu/configuration/configure_input_player.h
+++ b/src/yuzu/configuration/configure_input_player.h
@@ -54,6 +54,18 @@ public:
     /// Save all button configurations to settings file.
     void ApplyConfiguration();
 
+    /**
+     * Attempts to connect the currently selected controller in the HID backend.
+     * This function will not do anything if it is not connected in the frontend.
+     */
+    void TryConnectSelectedController();
+
+    /**
+     * Attempts to disconnect the currently selected controller in the HID backend.
+     * This function will not do anything if the configuration has not changed.
+     */
+    void TryDisconnectSelectedController();
+
     /// Set the connection state checkbox (used to sync state).
     void ConnectPlayer(bool connected);