summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/hid/emulated_controller.cpp1
-rw-r--r--src/core/hid/emulated_controller.h2
-rw-r--r--src/core/hid/hid_core.cpp21
-rw-r--r--src/core/hid/hid_core.h10
-rw-r--r--src/core/hle/service/am/applets/applet_controller.cpp14
-rw-r--r--src/input_common/main.cpp10
-rw-r--r--src/yuzu/applets/qt_controller.cpp143
-rw-r--r--src/yuzu/applets/qt_controller.h14
-rw-r--r--src/yuzu/applets/qt_software_keyboard.cpp21
-rw-r--r--src/yuzu/configuration/configure_input.cpp17
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.cpp4
-rw-r--r--src/yuzu/main.cpp11
12 files changed, 141 insertions, 127 deletions
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
index 7b0c4a49b..662260327 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -91,7 +91,6 @@ void EmulatedController::ReloadFromSettings() {
91} 91}
92 92
93void EmulatedController::ReloadInput() { 93void EmulatedController::ReloadInput() {
94 // LOG_ERROR(Service_HID, "reload config {}", NpadIdTypeToIndex(npad_id_type));
95 // If you load any device here add the equivalent to the UnloadInput() function 94 // If you load any device here add the equivalent to the UnloadInput() function
96 const auto left_side = button_params[Settings::NativeButton::ZL]; 95 const auto left_side = button_params[Settings::NativeButton::ZL];
97 const auto right_side = button_params[Settings::NativeButton::ZR]; 96 const auto right_side = button_params[Settings::NativeButton::ZR];
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h
index 3a0b20cf8..f3ee70726 100644
--- a/src/core/hid/emulated_controller.h
+++ b/src/core/hid/emulated_controller.h
@@ -329,7 +329,7 @@ private:
329 * @param type: Input type of the event to trigger 329 * @param type: Input type of the event to trigger
330 * @param is_service_update: indicates if this event should be sended to only services 330 * @param is_service_update: indicates if this event should be sended to only services
331 */ 331 */
332 void TriggerOnChange(ControllerTriggerType type, bool is_service_update); 332 void TriggerOnChange(ControllerTriggerType type, bool is_service_update);
333 333
334 NpadIdType npad_id_type; 334 NpadIdType npad_id_type;
335 NpadType npad_type{NpadType::None}; 335 NpadType npad_type{NpadType::None};
diff --git a/src/core/hid/hid_core.cpp b/src/core/hid/hid_core.cpp
index ee76db110..bd17081bd 100644
--- a/src/core/hid/hid_core.cpp
+++ b/src/core/hid/hid_core.cpp
@@ -111,6 +111,27 @@ NpadStyleTag HIDCore::GetSupportedStyleTag() const {
111 return supported_style_tag; 111 return supported_style_tag;
112} 112}
113 113
114s8 HIDCore::GetPlayerCount() const {
115 s8 active_players = 0;
116 for (std::size_t player_index = 0; player_index < 8; player_index++) {
117 const auto* controller = GetEmulatedControllerByIndex(player_index);
118 if (controller->IsConnected()) {
119 active_players++;
120 }
121 }
122 return active_players;
123}
124
125NpadIdType HIDCore::GetFirstNpadId() const {
126 for (std::size_t player_index = 0; player_index < 10; player_index++) {
127 const auto* controller = GetEmulatedControllerByIndex(player_index);
128 if (controller->IsConnected()) {
129 return controller->GetNpadIdType();
130 }
131 }
132 return NpadIdType::Player1;
133}
134
114void HIDCore::ReloadInputDevices() { 135void HIDCore::ReloadInputDevices() {
115 player_1->ReloadFromSettings(); 136 player_1->ReloadFromSettings();
116 player_2->ReloadFromSettings(); 137 player_2->ReloadFromSettings();
diff --git a/src/core/hid/hid_core.h b/src/core/hid/hid_core.h
index f11f48b61..196466a72 100644
--- a/src/core/hid/hid_core.h
+++ b/src/core/hid/hid_core.h
@@ -35,10 +35,16 @@ public:
35 void SetSupportedStyleTag(NpadStyleTag style_tag); 35 void SetSupportedStyleTag(NpadStyleTag style_tag);
36 NpadStyleTag GetSupportedStyleTag() const; 36 NpadStyleTag GetSupportedStyleTag() const;
37 37
38 // Reloads all input devices from settings 38 /// Counts the connected players from P1-P8
39 s8 GetPlayerCount() const;
40
41 /// Returns the first connected npad id
42 NpadIdType GetFirstNpadId() const;
43
44 /// Reloads all input devices from settings
39 void ReloadInputDevices(); 45 void ReloadInputDevices();
40 46
41 // Removes all callbacks from input common 47 /// Removes all callbacks from input common
42 void UnloadInputDevices(); 48 void UnloadInputDevices();
43 49
44private: 50private:
diff --git a/src/core/hle/service/am/applets/applet_controller.cpp b/src/core/hle/service/am/applets/applet_controller.cpp
index c1b6cd126..658265a00 100644
--- a/src/core/hle/service/am/applets/applet_controller.cpp
+++ b/src/core/hle/service/am/applets/applet_controller.cpp
@@ -243,19 +243,11 @@ void Controller::Execute() {
243void Controller::ConfigurationComplete() { 243void Controller::ConfigurationComplete() {
244 ControllerSupportResultInfo result_info{}; 244 ControllerSupportResultInfo result_info{};
245 245
246 const auto& players = Settings::values.players.GetValue();
247
248 // If enable_single_mode is enabled, player_count is 1 regardless of any other parameters. 246 // If enable_single_mode is enabled, player_count is 1 regardless of any other parameters.
249 // Otherwise, only count connected players from P1-P8. 247 // Otherwise, only count connected players from P1-P8.
250 result_info.player_count = 248 result_info.player_count = is_single_mode ? 1 : system.HIDCore().GetPlayerCount();
251 is_single_mode 249
252 ? 1 250 result_info.selected_id = static_cast<u32>(system.HIDCore().GetFirstNpadId());
253 : static_cast<s8>(std::count_if(players.begin(), players.end() - 2,
254 [](const auto& player) { return player.connected; }));
255
256 result_info.selected_id = HID::Controller_NPad::IndexToNPad(std::distance(
257 players.begin(), std::find_if(players.begin(), players.end(),
258 [](const auto& player) { return player.connected; })));
259 251
260 result_info.result = 0; 252 result_info.result = 0;
261 253
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index 7807dd38f..b048783c9 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -32,12 +32,17 @@ struct InputSubsystem::Impl {
32 keyboard = std::make_shared<Keyboard>("keyboard"); 32 keyboard = std::make_shared<Keyboard>("keyboard");
33 keyboard->SetMappingCallback(mapping_callback); 33 keyboard->SetMappingCallback(mapping_callback);
34 keyboard_factory = std::make_shared<InputFactory>(keyboard); 34 keyboard_factory = std::make_shared<InputFactory>(keyboard);
35 keyboard_output_factory = std::make_shared<OutputFactory>(keyboard);
35 Input::RegisterFactory<Input::InputDevice>(keyboard->GetEngineName(), keyboard_factory); 36 Input::RegisterFactory<Input::InputDevice>(keyboard->GetEngineName(), keyboard_factory);
37 Input::RegisterFactory<Input::OutputDevice>(keyboard->GetEngineName(),
38 keyboard_output_factory);
36 39
37 mouse = std::make_shared<Mouse>("mouse"); 40 mouse = std::make_shared<Mouse>("mouse");
38 mouse->SetMappingCallback(mapping_callback); 41 mouse->SetMappingCallback(mapping_callback);
39 mouse_factory = std::make_shared<InputFactory>(mouse); 42 mouse_factory = std::make_shared<InputFactory>(mouse);
43 mouse_output_factory = std::make_shared<OutputFactory>(mouse);
40 Input::RegisterFactory<Input::InputDevice>(mouse->GetEngineName(), mouse_factory); 44 Input::RegisterFactory<Input::InputDevice>(mouse->GetEngineName(), mouse_factory);
45 Input::RegisterFactory<Input::OutputDevice>(mouse->GetEngineName(), mouse_output_factory);
41 46
42 touch_screen = std::make_shared<TouchScreen>("touch"); 47 touch_screen = std::make_shared<TouchScreen>("touch");
43 touch_screen_factory = std::make_shared<InputFactory>(touch_screen); 48 touch_screen_factory = std::make_shared<InputFactory>(touch_screen);
@@ -61,7 +66,9 @@ struct InputSubsystem::Impl {
61 tas_input = std::make_shared<TasInput::Tas>("tas"); 66 tas_input = std::make_shared<TasInput::Tas>("tas");
62 tas_input->SetMappingCallback(mapping_callback); 67 tas_input->SetMappingCallback(mapping_callback);
63 tas_input_factory = std::make_shared<InputFactory>(tas_input); 68 tas_input_factory = std::make_shared<InputFactory>(tas_input);
69 tas_output_factory = std::make_shared<OutputFactory>(tas_input);
64 Input::RegisterFactory<Input::InputDevice>(tas_input->GetEngineName(), tas_input_factory); 70 Input::RegisterFactory<Input::InputDevice>(tas_input->GetEngineName(), tas_input_factory);
71 Input::RegisterFactory<Input::OutputDevice>(tas_input->GetEngineName(), tas_output_factory);
65 72
66#ifdef HAVE_SDL2 73#ifdef HAVE_SDL2
67 sdl = std::make_shared<SDLDriver>("sdl"); 74 sdl = std::make_shared<SDLDriver>("sdl");
@@ -268,7 +275,10 @@ struct InputSubsystem::Impl {
268 std::shared_ptr<InputFactory> udp_client_factory; 275 std::shared_ptr<InputFactory> udp_client_factory;
269 std::shared_ptr<InputFactory> tas_input_factory; 276 std::shared_ptr<InputFactory> tas_input_factory;
270 277
278 std::shared_ptr<OutputFactory> keyboard_output_factory;
279 std::shared_ptr<OutputFactory> mouse_output_factory;
271 std::shared_ptr<OutputFactory> gcadapter_output_factory; 280 std::shared_ptr<OutputFactory> gcadapter_output_factory;
281 std::shared_ptr<OutputFactory> tas_output_factory;
272 282
273#ifdef HAVE_SDL2 283#ifdef HAVE_SDL2
274 std::shared_ptr<SDLDriver> sdl; 284 std::shared_ptr<SDLDriver> sdl;
diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp
index 2cd5ed718..32cb5b5ff 100644
--- a/src/yuzu/applets/qt_controller.cpp
+++ b/src/yuzu/applets/qt_controller.cpp
@@ -9,6 +9,8 @@
9#include "common/param_package.h" 9#include "common/param_package.h"
10#include "common/string_util.h" 10#include "common/string_util.h"
11#include "core/core.h" 11#include "core/core.h"
12#include "core/hid/emulated_controller.h"
13#include "core/hid/hid_types.h"
12#include "core/hle/lock.h" 14#include "core/hle/lock.h"
13#include "core/hle/service/hid/controllers/npad.h" 15#include "core/hle/service/hid/controllers/npad.h"
14#include "core/hle/service/hid/hid.h" 16#include "core/hle/service/hid/hid.h"
@@ -26,48 +28,31 @@ namespace {
26 28
27constexpr std::size_t HANDHELD_INDEX = 8; 29constexpr std::size_t HANDHELD_INDEX = 8;
28 30
29constexpr std::array<std::array<bool, 4>, 8> led_patterns{{ 31void UpdateController(Core::HID::EmulatedController* controller, Core::HID::NpadType controller_type, bool connected) {
30 {true, false, false, false}, 32 if (controller->IsConnected()) {
31 {true, true, false, false}, 33 controller->Disconnect();
32 {true, true, true, false}, 34 }
33 {true, true, true, true}, 35 controller->SetNpadType(controller_type);
34 {true, false, false, true}, 36 if (connected) {
35 {true, false, true, false}, 37 controller->Connect();
36 {true, false, true, true},
37 {false, true, true, false},
38}};
39
40void UpdateController(Settings::ControllerType controller_type, std::size_t npad_index,
41 bool connected, Core::System& system) {
42 if (!system.IsPoweredOn()) {
43 return;
44 } 38 }
45
46 auto& npad =
47 system.ServiceManager()
48 .GetService<Service::HID::Hid>("hid")
49 ->GetAppletResource()
50 ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
51
52 npad.UpdateControllerAt(Core::HID::EmulatedController::MapSettingsTypeToNPad(controller_type),
53 npad_index, connected);
54} 39}
55 40
56// Returns true if the given controller type is compatible with the given parameters. 41// Returns true if the given controller type is compatible with the given parameters.
57bool IsControllerCompatible(Settings::ControllerType controller_type, 42bool IsControllerCompatible(Core::HID::NpadType controller_type,
58 Core::Frontend::ControllerParameters parameters) { 43 Core::Frontend::ControllerParameters parameters) {
59 switch (controller_type) { 44 switch (controller_type) {
60 case Settings::ControllerType::ProController: 45 case Core::HID::NpadType::ProController:
61 return parameters.allow_pro_controller; 46 return parameters.allow_pro_controller;
62 case Settings::ControllerType::DualJoyconDetached: 47 case Core::HID::NpadType::JoyconDual:
63 return parameters.allow_dual_joycons; 48 return parameters.allow_dual_joycons;
64 case Settings::ControllerType::LeftJoycon: 49 case Core::HID::NpadType::JoyconLeft:
65 return parameters.allow_left_joycon; 50 return parameters.allow_left_joycon;
66 case Settings::ControllerType::RightJoycon: 51 case Core::HID::NpadType::JoyconRight:
67 return parameters.allow_right_joycon; 52 return parameters.allow_right_joycon;
68 case Settings::ControllerType::Handheld: 53 case Core::HID::NpadType::Handheld:
69 return parameters.enable_single_mode && parameters.allow_handheld; 54 return parameters.enable_single_mode && parameters.allow_handheld;
70 case Settings::ControllerType::GameCube: 55 case Core::HID::NpadType::GameCube:
71 return parameters.allow_gamecube_controller; 56 return parameters.allow_gamecube_controller;
72 default: 57 default:
73 return false; 58 return false;
@@ -198,7 +183,7 @@ QtControllerSelectorDialog::QtControllerSelectorDialog(
198 connect(emulated_controllers[i], qOverload<int>(&QComboBox::currentIndexChanged), 183 connect(emulated_controllers[i], qOverload<int>(&QComboBox::currentIndexChanged),
199 [this, i](int index) { 184 [this, i](int index) {
200 UpdateDockedState(GetControllerTypeFromIndex(index, i) == 185 UpdateDockedState(GetControllerTypeFromIndex(index, i) ==
201 Settings::ControllerType::Handheld); 186 Core::HID::NpadType::Handheld);
202 }); 187 });
203 } 188 }
204 } 189 }
@@ -251,17 +236,17 @@ void QtControllerSelectorDialog::ApplyConfiguration() {
251} 236}
252 237
253void QtControllerSelectorDialog::LoadConfiguration() { 238void QtControllerSelectorDialog::LoadConfiguration() {
239 const auto* handheld = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
254 for (std::size_t index = 0; index < NUM_PLAYERS; ++index) { 240 for (std::size_t index = 0; index < NUM_PLAYERS; ++index) {
255 const auto connected = 241 const auto* controller = system.HIDCore().GetEmulatedControllerByIndex(index);
256 Settings::values.players.GetValue()[index].connected || 242 const auto connected = controller->IsConnected() || (index == 0 && handheld->IsConnected());
257 (index == 0 && Settings::values.players.GetValue()[HANDHELD_INDEX].connected);
258 player_groupboxes[index]->setChecked(connected); 243 player_groupboxes[index]->setChecked(connected);
259 connected_controller_checkboxes[index]->setChecked(connected); 244 connected_controller_checkboxes[index]->setChecked(connected);
260 emulated_controllers[index]->setCurrentIndex(GetIndexFromControllerType( 245 emulated_controllers[index]->setCurrentIndex(
261 Settings::values.players.GetValue()[index].controller_type, index)); 246 GetIndexFromControllerType(controller->GetNpadType(), index));
262 } 247 }
263 248
264 UpdateDockedState(Settings::values.players.GetValue()[HANDHELD_INDEX].connected); 249 UpdateDockedState(handheld->IsConnected());
265 250
266 ui->vibrationGroup->setChecked(Settings::values.vibration_enabled.GetValue()); 251 ui->vibrationGroup->setChecked(Settings::values.vibration_enabled.GetValue());
267 ui->motionGroup->setChecked(Settings::values.motion_enabled.GetValue()); 252 ui->motionGroup->setChecked(Settings::values.motion_enabled.GetValue());
@@ -417,33 +402,32 @@ void QtControllerSelectorDialog::SetEmulatedControllers(std::size_t player_index
417 emulated_controllers[player_index]->clear(); 402 emulated_controllers[player_index]->clear();
418 403
419 pairs.emplace_back(emulated_controllers[player_index]->count(), 404 pairs.emplace_back(emulated_controllers[player_index]->count(),
420 Settings::ControllerType::ProController); 405 Core::HID::NpadType::ProController);
421 emulated_controllers[player_index]->addItem(tr("Pro Controller")); 406 emulated_controllers[player_index]->addItem(tr("Pro Controller"));
422 407
423 pairs.emplace_back(emulated_controllers[player_index]->count(), 408 pairs.emplace_back(emulated_controllers[player_index]->count(),
424 Settings::ControllerType::DualJoyconDetached); 409 Core::HID::NpadType::JoyconDual);
425 emulated_controllers[player_index]->addItem(tr("Dual Joycons")); 410 emulated_controllers[player_index]->addItem(tr("Dual Joycons"));
426 411
427 pairs.emplace_back(emulated_controllers[player_index]->count(), 412 pairs.emplace_back(emulated_controllers[player_index]->count(),
428 Settings::ControllerType::LeftJoycon); 413 Core::HID::NpadType::JoyconLeft);
429 emulated_controllers[player_index]->addItem(tr("Left Joycon")); 414 emulated_controllers[player_index]->addItem(tr("Left Joycon"));
430 415
431 pairs.emplace_back(emulated_controllers[player_index]->count(), 416 pairs.emplace_back(emulated_controllers[player_index]->count(),
432 Settings::ControllerType::RightJoycon); 417 Core::HID::NpadType::JoyconRight);
433 emulated_controllers[player_index]->addItem(tr("Right Joycon")); 418 emulated_controllers[player_index]->addItem(tr("Right Joycon"));
434 419
435 if (player_index == 0) { 420 if (player_index == 0) {
436 pairs.emplace_back(emulated_controllers[player_index]->count(), 421 pairs.emplace_back(emulated_controllers[player_index]->count(),
437 Settings::ControllerType::Handheld); 422 Core::HID::NpadType::Handheld);
438 emulated_controllers[player_index]->addItem(tr("Handheld")); 423 emulated_controllers[player_index]->addItem(tr("Handheld"));
439 } 424 }
440 425
441 pairs.emplace_back(emulated_controllers[player_index]->count(), 426 pairs.emplace_back(emulated_controllers[player_index]->count(), Core::HID::NpadType::GameCube);
442 Settings::ControllerType::GameCube);
443 emulated_controllers[player_index]->addItem(tr("GameCube Controller")); 427 emulated_controllers[player_index]->addItem(tr("GameCube Controller"));
444} 428}
445 429
446Settings::ControllerType QtControllerSelectorDialog::GetControllerTypeFromIndex( 430Core::HID::NpadType QtControllerSelectorDialog::GetControllerTypeFromIndex(
447 int index, std::size_t player_index) const { 431 int index, std::size_t player_index) const {
448 const auto& pairs = index_controller_type_pairs[player_index]; 432 const auto& pairs = index_controller_type_pairs[player_index];
449 433
@@ -451,13 +435,13 @@ Settings::ControllerType QtControllerSelectorDialog::GetControllerTypeFromIndex(
451 [index](const auto& pair) { return pair.first == index; }); 435 [index](const auto& pair) { return pair.first == index; });
452 436
453 if (it == pairs.end()) { 437 if (it == pairs.end()) {
454 return Settings::ControllerType::ProController; 438 return Core::HID::NpadType::ProController;
455 } 439 }
456 440
457 return it->second; 441 return it->second;
458} 442}
459 443
460int QtControllerSelectorDialog::GetIndexFromControllerType(Settings::ControllerType type, 444int QtControllerSelectorDialog::GetIndexFromControllerType(Core::HID::NpadType type,
461 std::size_t player_index) const { 445 std::size_t player_index) const {
462 const auto& pairs = index_controller_type_pairs[player_index]; 446 const auto& pairs = index_controller_type_pairs[player_index];
463 447
@@ -481,16 +465,16 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index)
481 const QString stylesheet = [this, player_index] { 465 const QString stylesheet = [this, player_index] {
482 switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(), 466 switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(),
483 player_index)) { 467 player_index)) {
484 case Settings::ControllerType::ProController: 468 case Core::HID::NpadType::ProController:
485 case Settings::ControllerType::GameCube: 469 case Core::HID::NpadType::GameCube:
486 return QStringLiteral("image: url(:/controller/applet_pro_controller%0); "); 470 return QStringLiteral("image: url(:/controller/applet_pro_controller%0); ");
487 case Settings::ControllerType::DualJoyconDetached: 471 case Core::HID::NpadType::JoyconDual:
488 return QStringLiteral("image: url(:/controller/applet_dual_joycon%0); "); 472 return QStringLiteral("image: url(:/controller/applet_dual_joycon%0); ");
489 case Settings::ControllerType::LeftJoycon: 473 case Core::HID::NpadType::JoyconLeft:
490 return QStringLiteral("image: url(:/controller/applet_joycon_left%0); "); 474 return QStringLiteral("image: url(:/controller/applet_joycon_left%0); ");
491 case Settings::ControllerType::RightJoycon: 475 case Core::HID::NpadType::JoyconRight:
492 return QStringLiteral("image: url(:/controller/applet_joycon_right%0); "); 476 return QStringLiteral("image: url(:/controller/applet_joycon_right%0); ");
493 case Settings::ControllerType::Handheld: 477 case Core::HID::NpadType::Handheld:
494 return QStringLiteral("image: url(:/controller/applet_handheld%0); "); 478 return QStringLiteral("image: url(:/controller/applet_handheld%0); ");
495 default: 479 default:
496 return QString{}; 480 return QString{};
@@ -518,54 +502,42 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index)
518} 502}
519 503
520void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) { 504void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) {
521 auto& player = Settings::values.players.GetValue()[player_index]; 505 auto* controller = system.HIDCore().GetEmulatedControllerByIndex(player_index);
522 506
523 const auto controller_type = GetControllerTypeFromIndex( 507 const auto controller_type = GetControllerTypeFromIndex(
524 emulated_controllers[player_index]->currentIndex(), player_index); 508 emulated_controllers[player_index]->currentIndex(), player_index);
525 const auto player_connected = player_groupboxes[player_index]->isChecked() && 509 const auto player_connected = player_groupboxes[player_index]->isChecked() &&
526 controller_type != Settings::ControllerType::Handheld; 510 controller_type != Core::HID::NpadType::Handheld;
527 511
528 if (player.controller_type == controller_type && player.connected == player_connected) { 512 if (controller->GetNpadType() == controller_type &&
513 controller->IsConnected() == player_connected) {
529 // Set vibration devices in the event that the input device has changed. 514 // Set vibration devices in the event that the input device has changed.
530 ConfigureVibration::SetVibrationDevices(player_index); 515 ConfigureVibration::SetVibrationDevices(player_index);
531 return; 516 return;
532 } 517 }
533 518
534 // Disconnect the controller first. 519 // Disconnect the controller first.
535 UpdateController(controller_type, player_index, false, system); 520 UpdateController(controller, controller_type, false);
536
537 player.controller_type = controller_type;
538 player.connected = player_connected;
539 521
540 ConfigureVibration::SetVibrationDevices(player_index); 522 ConfigureVibration::SetVibrationDevices(player_index);
541 523
542 // Handheld 524 // Handheld
543 if (player_index == 0) { 525 if (player_index == 0) {
544 auto& handheld = Settings::values.players.GetValue()[HANDHELD_INDEX]; 526 if (controller_type == Core::HID::NpadType::Handheld) {
545 if (controller_type == Settings::ControllerType::Handheld) { 527 auto* handheld =
546 handheld = player; 528 system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
529 UpdateController(handheld, Core::HID::NpadType::Handheld,
530 player_groupboxes[player_index]->isChecked());
547 } 531 }
548 handheld.connected = player_groupboxes[player_index]->isChecked() &&
549 controller_type == Settings::ControllerType::Handheld;
550 UpdateController(Settings::ControllerType::Handheld, 8, handheld.connected, system);
551 } 532 }
552 533
553 if (!player.connected) { 534 UpdateController(controller, controller_type, player_connected);
554 return;
555 }
556
557 // This emulates a delay between disconnecting and reconnecting controllers as some games
558 // do not respond to a change in controller type if it was instantaneous.
559 using namespace std::chrono_literals;
560 std::this_thread::sleep_for(60ms);
561
562 UpdateController(controller_type, player_index, player_connected, system);
563} 535}
564 536
565void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) { 537void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) {
566 if (!player_groupboxes[player_index]->isChecked() || 538 if (!player_groupboxes[player_index]->isChecked() ||
567 GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(), 539 GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(),
568 player_index) == Settings::ControllerType::Handheld) { 540 player_index) == Core::HID::NpadType::Handheld) {
569 led_patterns_boxes[player_index][0]->setChecked(false); 541 led_patterns_boxes[player_index][0]->setChecked(false);
570 led_patterns_boxes[player_index][1]->setChecked(false); 542 led_patterns_boxes[player_index][1]->setChecked(false);
571 led_patterns_boxes[player_index][2]->setChecked(false); 543 led_patterns_boxes[player_index][2]->setChecked(false);
@@ -573,10 +545,12 @@ void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) {
573 return; 545 return;
574 } 546 }
575 547
576 led_patterns_boxes[player_index][0]->setChecked(led_patterns[player_index][0]); 548 const auto* controller = system.HIDCore().GetEmulatedControllerByIndex(player_index);
577 led_patterns_boxes[player_index][1]->setChecked(led_patterns[player_index][1]); 549 const auto led_pattern = controller->GetLedPattern();
578 led_patterns_boxes[player_index][2]->setChecked(led_patterns[player_index][2]); 550 led_patterns_boxes[player_index][0]->setChecked(led_pattern.position1);
579 led_patterns_boxes[player_index][3]->setChecked(led_patterns[player_index][3]); 551 led_patterns_boxes[player_index][1]->setChecked(led_pattern.position2);
552 led_patterns_boxes[player_index][2]->setChecked(led_pattern.position3);
553 led_patterns_boxes[player_index][3]->setChecked(led_pattern.position4);
580} 554}
581 555
582void QtControllerSelectorDialog::UpdateBorderColor(std::size_t player_index) { 556void QtControllerSelectorDialog::UpdateBorderColor(std::size_t player_index) {
@@ -656,10 +630,9 @@ void QtControllerSelectorDialog::DisableUnsupportedPlayers() {
656 } 630 }
657 631
658 for (std::size_t index = max_supported_players; index < NUM_PLAYERS; ++index) { 632 for (std::size_t index = max_supported_players; index < NUM_PLAYERS; ++index) {
633 auto* controller = system.HIDCore().GetEmulatedControllerByIndex(index);
659 // Disconnect any unsupported players here and disable or hide them if applicable. 634 // Disconnect any unsupported players here and disable or hide them if applicable.
660 Settings::values.players.GetValue()[index].connected = false; 635 UpdateController(controller, controller->GetNpadType(), false);
661 UpdateController(Settings::values.players.GetValue()[index].controller_type, index, false,
662 system);
663 // Hide the player widgets when max_supported_controllers is less than or equal to 4. 636 // Hide the player widgets when max_supported_controllers is less than or equal to 4.
664 if (max_supported_players <= 4) { 637 if (max_supported_players <= 4) {
665 player_widgets[index]->hide(); 638 player_widgets[index]->hide();
diff --git a/src/yuzu/applets/qt_controller.h b/src/yuzu/applets/qt_controller.h
index ca09fde04..dd981f479 100644
--- a/src/yuzu/applets/qt_controller.h
+++ b/src/yuzu/applets/qt_controller.h
@@ -23,10 +23,6 @@ namespace InputCommon {
23class InputSubsystem; 23class InputSubsystem;
24} 24}
25 25
26namespace Settings {
27enum class ControllerType;
28}
29
30namespace Ui { 26namespace Ui {
31class QtControllerSelectorDialog; 27class QtControllerSelectorDialog;
32} 28}
@@ -35,6 +31,10 @@ namespace Core {
35class System; 31class System;
36} 32}
37 33
34namespace Core::HID {
35enum class NpadType : u8;
36}
37
38class QtControllerSelectorDialog final : public QDialog { 38class QtControllerSelectorDialog final : public QDialog {
39 Q_OBJECT 39 Q_OBJECT
40 40
@@ -74,10 +74,10 @@ private:
74 void SetEmulatedControllers(std::size_t player_index); 74 void SetEmulatedControllers(std::size_t player_index);
75 75
76 // Gets the Controller Type for a given controller combobox index per player. 76 // Gets the Controller Type for a given controller combobox index per player.
77 Settings::ControllerType GetControllerTypeFromIndex(int index, std::size_t player_index) const; 77 Core::HID::NpadType GetControllerTypeFromIndex(int index, std::size_t player_index) const;
78 78
79 // Gets the controller combobox index for a given Controller Type per player. 79 // Gets the controller combobox index for a given Controller Type per player.
80 int GetIndexFromControllerType(Settings::ControllerType type, std::size_t player_index) const; 80 int GetIndexFromControllerType(Core::HID::NpadType type, std::size_t player_index) const;
81 81
82 // Updates the controller icons per player. 82 // Updates the controller icons per player.
83 void UpdateControllerIcon(std::size_t player_index); 83 void UpdateControllerIcon(std::size_t player_index);
@@ -139,7 +139,7 @@ private:
139 std::array<QComboBox*, NUM_PLAYERS> emulated_controllers; 139 std::array<QComboBox*, NUM_PLAYERS> emulated_controllers;
140 140
141 /// Pairs of emulated controller index and Controller Type enum per player. 141 /// Pairs of emulated controller index and Controller Type enum per player.
142 std::array<std::vector<std::pair<int, Settings::ControllerType>>, NUM_PLAYERS> 142 std::array<std::vector<std::pair<int, Core::HID::NpadType>>, NUM_PLAYERS>
143 index_controller_type_pairs; 143 index_controller_type_pairs;
144 144
145 // Labels representing the number of connected controllers 145 // Labels representing the number of connected controllers
diff --git a/src/yuzu/applets/qt_software_keyboard.cpp b/src/yuzu/applets/qt_software_keyboard.cpp
index 7e8731232..3d91f8034 100644
--- a/src/yuzu/applets/qt_software_keyboard.cpp
+++ b/src/yuzu/applets/qt_software_keyboard.cpp
@@ -10,6 +10,8 @@
10#include "common/settings.h" 10#include "common/settings.h"
11#include "common/string_util.h" 11#include "common/string_util.h"
12#include "core/core.h" 12#include "core/core.h"
13#include "core/hid/emulated_controller.h"
14#include "core/hid/hid_core.h"
13#include "core/hid/hid_types.h" 15#include "core/hid/hid_types.h"
14#include "core/hid/input_interpreter.h" 16#include "core/hid/input_interpreter.h"
15#include "ui_qt_software_keyboard.h" 17#include "ui_qt_software_keyboard.h"
@@ -796,9 +798,10 @@ void QtSoftwareKeyboardDialog::SetTextDrawType() {
796} 798}
797 799
798void QtSoftwareKeyboardDialog::SetControllerImage() { 800void QtSoftwareKeyboardDialog::SetControllerImage() {
799 const auto controller_type = Settings::values.players.GetValue()[8].connected 801 const auto* handheld = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
800 ? Settings::values.players.GetValue()[8].controller_type 802 const auto* player_1 = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
801 : Settings::values.players.GetValue()[0].controller_type; 803 const auto controller_type =
804 handheld->IsConnected() ? handheld->GetNpadType() : player_1->GetNpadType();
802 805
803 const QString theme = [] { 806 const QString theme = [] {
804 if (QIcon::themeName().contains(QStringLiteral("dark")) || 807 if (QIcon::themeName().contains(QStringLiteral("dark")) ||
@@ -810,8 +813,8 @@ void QtSoftwareKeyboardDialog::SetControllerImage() {
810 }(); 813 }();
811 814
812 switch (controller_type) { 815 switch (controller_type) {
813 case Settings::ControllerType::ProController: 816 case Core::HID::NpadType::ProController:
814 case Settings::ControllerType::GameCube: 817 case Core::HID::NpadType::GameCube:
815 ui->icon_controller->setStyleSheet( 818 ui->icon_controller->setStyleSheet(
816 QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme)); 819 QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme));
817 ui->icon_controller_shift->setStyleSheet( 820 ui->icon_controller_shift->setStyleSheet(
@@ -819,7 +822,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() {
819 ui->icon_controller_num->setStyleSheet( 822 ui->icon_controller_num->setStyleSheet(
820 QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme)); 823 QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme));
821 break; 824 break;
822 case Settings::ControllerType::DualJoyconDetached: 825 case Core::HID::NpadType::JoyconDual:
823 ui->icon_controller->setStyleSheet( 826 ui->icon_controller->setStyleSheet(
824 QStringLiteral("image: url(:/overlay/controller_dual_joycon%1.png);").arg(theme)); 827 QStringLiteral("image: url(:/overlay/controller_dual_joycon%1.png);").arg(theme));
825 ui->icon_controller_shift->setStyleSheet( 828 ui->icon_controller_shift->setStyleSheet(
@@ -827,7 +830,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() {
827 ui->icon_controller_num->setStyleSheet( 830 ui->icon_controller_num->setStyleSheet(
828 QStringLiteral("image: url(:/overlay/controller_dual_joycon%1.png);").arg(theme)); 831 QStringLiteral("image: url(:/overlay/controller_dual_joycon%1.png);").arg(theme));
829 break; 832 break;
830 case Settings::ControllerType::LeftJoycon: 833 case Core::HID::NpadType::JoyconLeft:
831 ui->icon_controller->setStyleSheet( 834 ui->icon_controller->setStyleSheet(
832 QStringLiteral("image: url(:/overlay/controller_single_joycon_left%1.png);") 835 QStringLiteral("image: url(:/overlay/controller_single_joycon_left%1.png);")
833 .arg(theme)); 836 .arg(theme));
@@ -838,7 +841,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() {
838 QStringLiteral("image: url(:/overlay/controller_single_joycon_left%1.png);") 841 QStringLiteral("image: url(:/overlay/controller_single_joycon_left%1.png);")
839 .arg(theme)); 842 .arg(theme));
840 break; 843 break;
841 case Settings::ControllerType::RightJoycon: 844 case Core::HID::NpadType::JoyconRight:
842 ui->icon_controller->setStyleSheet( 845 ui->icon_controller->setStyleSheet(
843 QStringLiteral("image: url(:/overlay/controller_single_joycon_right%1.png);") 846 QStringLiteral("image: url(:/overlay/controller_single_joycon_right%1.png);")
844 .arg(theme)); 847 .arg(theme));
@@ -849,7 +852,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() {
849 QStringLiteral("image: url(:/overlay/controller_single_joycon_right%1.png);") 852 QStringLiteral("image: url(:/overlay/controller_single_joycon_right%1.png);")
850 .arg(theme)); 853 .arg(theme));
851 break; 854 break;
852 case Settings::ControllerType::Handheld: 855 case Core::HID::NpadType::Handheld:
853 ui->icon_controller->setStyleSheet( 856 ui->icon_controller->setStyleSheet(
854 QStringLiteral("image: url(:/overlay/controller_handheld%1.png);").arg(theme)); 857 QStringLiteral("image: url(:/overlay/controller_handheld%1.png);").arg(theme));
855 ui->icon_controller_shift->setStyleSheet( 858 ui->icon_controller_shift->setStyleSheet(
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index 67faa8be8..dece27fde 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -211,8 +211,10 @@ void ConfigureInput::RetranslateUI() {
211} 211}
212 212
213void ConfigureInput::LoadConfiguration() { 213void ConfigureInput::LoadConfiguration() {
214 const auto* handheld = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
215
214 LoadPlayerControllerIndices(); 216 LoadPlayerControllerIndices();
215 UpdateDockedState(Settings::values.players.GetValue()[8].connected); 217 UpdateDockedState(handheld->IsConnected());
216 218
217 ui->vibrationGroup->setChecked(Settings::values.vibration_enabled.GetValue()); 219 ui->vibrationGroup->setChecked(Settings::values.vibration_enabled.GetValue());
218 ui->motionGroup->setChecked(Settings::values.motion_enabled.GetValue()); 220 ui->motionGroup->setChecked(Settings::values.motion_enabled.GetValue());
@@ -220,9 +222,16 @@ void ConfigureInput::LoadConfiguration() {
220 222
221void ConfigureInput::LoadPlayerControllerIndices() { 223void ConfigureInput::LoadPlayerControllerIndices() {
222 for (std::size_t i = 0; i < player_connected.size(); ++i) { 224 for (std::size_t i = 0; i < player_connected.size(); ++i) {
223 const auto connected = Settings::values.players.GetValue()[i].connected || 225 if (i == 0) {
224 (i == 0 && Settings::values.players.GetValue()[8].connected); 226 auto* handheld =
225 player_connected[i]->setChecked(connected); 227 system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
228 if (handheld->IsConnected()) {
229 player_connected[i]->setChecked(true);
230 continue;
231 }
232 }
233 const auto* controller = system.HIDCore().GetEmulatedControllerByIndex(i);
234 player_connected[i]->setChecked(controller->IsConnected());
226 } 235 }
227} 236}
228 237
diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp
index 93f7eddc9..be87204fc 100644
--- a/src/yuzu/configuration/configure_input_player_widget.cpp
+++ b/src/yuzu/configuration/configure_input_player_widget.cpp
@@ -104,8 +104,8 @@ void PlayerControlPreview::UpdateColors() {
104 colors.left = colors.primary; 104 colors.left = colors.primary;
105 colors.right = colors.primary; 105 colors.right = colors.primary;
106 // Possible alternative to set colors from settings 106 // Possible alternative to set colors from settings
107 // colors.left = QColor(Settings::values.players.GetValue()[player_index].body_color_left); 107 // colors.left = QColor(controller->GetColors().left.body);
108 // colors.right = QColor(Settings::values.players.GetValue()[player_index].body_color_right); 108 // colors.right = QColor(controller->GetColors().right.body);
109} 109}
110 110
111void PlayerControlPreview::ResetInputs() { 111void PlayerControlPreview::ResetInputs() {
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index ae997ccfa..46a5f62ad 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -832,15 +832,16 @@ void GMainWindow::InitializeWidgets() {
832 dock_status_button->setFocusPolicy(Qt::NoFocus); 832 dock_status_button->setFocusPolicy(Qt::NoFocus);
833 connect(dock_status_button, &QPushButton::clicked, [&] { 833 connect(dock_status_button, &QPushButton::clicked, [&] {
834 const bool is_docked = Settings::values.use_docked_mode.GetValue(); 834 const bool is_docked = Settings::values.use_docked_mode.GetValue();
835 auto& controller_type = Settings::values.players.GetValue()[0].controller_type; 835 auto* player_1 = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
836 auto* handheld = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
836 837
837 if (!is_docked && controller_type == Settings::ControllerType::Handheld) { 838 if (!is_docked && handheld->IsConnected()) {
838 QMessageBox::warning(this, tr("Invalid config detected"), 839 QMessageBox::warning(this, tr("Invalid config detected"),
839 tr("Handheld controller can't be used on docked mode. Pro " 840 tr("Handheld controller can't be used on docked mode. Pro "
840 "controller will be selected.")); 841 "controller will be selected."));
841 controller_type = Settings::ControllerType::ProController; 842 handheld->Disconnect();
842 ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get(), *system); 843 player_1->SetNpadType(Core::HID::NpadType::ProController);
843 configure_dialog.ApplyConfiguration(); 844 player_1->Connect();
844 } 845 }
845 846
846 Settings::values.use_docked_mode.SetValue(!is_docked); 847 Settings::values.use_docked_mode.SetValue(!is_docked);