From 7fe455e42ea1a8d5e702258212d54f21f1f31610 Mon Sep 17 00:00:00 2001
From: german77 <juangerman-13@hotmail.com>
Date: Sat, 4 Dec 2021 19:37:03 -0600
Subject: [PATCH] core/hid: Ensure only valid npad are connected

---
 src/core/hid/emulated_controller.cpp          |  43 +++++
 src/core/hid/emulated_controller.h            |  14 ++
 src/core/hid/hid_core.cpp                     |  10 ++
 src/core/hid/hid_core.h                       |   2 +-
 src/core/hid/hid_types.h                      |   2 +
 src/core/hle/service/hid/controllers/npad.cpp |  30 ++--
 .../configuration/configure_input_player.cpp  | 149 ++++++++----------
 src/yuzu/main.cpp                             |   3 +
 8 files changed, 156 insertions(+), 97 deletions(-)

diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
index 466ff55423..7207067941 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -866,7 +866,50 @@ void EmulatedController::SetLedPattern() {
     }
 }
 
+void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles) {
+    supported_style_tag = supported_styles;
+    if (!is_connected) {
+        return;
+    }
+    if (!IsControllerSupported()) {
+        LOG_ERROR(Service_HID, "Controller type {} is not supported. Disconnecting controller",
+                  npad_type);
+        Disconnect();
+    }
+}
+
+bool EmulatedController::IsControllerSupported() const {
+    switch (npad_type) {
+    case NpadStyleIndex::ProController:
+        return supported_style_tag.fullkey;
+    case NpadStyleIndex::JoyconDual:
+        return supported_style_tag.joycon_dual;
+    case NpadStyleIndex::JoyconLeft:
+        return supported_style_tag.joycon_left;
+    case NpadStyleIndex::JoyconRight:
+        return supported_style_tag.joycon_right;
+    case NpadStyleIndex::GameCube:
+        return supported_style_tag.gamecube;
+    case NpadStyleIndex::Pokeball:
+        return supported_style_tag.palma;
+    case NpadStyleIndex::NES:
+        return supported_style_tag.lark;
+    case NpadStyleIndex::SNES:
+        return supported_style_tag.lucia;
+    case NpadStyleIndex::N64:
+        return supported_style_tag.lagoon;
+    case NpadStyleIndex::SegaGenesis:
+        return supported_style_tag.lager;
+    default:
+        return false;
+    }
+}
+
 void EmulatedController::Connect() {
+    if (!IsControllerSupported()) {
+        LOG_ERROR(Service_HID, "Controller type {} is not supported", npad_type);
+        return;
+    }
     {
         std::lock_guard lock{mutex};
         if (is_configuring) {
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h
index 5887e3e38c..425b3e7c47 100644
--- a/src/core/hid/emulated_controller.h
+++ b/src/core/hid/emulated_controller.h
@@ -160,6 +160,13 @@ public:
      */
     NpadStyleIndex GetNpadStyleIndex(bool get_temporary_value = false) const;
 
+    /**
+     * Sets the supported controller types. Disconnects the controller if current type is not
+     * supported
+     * @param supported_styles bitflag with supported types
+     */
+    void SetSupportedNpadStyleTag(NpadStyleTag supported_styles);
+
     /// Sets the connected status to true
     void Connect();
 
@@ -310,6 +317,12 @@ private:
     /// Set the params for TAS devices
     void LoadTASParams();
 
+    /**
+     * Checks the current controller type against the supported_style_tag
+     * @return true if the controller is supported
+     */
+    bool IsControllerSupported() const;
+
     /**
      * Updates the button status of the controller
      * @param callback A CallbackStatus containing the button status
@@ -354,6 +367,7 @@ private:
 
     NpadIdType npad_id_type;
     NpadStyleIndex npad_type{NpadStyleIndex::None};
+    NpadStyleTag supported_style_tag{NpadStyleSet::All};
     bool is_connected{false};
     bool is_configuring{false};
     f32 motion_sensitivity{0.01f};
diff --git a/src/core/hid/hid_core.cpp b/src/core/hid/hid_core.cpp
index 946adde006..0c3eb5a62e 100644
--- a/src/core/hid/hid_core.cpp
+++ b/src/core/hid/hid_core.cpp
@@ -108,6 +108,16 @@ const EmulatedController* HIDCore::GetEmulatedControllerByIndex(std::size_t inde
 
 void HIDCore::SetSupportedStyleTag(NpadStyleTag style_tag) {
     supported_style_tag.raw = style_tag.raw;
+    player_1->SetSupportedNpadStyleTag(supported_style_tag);
+    player_2->SetSupportedNpadStyleTag(supported_style_tag);
+    player_3->SetSupportedNpadStyleTag(supported_style_tag);
+    player_4->SetSupportedNpadStyleTag(supported_style_tag);
+    player_5->SetSupportedNpadStyleTag(supported_style_tag);
+    player_6->SetSupportedNpadStyleTag(supported_style_tag);
+    player_7->SetSupportedNpadStyleTag(supported_style_tag);
+    player_8->SetSupportedNpadStyleTag(supported_style_tag);
+    other->SetSupportedNpadStyleTag(supported_style_tag);
+    handheld->SetSupportedNpadStyleTag(supported_style_tag);
 }
 
 NpadStyleTag HIDCore::GetSupportedStyleTag() const {
diff --git a/src/core/hid/hid_core.h b/src/core/hid/hid_core.h
index 140a0e9629..2fb0f7e19e 100644
--- a/src/core/hid/hid_core.h
+++ b/src/core/hid/hid_core.h
@@ -73,7 +73,7 @@ private:
     std::unique_ptr<EmulatedController> handheld;
     std::unique_ptr<EmulatedConsole> console;
     std::unique_ptr<EmulatedDevices> devices;
-    NpadStyleTag supported_style_tag;
+    NpadStyleTag supported_style_tag{NpadStyleSet::All};
 };
 
 } // namespace Core::HID
diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h
index 780659b86d..7c12f01fc8 100644
--- a/src/core/hid/hid_types.h
+++ b/src/core/hid/hid_types.h
@@ -256,6 +256,8 @@ enum class NpadStyleSet : u32 {
     Lager = 1U << 11,
     SystemExt = 1U << 29,
     System = 1U << 30,
+
+    All = 0xFFFFFFFFU,
 };
 static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size");
 
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 6916930f75..ae56f10cf8 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -126,8 +126,11 @@ void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type,
 }
 
 void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
-    LOG_DEBUG(Service_HID, "Npad connected {}", npad_id);
     auto& controller = GetControllerFromNpadIdType(npad_id);
+    if (!IsControllerSupported(controller.device->GetNpadStyleIndex())) {
+        return;
+    }
+    LOG_DEBUG(Service_HID, "Npad connected {}", npad_id);
     const auto controller_type = controller.device->GetNpadStyleIndex();
     auto& shared_memory = controller.shared_memory_entry;
     if (controller_type == Core::HID::NpadStyleIndex::None) {
@@ -255,19 +258,7 @@ void Controller_NPad::OnInit() {
 
     if (hid_core.GetSupportedStyleTag().raw == Core::HID::NpadStyleSet::None) {
         // We want to support all controllers
-        Core::HID::NpadStyleTag style{};
-        style.handheld.Assign(1);
-        style.joycon_left.Assign(1);
-        style.joycon_right.Assign(1);
-        style.joycon_dual.Assign(1);
-        style.fullkey.Assign(1);
-        style.gamecube.Assign(1);
-        style.palma.Assign(1);
-        style.lark.Assign(1);
-        style.lucia.Assign(1);
-        style.lagoon.Assign(1);
-        style.lager.Assign(1);
-        hid_core.SetSupportedStyleTag(style);
+        hid_core.SetSupportedStyleTag({Core::HID::NpadStyleSet::All});
     }
 
     supported_npad_id_types.resize(npad_id_list.size());
@@ -1072,13 +1063,18 @@ bool Controller_NPad::SwapNpadAssignment(Core::HID::NpadIdType npad_id_1,
     const auto& controller_2 = GetControllerFromNpadIdType(npad_id_2).device;
     const auto type_index_1 = controller_1->GetNpadStyleIndex();
     const auto type_index_2 = controller_2->GetNpadStyleIndex();
+    const auto is_connected_1 = controller_1->IsConnected();
+    const auto is_connected_2 = controller_2->IsConnected();
 
-    if (!IsControllerSupported(type_index_1) || !IsControllerSupported(type_index_2)) {
+    if (!IsControllerSupported(type_index_1) && is_connected_1) {
+        return false;
+    }
+    if (!IsControllerSupported(type_index_2) && is_connected_2) {
         return false;
     }
 
-    AddNewControllerAt(type_index_2, npad_id_1);
-    AddNewControllerAt(type_index_1, npad_id_2);
+    UpdateControllerAt(type_index_2, npad_id_1, is_connected_2);
+    UpdateControllerAt(type_index_1, npad_id_2, is_connected_1);
 
     return true;
 }
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 34099bc835..8a8be8e406 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -907,88 +907,79 @@ void ConfigureInputPlayer::UpdateUI() {
 }
 
 void ConfigureInputPlayer::SetConnectableControllers() {
-    const auto add_controllers = [this](bool enable_all,
-                                        Core::HID::NpadStyleTag npad_style_set = {}) {
-        index_controller_type_pairs.clear();
-        ui->comboControllerType->clear();
+    Core::HID::NpadStyleTag npad_style_set = hid_core.GetSupportedStyleTag();
+    index_controller_type_pairs.clear();
+    ui->comboControllerType->clear();
 
-        if (enable_all || npad_style_set.fullkey == 1) {
-            index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
-                                                     Core::HID::NpadStyleIndex::ProController);
-            ui->comboControllerType->addItem(tr("Pro Controller"));
-        }
-
-        if (enable_all || npad_style_set.joycon_dual == 1) {
-            index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
-                                                     Core::HID::NpadStyleIndex::JoyconDual);
-            ui->comboControllerType->addItem(tr("Dual Joycons"));
-        }
-
-        if (enable_all || npad_style_set.joycon_left == 1) {
-            index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
-                                                     Core::HID::NpadStyleIndex::JoyconLeft);
-            ui->comboControllerType->addItem(tr("Left Joycon"));
-        }
-
-        if (enable_all || npad_style_set.joycon_right == 1) {
-            index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
-                                                     Core::HID::NpadStyleIndex::JoyconRight);
-            ui->comboControllerType->addItem(tr("Right Joycon"));
-        }
-
-        if (player_index == 0 && (enable_all || npad_style_set.handheld == 1)) {
-            index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
-                                                     Core::HID::NpadStyleIndex::Handheld);
-            ui->comboControllerType->addItem(tr("Handheld"));
-        }
-
-        if (enable_all || npad_style_set.gamecube == 1) {
-            index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
-                                                     Core::HID::NpadStyleIndex::GameCube);
-            ui->comboControllerType->addItem(tr("GameCube Controller"));
-        }
-
-        // Disable all unsupported controllers
-        if (!Settings::values.enable_all_controllers) {
-            return;
-        }
-        if (enable_all || npad_style_set.palma == 1) {
-            index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
-                                                     Core::HID::NpadStyleIndex::Pokeball);
-            ui->comboControllerType->addItem(tr("Poke Ball Plus"));
-        }
-
-        if (enable_all || npad_style_set.lark == 1) {
-            index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
-                                                     Core::HID::NpadStyleIndex::NES);
-            ui->comboControllerType->addItem(tr("NES Controller"));
-        }
-
-        if (enable_all || npad_style_set.lucia == 1) {
-            index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
-                                                     Core::HID::NpadStyleIndex::SNES);
-            ui->comboControllerType->addItem(tr("SNES Controller"));
-        }
-
-        if (enable_all || npad_style_set.lagoon == 1) {
-            index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
-                                                     Core::HID::NpadStyleIndex::N64);
-            ui->comboControllerType->addItem(tr("N64 Controller"));
-        }
-
-        if (enable_all || npad_style_set.lager == 1) {
-            index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
-                                                     Core::HID::NpadStyleIndex::SegaGenesis);
-            ui->comboControllerType->addItem(tr("Sega Genesis"));
-        }
-    };
-
-    if (!is_powered_on) {
-        add_controllers(true);
-        return;
+    if (npad_style_set.fullkey == 1) {
+        index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
+                                                 Core::HID::NpadStyleIndex::ProController);
+        ui->comboControllerType->addItem(tr("Pro Controller"));
     }
 
-    add_controllers(false, hid_core.GetSupportedStyleTag());
+    if (npad_style_set.joycon_dual == 1) {
+        index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
+                                                 Core::HID::NpadStyleIndex::JoyconDual);
+        ui->comboControllerType->addItem(tr("Dual Joycons"));
+    }
+
+    if (npad_style_set.joycon_left == 1) {
+        index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
+                                                 Core::HID::NpadStyleIndex::JoyconLeft);
+        ui->comboControllerType->addItem(tr("Left Joycon"));
+    }
+
+    if (npad_style_set.joycon_right == 1) {
+        index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
+                                                 Core::HID::NpadStyleIndex::JoyconRight);
+        ui->comboControllerType->addItem(tr("Right Joycon"));
+    }
+
+    if (player_index == 0 && npad_style_set.handheld == 1) {
+        index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
+                                                 Core::HID::NpadStyleIndex::Handheld);
+        ui->comboControllerType->addItem(tr("Handheld"));
+    }
+
+    if (npad_style_set.gamecube == 1) {
+        index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
+                                                 Core::HID::NpadStyleIndex::GameCube);
+        ui->comboControllerType->addItem(tr("GameCube Controller"));
+    }
+
+    // Disable all unsupported controllers
+    if (!Settings::values.enable_all_controllers) {
+        return;
+    }
+    if (npad_style_set.palma == 1) {
+        index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
+                                                 Core::HID::NpadStyleIndex::Pokeball);
+        ui->comboControllerType->addItem(tr("Poke Ball Plus"));
+    }
+
+    if (npad_style_set.lark == 1) {
+        index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
+                                                 Core::HID::NpadStyleIndex::NES);
+        ui->comboControllerType->addItem(tr("NES Controller"));
+    }
+
+    if (npad_style_set.lucia == 1) {
+        index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
+                                                 Core::HID::NpadStyleIndex::SNES);
+        ui->comboControllerType->addItem(tr("SNES Controller"));
+    }
+
+    if (npad_style_set.lagoon == 1) {
+        index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
+                                                 Core::HID::NpadStyleIndex::N64);
+        ui->comboControllerType->addItem(tr("N64 Controller"));
+    }
+
+    if (npad_style_set.lager == 1) {
+        index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
+                                                 Core::HID::NpadStyleIndex::SegaGenesis);
+        ui->comboControllerType->addItem(tr("Sega Genesis"));
+    }
 }
 
 Core::HID::NpadStyleIndex ConfigureInputPlayer::GetControllerTypeFromIndex(int index) const {
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index f266fd9632..5a9dec8f3a 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1516,6 +1516,9 @@ void GMainWindow::ShutdownGame() {
     input_subsystem->GetTas()->Stop();
     OnTasStateChanged();
 
+    // Enable all controllers
+    system->HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All});
+
     render_window->removeEventFilter(render_window);
     render_window->setAttribute(Qt::WA_Hover, false);