summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar german772021-10-18 23:15:46 -0500
committerGravatar Narr the Reg2021-11-24 20:30:24 -0600
commit4d308fd0b4fc8f14754c47811e751bf068b330b8 (patch)
tree3ea29a0c024fdc9ad7681aaf6160e46511ceb2a6
parentcore/hid: Documment some files (diff)
downloadyuzu-4d308fd0b4fc8f14754c47811e751bf068b330b8.tar.gz
yuzu-4d308fd0b4fc8f14754c47811e751bf068b330b8.tar.xz
yuzu-4d308fd0b4fc8f14754c47811e751bf068b330b8.zip
hid: Fix controller connection/disconnection
-rw-r--r--src/core/hid/emulated_console.cpp1
-rw-r--r--src/core/hid/emulated_controller.cpp98
-rw-r--r--src/core/hid/emulated_controller.h18
-rw-r--r--src/core/hid/hid_types.h8
-rw-r--r--src/core/hle/service/hid/controllers/controller_base.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp77
-rw-r--r--src/core/hle/service/hid/controllers/npad.h3
-rw-r--r--src/yuzu/configuration/configure_input.cpp1
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp81
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.cpp2
10 files changed, 226 insertions, 65 deletions
diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp
index c65d05041..7f7c8fd59 100644
--- a/src/core/hid/emulated_console.cpp
+++ b/src/core/hid/emulated_console.cpp
@@ -53,7 +53,6 @@ void EmulatedConsole::ReloadInput() {
53 touch_button_params.Set("x", x); 53 touch_button_params.Set("x", x);
54 touch_button_params.Set("y", y); 54 touch_button_params.Set("y", y);
55 touch_button_params.Set("touch_id", static_cast<int>(index)); 55 touch_button_params.Set("touch_id", static_cast<int>(index));
56 LOG_ERROR(Common, "{} ", touch_button_params.Serialize());
57 touch_devices[index] = 56 touch_devices[index] =
58 Input::CreateDeviceFromString<Input::InputDevice>(touch_button_params.Serialize()); 57 Input::CreateDeviceFromString<Input::InputDevice>(touch_button_params.Serialize());
59 if (!touch_devices[index]) { 58 if (!touch_devices[index]) {
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
index b04ab4cd8..7ef6ef118 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -54,6 +54,7 @@ Settings::ControllerType EmulatedController::MapNPadToSettingsType(NpadType type
54} 54}
55 55
56void EmulatedController::ReloadFromSettings() { 56void EmulatedController::ReloadFromSettings() {
57 //LOG_ERROR(Service_HID, "reload config from settings {}", NpadIdTypeToIndex(npad_id_type));
57 const auto player_index = NpadIdTypeToIndex(npad_id_type); 58 const auto player_index = NpadIdTypeToIndex(npad_id_type);
58 const auto& player = Settings::values.players.GetValue()[player_index]; 59 const auto& player = Settings::values.players.GetValue()[player_index];
59 60
@@ -91,6 +92,7 @@ void EmulatedController::ReloadFromSettings() {
91} 92}
92 93
93void EmulatedController::ReloadInput() { 94void EmulatedController::ReloadInput() {
95 //LOG_ERROR(Service_HID, "reload config {}", NpadIdTypeToIndex(npad_id_type));
94 // If you load any device here add the equivalent to the UnloadInput() function 96 // If you load any device here add the equivalent to the UnloadInput() function
95 const auto player_index = NpadIdTypeToIndex(npad_id_type); 97 const auto player_index = NpadIdTypeToIndex(npad_id_type);
96 const auto left_side = button_params[Settings::NativeButton::ZL]; 98 const auto left_side = button_params[Settings::NativeButton::ZL];
@@ -187,11 +189,29 @@ void EmulatedController::UnloadInput() {
187 189
188void EmulatedController::EnableConfiguration() { 190void EmulatedController::EnableConfiguration() {
189 is_configuring = true; 191 is_configuring = true;
190 SaveCurrentConfig(); 192 temporary_is_connected = is_connected;
193 temporary_npad_type = npad_type;
191} 194}
192 195
193void EmulatedController::DisableConfiguration() { 196void EmulatedController::DisableConfiguration() {
194 is_configuring = false; 197 is_configuring = false;
198
199 // Apply temporary npad type to the real controller
200 if (temporary_npad_type != npad_type) {
201 if (is_connected) {
202 Disconnect();
203 }
204 SetNpadType(temporary_npad_type);
205 }
206
207 // Apply temporary connected status to the real controller
208 if (temporary_is_connected != is_connected) {
209 if (temporary_is_connected) {
210 Connect();
211 return;
212 }
213 Disconnect();
214 }
195} 215}
196 216
197bool EmulatedController::IsConfiguring() const { 217bool EmulatedController::IsConfiguring() const {
@@ -199,10 +219,6 @@ bool EmulatedController::IsConfiguring() const {
199} 219}
200 220
201void EmulatedController::SaveCurrentConfig() { 221void EmulatedController::SaveCurrentConfig() {
202 if (!is_configuring) {
203 return;
204 }
205
206 const auto player_index = NpadIdTypeToIndex(npad_id_type); 222 const auto player_index = NpadIdTypeToIndex(npad_id_type);
207 auto& player = Settings::values.players.GetValue()[player_index]; 223 auto& player = Settings::values.players.GetValue()[player_index];
208 player.connected = is_connected; 224 player.connected = is_connected;
@@ -657,26 +673,47 @@ void EmulatedController::SetLedPattern() {
657} 673}
658 674
659void EmulatedController::Connect() { 675void EmulatedController::Connect() {
660 std::lock_guard lock{mutex}; 676 {
661 if (is_connected) { 677 std::lock_guard lock{mutex};
662 LOG_WARNING(Service_HID, "Tried to turn on a connected controller {}", npad_id_type); 678 if (is_configuring) {
663 return; 679 temporary_is_connected = true;
680 TriggerOnChange(ControllerTriggerType::Connected);
681 return;
682 }
683
684 if (is_connected) {
685 return;
686 }
687 is_connected = true;
664 } 688 }
665 is_connected = true; 689 LOG_ERROR(Service_HID, "Connected controller {}", NpadIdTypeToIndex(npad_id_type));
666 TriggerOnChange(ControllerTriggerType::Connected); 690 TriggerOnChange(ControllerTriggerType::Connected);
667} 691}
668 692
669void EmulatedController::Disconnect() { 693void EmulatedController::Disconnect() {
670 std::lock_guard lock{mutex}; 694 {
671 if (!is_connected) { 695 std::lock_guard lock{mutex};
672 LOG_WARNING(Service_HID, "Tried to turn off a disconnected controller {}", npad_id_type); 696 if (is_configuring) {
673 return; 697 temporary_is_connected = false;
698 LOG_ERROR(Service_HID, "Disconnected temporal controller {}",
699 NpadIdTypeToIndex(npad_id_type));
700 TriggerOnChange(ControllerTriggerType::Disconnected);
701 return;
702 }
703
704 if (!is_connected) {
705 return;
706 }
707 is_connected = false;
674 } 708 }
675 is_connected = false; 709 LOG_ERROR(Service_HID, "Disconnected controller {}", NpadIdTypeToIndex(npad_id_type));
676 TriggerOnChange(ControllerTriggerType::Disconnected); 710 TriggerOnChange(ControllerTriggerType::Disconnected);
677} 711}
678 712
679bool EmulatedController::IsConnected() const { 713bool EmulatedController::IsConnected(bool temporary) const {
714 if (temporary) {
715 return temporary_is_connected;
716 }
680 return is_connected; 717 return is_connected;
681} 718}
682 719
@@ -688,16 +725,35 @@ NpadIdType EmulatedController::GetNpadIdType() const {
688 return npad_id_type; 725 return npad_id_type;
689} 726}
690 727
691NpadType EmulatedController::GetNpadType() const { 728NpadType EmulatedController::GetNpadType(bool temporary) const {
729 if (temporary) {
730 return temporary_npad_type;
731 }
692 return npad_type; 732 return npad_type;
693} 733}
694 734
695void EmulatedController::SetNpadType(NpadType npad_type_) { 735void EmulatedController::SetNpadType(NpadType npad_type_) {
696 std::lock_guard lock{mutex}; 736 {
697 if (npad_type == npad_type_) { 737 std::lock_guard lock{mutex};
698 return; 738
739 if (is_configuring) {
740 if (temporary_npad_type == npad_type_) {
741 return;
742 }
743 temporary_npad_type = npad_type_;
744 TriggerOnChange(ControllerTriggerType::Type);
745 return;
746 }
747
748 if (npad_type == npad_type_) {
749 return;
750 }
751 if (is_connected) {
752 LOG_WARNING(Service_HID, "Controller {} type changed while it's connected",
753 NpadIdTypeToIndex(npad_id_type));
754 }
755 npad_type = npad_type_;
699 } 756 }
700 npad_type = npad_type_;
701 TriggerOnChange(ControllerTriggerType::Type); 757 TriggerOnChange(ControllerTriggerType::Type);
702} 758}
703 759
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h
index 096fe1705..6a6dc1892 100644
--- a/src/core/hid/emulated_controller.h
+++ b/src/core/hid/emulated_controller.h
@@ -139,8 +139,12 @@ public:
139 /// Sets the NpadType for this controller 139 /// Sets the NpadType for this controller
140 void SetNpadType(NpadType npad_type_); 140 void SetNpadType(NpadType npad_type_);
141 141
142 /// Gets the NpadType for this controller 142 /**
143 NpadType GetNpadType() const; 143 * Gets the NpadType for this controller
144 * @param Returns the temporary value if true
145 * @return NpadType set on the controller
146 */
147 NpadType GetNpadType(bool temporary = false) const;
144 148
145 /// Sets the connected status to true 149 /// Sets the connected status to true
146 void Connect(); 150 void Connect();
@@ -148,8 +152,12 @@ public:
148 /// Sets the connected status to false 152 /// Sets the connected status to false
149 void Disconnect(); 153 void Disconnect();
150 154
151 /// Returns true if the controller has the connected status 155 /**
152 bool IsConnected() const; 156 * Is the emulated connected
157 * @param Returns the temporary value if true
158 * @return true if the controller has the connected status
159 */
160 bool IsConnected(bool temporary = false) const;
153 161
154 /// Returns true if vibration is enabled 162 /// Returns true if vibration is enabled
155 bool IsVibrationEnabled() const; 163 bool IsVibrationEnabled() const;
@@ -323,7 +331,9 @@ private:
323 331
324 NpadIdType npad_id_type; 332 NpadIdType npad_id_type;
325 NpadType npad_type{NpadType::None}; 333 NpadType npad_type{NpadType::None};
334 NpadType temporary_npad_type{NpadType::None};
326 bool is_connected{false}; 335 bool is_connected{false};
336 bool temporary_is_connected{false};
327 bool is_configuring{false}; 337 bool is_configuring{false};
328 bool is_vibration_enabled{true}; 338 bool is_vibration_enabled{true};
329 f32 motion_sensitivity{0.01f}; 339 f32 motion_sensitivity{0.01f};
diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h
index f12a14cb8..539436283 100644
--- a/src/core/hid/hid_types.h
+++ b/src/core/hid/hid_types.h
@@ -47,9 +47,9 @@ constexpr size_t NpadIdTypeToIndex(NpadIdType npad_id_type) {
47 return 6; 47 return 6;
48 case NpadIdType::Player8: 48 case NpadIdType::Player8:
49 return 7; 49 return 7;
50 case NpadIdType::Other:
51 return 8;
52 case NpadIdType::Handheld: 50 case NpadIdType::Handheld:
51 return 8;
52 case NpadIdType::Other:
53 return 9; 53 return 9;
54 default: 54 default:
55 return 0; 55 return 0;
@@ -76,9 +76,9 @@ constexpr NpadIdType IndexToNpadIdType(size_t index) {
76 case 7: 76 case 7:
77 return NpadIdType::Player8; 77 return NpadIdType::Player8;
78 case 8: 78 case 8:
79 return NpadIdType::Other;
80 case 9:
81 return NpadIdType::Handheld; 79 return NpadIdType::Handheld;
80 case 9:
81 return NpadIdType::Other;
82 default: 82 default:
83 return NpadIdType::Invalid; 83 return NpadIdType::Invalid;
84 } 84 }
diff --git a/src/core/hle/service/hid/controllers/controller_base.cpp b/src/core/hle/service/hid/controllers/controller_base.cpp
index 9d1e6db6a..74a394784 100644
--- a/src/core/hle/service/hid/controllers/controller_base.cpp
+++ b/src/core/hle/service/hid/controllers/controller_base.cpp
@@ -11,7 +11,7 @@ ControllerBase::~ControllerBase() = default;
11 11
12void ControllerBase::ActivateController() { 12void ControllerBase::ActivateController() {
13 if (is_activated) { 13 if (is_activated) {
14 OnRelease(); 14 return;
15 } 15 }
16 is_activated = true; 16 is_activated = true;
17 OnInit(); 17 OnInit();
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index a2e9ddf4d..144abab65 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -125,18 +125,22 @@ void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type,
125 return; 125 return;
126 } 126 }
127 127
128 auto& controller = controller_data[controller_idx];
129 const auto is_connected = controller.device->IsConnected();
130 const auto npad_type = controller.device->GetNpadType();
128 switch (type) { 131 switch (type) {
129 case Core::HID::ControllerTriggerType::Connected: 132 case Core::HID::ControllerTriggerType::Connected:
130 InitNewlyAddedController(controller_idx);
131 break;
132 case Core::HID::ControllerTriggerType::Disconnected: 133 case Core::HID::ControllerTriggerType::Disconnected:
133 DisconnectNpadAtIndex(controller_idx); 134 if (is_connected == controller.is_connected) {
135 return;
136 }
137 UpdateControllerAt(npad_type, controller_idx, is_connected);
134 break; 138 break;
135 case Core::HID::ControllerTriggerType::Type: { 139 case Core::HID::ControllerTriggerType::Type: {
136 auto& controller = controller_data[controller_idx]; 140 if (npad_type == controller.npad_type) {
137 if (controller.device->IsConnected()) { 141 return;
138 LOG_ERROR(Service_HID, "Controller type changed without turning off the controller");
139 } 142 }
143 // UpdateControllerAt(npad_type, controller_idx, is_connected);
140 break; 144 break;
141 } 145 }
142 default: 146 default:
@@ -146,6 +150,7 @@ void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type,
146 150
147void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { 151void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
148 auto& controller = controller_data[controller_idx]; 152 auto& controller = controller_data[controller_idx];
153 LOG_ERROR(Service_HID, "Connect {} {}", controller_idx, controller.is_connected);
149 const auto controller_type = controller.device->GetNpadType(); 154 const auto controller_type = controller.device->GetNpadType();
150 auto& shared_memory = controller.shared_memory_entry; 155 auto& shared_memory = controller.shared_memory_entry;
151 if (controller_type == Core::HID::NpadType::None) { 156 if (controller_type == Core::HID::NpadType::None) {
@@ -235,20 +240,23 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
235 shared_memory.battery_level_left = battery_level.left.battery_level; 240 shared_memory.battery_level_left = battery_level.left.battery_level;
236 shared_memory.battery_level_right = battery_level.right.battery_level; 241 shared_memory.battery_level_right = battery_level.right.battery_level;
237 242
243 controller.is_connected = true;
244 controller.device->Connect();
238 SignalStyleSetChangedEvent(IndexToNPad(controller_idx)); 245 SignalStyleSetChangedEvent(IndexToNPad(controller_idx));
246 WriteEmptyEntry(controller.shared_memory_entry);
239} 247}
240 248
241void Controller_NPad::OnInit() { 249void Controller_NPad::OnInit() {
250 if (!IsControllerActivated()) {
251 return;
252 }
253
242 for (std::size_t i = 0; i < controller_data.size(); ++i) { 254 for (std::size_t i = 0; i < controller_data.size(); ++i) {
243 auto& controller = controller_data[i]; 255 auto& controller = controller_data[i];
244 controller.styleset_changed_event = 256 controller.styleset_changed_event =
245 service_context.CreateEvent(fmt::format("npad:NpadStyleSetChanged_{}", i)); 257 service_context.CreateEvent(fmt::format("npad:NpadStyleSetChanged_{}", i));
246 } 258 }
247 259
248 if (!IsControllerActivated()) {
249 return;
250 }
251
252 if (system.HIDCore().GetSupportedStyleTag().raw == 0) { 260 if (system.HIDCore().GetSupportedStyleTag().raw == 0) {
253 // We want to support all controllers 261 // We want to support all controllers
254 Core::HID::NpadStyleTag style{}; 262 Core::HID::NpadStyleTag style{};
@@ -277,20 +285,33 @@ void Controller_NPad::OnInit() {
277 for (auto& controller : controller_data) { 285 for (auto& controller : controller_data) {
278 NPadGenericState dummy_pad_state{}; 286 NPadGenericState dummy_pad_state{};
279 auto& npad = controller.shared_memory_entry; 287 auto& npad = controller.shared_memory_entry;
280 for (std::size_t i = 0; i < 17; ++i) { 288 for (std::size_t i = 0; i < 19; ++i) {
281 dummy_pad_state.sampling_number = 289 WriteEmptyEntry(npad);
282 npad.fullkey_lifo.ReadCurrentEntry().sampling_number + 1;
283 npad.fullkey_lifo.WriteNextEntry(dummy_pad_state);
284 npad.handheld_lifo.WriteNextEntry(dummy_pad_state);
285 npad.joy_dual_lifo.WriteNextEntry(dummy_pad_state);
286 npad.joy_left_lifo.WriteNextEntry(dummy_pad_state);
287 npad.joy_right_lifo.WriteNextEntry(dummy_pad_state);
288 npad.joy_right_lifo.WriteNextEntry(dummy_pad_state);
289 npad.palma_lifo.WriteNextEntry(dummy_pad_state);
290 } 290 }
291 } 291 }
292} 292}
293 293
294void Controller_NPad::WriteEmptyEntry(NpadInternalState& npad) {
295 NPadGenericState dummy_pad_state{};
296 NpadGcTriggerState dummy_gc_state{};
297 dummy_pad_state.sampling_number = npad.fullkey_lifo.ReadCurrentEntry().sampling_number + 1;
298 npad.fullkey_lifo.WriteNextEntry(dummy_pad_state);
299 dummy_pad_state.sampling_number = npad.handheld_lifo.ReadCurrentEntry().sampling_number + 1;
300 npad.handheld_lifo.WriteNextEntry(dummy_pad_state);
301 dummy_pad_state.sampling_number = npad.joy_dual_lifo.ReadCurrentEntry().sampling_number + 1;
302 npad.joy_dual_lifo.WriteNextEntry(dummy_pad_state);
303 dummy_pad_state.sampling_number = npad.joy_left_lifo.ReadCurrentEntry().sampling_number + 1;
304 npad.joy_left_lifo.WriteNextEntry(dummy_pad_state);
305 dummy_pad_state.sampling_number = npad.joy_right_lifo.ReadCurrentEntry().sampling_number + 1;
306 npad.joy_right_lifo.WriteNextEntry(dummy_pad_state);
307 dummy_pad_state.sampling_number = npad.palma_lifo.ReadCurrentEntry().sampling_number + 1;
308 npad.palma_lifo.WriteNextEntry(dummy_pad_state);
309 dummy_pad_state.sampling_number = npad.system_ext_lifo.ReadCurrentEntry().sampling_number + 1;
310 npad.system_ext_lifo.WriteNextEntry(dummy_pad_state);
311 dummy_gc_state.sampling_number = npad.gc_trigger_lifo.ReadCurrentEntry().sampling_number + 1;
312 npad.gc_trigger_lifo.WriteNextEntry(dummy_gc_state);
313}
314
294void Controller_NPad::OnRelease() { 315void Controller_NPad::OnRelease() {
295 for (std::size_t i = 0; i < controller_data.size(); ++i) { 316 for (std::size_t i = 0; i < controller_data.size(); ++i) {
296 auto& controller = controller_data[i]; 317 auto& controller = controller_data[i];
@@ -359,6 +380,7 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
359 if (!IsControllerActivated()) { 380 if (!IsControllerActivated()) {
360 return; 381 return;
361 } 382 }
383
362 for (std::size_t i = 0; i < controller_data.size(); ++i) { 384 for (std::size_t i = 0; i < controller_data.size(); ++i) {
363 auto& controller = controller_data[i]; 385 auto& controller = controller_data[i];
364 auto& npad = controller.shared_memory_entry; 386 auto& npad = controller.shared_memory_entry;
@@ -366,6 +388,9 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
366 const auto& controller_type = controller.device->GetNpadType(); 388 const auto& controller_type = controller.device->GetNpadType();
367 389
368 if (controller_type == Core::HID::NpadType::None || !controller.device->IsConnected()) { 390 if (controller_type == Core::HID::NpadType::None || !controller.device->IsConnected()) {
391 // Refresh shared memory
392 std::memcpy(data + NPAD_OFFSET + (i * sizeof(NpadInternalState)),
393 &controller.shared_memory_entry, sizeof(NpadInternalState));
369 continue; 394 continue;
370 } 395 }
371 const u32 npad_index = static_cast<u32>(i); 396 const u32 npad_index = static_cast<u32>(i);
@@ -830,14 +855,14 @@ void Controller_NPad::AddNewControllerAt(Core::HID::NpadType controller, std::si
830 855
831void Controller_NPad::UpdateControllerAt(Core::HID::NpadType type, std::size_t npad_index, 856void Controller_NPad::UpdateControllerAt(Core::HID::NpadType type, std::size_t npad_index,
832 bool connected) { 857 bool connected) {
833 auto& controller = controller_data[npad_index].device; 858 auto& controller = controller_data[npad_index];
834 if (!connected) { 859 if (!connected) {
835 DisconnectNpadAtIndex(npad_index); 860 DisconnectNpadAtIndex(npad_index);
836 return; 861 return;
837 } 862 }
838 863
839 controller->SetNpadType(type); 864 controller.device->SetNpadType(type);
840 controller->Connect(); 865 controller.device->Connect();
841 InitNewlyAddedController(npad_index); 866 InitNewlyAddedController(npad_index);
842} 867}
843 868
@@ -847,14 +872,13 @@ void Controller_NPad::DisconnectNpad(u32 npad_id) {
847 872
848void Controller_NPad::DisconnectNpadAtIndex(std::size_t npad_index) { 873void Controller_NPad::DisconnectNpadAtIndex(std::size_t npad_index) {
849 auto& controller = controller_data[npad_index]; 874 auto& controller = controller_data[npad_index];
875 LOG_ERROR(Service_HID, "Disconnect {} {}", npad_index, controller.is_connected);
850 for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) { 876 for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) {
851 // Send an empty vibration to stop any vibrations. 877 // Send an empty vibration to stop any vibrations.
852 VibrateControllerAtIndex(npad_index, device_idx, {}); 878 VibrateControllerAtIndex(npad_index, device_idx, {});
853 controller.vibration[device_idx].device_mounted = false; 879 controller.vibration[device_idx].device_mounted = false;
854 } 880 }
855 881
856 controller.device->Disconnect();
857
858 auto& shared_memory_entry = controller.shared_memory_entry; 882 auto& shared_memory_entry = controller.shared_memory_entry;
859 shared_memory_entry.style_set.raw = 0; // Zero out 883 shared_memory_entry.style_set.raw = 0; // Zero out
860 shared_memory_entry.device_type.raw = 0; 884 shared_memory_entry.device_type.raw = 0;
@@ -868,7 +892,10 @@ void Controller_NPad::DisconnectNpadAtIndex(std::size_t npad_index) {
868 shared_memory_entry.assignment_mode = NpadJoyAssignmentMode::Dual; 892 shared_memory_entry.assignment_mode = NpadJoyAssignmentMode::Dual;
869 shared_memory_entry.footer_type = AppletFooterUiType::None; 893 shared_memory_entry.footer_type = AppletFooterUiType::None;
870 894
895 controller.is_connected = false;
896 controller.device->Disconnect();
871 SignalStyleSetChangedEvent(IndexToNPad(npad_index)); 897 SignalStyleSetChangedEvent(IndexToNPad(npad_index));
898 WriteEmptyEntry(controller.shared_memory_entry);
872} 899}
873 900
874void Controller_NPad::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode) { 901void Controller_NPad::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode) {
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index b0e2f8430..d805ccb97 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -417,6 +417,8 @@ private:
417 417
418 std::array<VibrationData, 2> vibration{}; 418 std::array<VibrationData, 2> vibration{};
419 bool unintended_home_button_input_protection{}; 419 bool unintended_home_button_input_protection{};
420 bool is_connected{};
421 Core::HID::NpadType npad_type{Core::HID::NpadType::None};
420 422
421 // Current pad state 423 // Current pad state
422 NPadGenericState npad_pad_state{}; 424 NPadGenericState npad_pad_state{};
@@ -435,6 +437,7 @@ private:
435 void InitNewlyAddedController(std::size_t controller_idx); 437 void InitNewlyAddedController(std::size_t controller_idx);
436 bool IsControllerSupported(Core::HID::NpadType controller) const; 438 bool IsControllerSupported(Core::HID::NpadType controller) const;
437 void RequestPadStateUpdate(u32 npad_id); 439 void RequestPadStateUpdate(u32 npad_id);
440 void WriteEmptyEntry(NpadInternalState& npad);
438 441
439 std::atomic<u32> press_state{}; 442 std::atomic<u32> press_state{};
440 443
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index a8611f77f..67faa8be8 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -114,6 +114,7 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem, Co
114 player_tabs[i]->setLayout(new QHBoxLayout(player_tabs[i])); 114 player_tabs[i]->setLayout(new QHBoxLayout(player_tabs[i]));
115 player_tabs[i]->layout()->addWidget(player_controllers[i]); 115 player_tabs[i]->layout()->addWidget(player_controllers[i]);
116 connect(player_controllers[i], &ConfigureInputPlayer::Connected, [&, i](bool is_connected) { 116 connect(player_controllers[i], &ConfigureInputPlayer::Connected, [&, i](bool is_connected) {
117 // Ensures that the controllers are always connected in sequential order
117 if (is_connected) { 118 if (is_connected) {
118 for (std::size_t index = 0; index <= i; ++index) { 119 for (std::size_t index = 0; index <= i; ++index) {
119 player_connected[index]->setChecked(is_connected); 120 player_connected[index]->setChecked(is_connected);
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index ed9c3facf..81310a5b3 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -143,8 +143,26 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
143 timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()), 143 timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()),
144 bottom_row(bottom_row), system{system_} { 144 bottom_row(bottom_row), system{system_} {
145 145
146 emulated_controller = system_.HIDCore().GetEmulatedControllerByIndex(player_index); 146 if (player_index == 0) {
147 emulated_controller->EnableConfiguration(); 147 auto* emulated_controller_p1 =
148 system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
149 auto* emulated_controller_hanheld =
150 system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
151 emulated_controller_p1->SaveCurrentConfig();
152 emulated_controller_p1->EnableConfiguration();
153 emulated_controller_hanheld->SaveCurrentConfig();
154 emulated_controller_hanheld->EnableConfiguration();
155 if (emulated_controller_hanheld->IsConnected(true)) {
156 emulated_controller_p1->Disconnect();
157 emulated_controller = emulated_controller_hanheld;
158 } else {
159 emulated_controller = emulated_controller_p1;
160 }
161 } else {
162 emulated_controller = system_.HIDCore().GetEmulatedControllerByIndex(player_index);
163 emulated_controller->SaveCurrentConfig();
164 emulated_controller->EnableConfiguration();
165 }
148 ui->setupUi(this); 166 ui->setupUi(this);
149 167
150 setFocusPolicy(Qt::ClickFocus); 168 setFocusPolicy(Qt::ClickFocus);
@@ -460,13 +478,36 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
460 UpdateControllerEnabledButtons(); 478 UpdateControllerEnabledButtons();
461 UpdateControllerButtonNames(); 479 UpdateControllerButtonNames();
462 UpdateMotionButtons(); 480 UpdateMotionButtons();
463 connect(ui->comboControllerType, qOverload<int>(&QComboBox::currentIndexChanged), [this](int) { 481 connect(ui->comboControllerType, qOverload<int>(&QComboBox::currentIndexChanged), [this, player_index](int) {
464 UpdateControllerAvailableButtons(); 482 UpdateControllerAvailableButtons();
465 UpdateControllerEnabledButtons(); 483 UpdateControllerEnabledButtons();
466 UpdateControllerButtonNames(); 484 UpdateControllerButtonNames();
467 UpdateMotionButtons(); 485 UpdateMotionButtons();
468 emulated_controller->SetNpadType( 486 const Core::HID::NpadType type = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex());
469 GetControllerTypeFromIndex(ui->comboControllerType->currentIndex())); 487
488 if (player_index == 0) {
489 auto* emulated_controller_p1 =
490 system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
491 auto* emulated_controller_hanheld =
492 system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
493 bool is_connected = emulated_controller->IsConnected(true);
494
495 emulated_controller_p1->SetNpadType(type);
496 emulated_controller_hanheld->SetNpadType(type);
497 if (is_connected) {
498 if (type == Core::HID::NpadType::Handheld) {
499 emulated_controller_p1->Disconnect();
500 emulated_controller_hanheld->Connect();
501 emulated_controller = emulated_controller_hanheld;
502 } else {
503 emulated_controller_hanheld->Disconnect();
504 emulated_controller_p1->Connect();
505 emulated_controller = emulated_controller_p1;
506 }
507 }
508 ui->controllerFrame->SetController(emulated_controller);
509 }
510 emulated_controller->SetNpadType(type);
470 }); 511 });
471 512
472 connect(ui->comboDevices, qOverload<int>(&QComboBox::activated), this, 513 connect(ui->comboDevices, qOverload<int>(&QComboBox::activated), this,
@@ -504,11 +545,35 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
504} 545}
505 546
506ConfigureInputPlayer::~ConfigureInputPlayer() { 547ConfigureInputPlayer::~ConfigureInputPlayer() {
507 emulated_controller->DisableConfiguration(); 548 if (player_index == 0) {
549 auto* emulated_controller_p1 =
550 system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
551 auto* emulated_controller_hanheld =
552 system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
553 emulated_controller_p1->DisableConfiguration();
554 emulated_controller_hanheld->DisableConfiguration();
555 } else {
556 emulated_controller->DisableConfiguration();
557 }
508}; 558};
509 559
510void ConfigureInputPlayer::ApplyConfiguration() { 560void ConfigureInputPlayer::ApplyConfiguration() {
561 if (player_index == 0) {
562 auto* emulated_controller_p1 =
563 system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
564 auto* emulated_controller_hanheld =
565 system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
566 emulated_controller_p1->DisableConfiguration();
567 emulated_controller_p1->SaveCurrentConfig();
568 emulated_controller_p1->EnableConfiguration();
569 emulated_controller_hanheld->DisableConfiguration();
570 emulated_controller_hanheld->SaveCurrentConfig();
571 emulated_controller_hanheld->EnableConfiguration();
572 return;
573 }
574 emulated_controller->DisableConfiguration();
511 emulated_controller->SaveCurrentConfig(); 575 emulated_controller->SaveCurrentConfig();
576 emulated_controller->EnableConfiguration();
512} 577}
513 578
514void ConfigureInputPlayer::showEvent(QShowEvent* event) { 579void ConfigureInputPlayer::showEvent(QShowEvent* event) {
@@ -535,9 +600,9 @@ void ConfigureInputPlayer::RetranslateUI() {
535void ConfigureInputPlayer::LoadConfiguration() { 600void ConfigureInputPlayer::LoadConfiguration() {
536 UpdateUI(); 601 UpdateUI();
537 UpdateInputDeviceCombobox(); 602 UpdateInputDeviceCombobox();
538 const int comboBoxIndex = GetIndexFromControllerType(emulated_controller->GetNpadType()); 603 const int comboBoxIndex = GetIndexFromControllerType(emulated_controller->GetNpadType(true));
539 ui->comboControllerType->setCurrentIndex(comboBoxIndex); 604 ui->comboControllerType->setCurrentIndex(comboBoxIndex);
540 ui->groupConnectedController->setChecked(emulated_controller->IsConnected()); 605 ui->groupConnectedController->setChecked(emulated_controller->IsConnected(true));
541} 606}
542 607
543void ConfigureInputPlayer::ConnectPlayer(bool connected) { 608void ConfigureInputPlayer::ConnectPlayer(bool connected) {
diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp
index 446b72e55..3b79b6076 100644
--- a/src/yuzu/configuration/configure_input_player_widget.cpp
+++ b/src/yuzu/configuration/configure_input_player_widget.cpp
@@ -145,7 +145,7 @@ void PlayerControlPreview::ControllerUpdate(Core::HID::ControllerTriggerType typ
145 needs_redraw = true; 145 needs_redraw = true;
146 break; 146 break;
147 case Core::HID::ControllerTriggerType::Type: 147 case Core::HID::ControllerTriggerType::Type:
148 controller_type = controller->GetNpadType(); 148 controller_type = controller->GetNpadType(true);
149 needs_redraw = true; 149 needs_redraw = true;
150 break; 150 break;
151 case Core::HID::ControllerTriggerType::Color: 151 case Core::HID::ControllerTriggerType::Color: