summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/frontend/applets/controller.h1
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp63
-rw-r--r--src/core/hle/service/hid/controllers/npad.h26
-rw-r--r--src/input_common/settings.h1
-rw-r--r--src/yuzu/applets/controller.cpp9
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp106
-rw-r--r--src/yuzu/configuration/configure_input_player.h6
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.cpp3
8 files changed, 209 insertions, 6 deletions
diff --git a/src/core/frontend/applets/controller.h b/src/core/frontend/applets/controller.h
index dff71d8d9..b0626a0f9 100644
--- a/src/core/frontend/applets/controller.h
+++ b/src/core/frontend/applets/controller.h
@@ -31,6 +31,7 @@ struct ControllerParameters {
31 bool allow_dual_joycons{}; 31 bool allow_dual_joycons{};
32 bool allow_left_joycon{}; 32 bool allow_left_joycon{};
33 bool allow_right_joycon{}; 33 bool allow_right_joycon{};
34 bool allow_gamecube_controller{};
34}; 35};
35 36
36class ControllerApplet { 37class ControllerApplet {
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index dbf198345..70b9f3824 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -21,6 +21,7 @@
21 21
22namespace Service::HID { 22namespace Service::HID {
23constexpr s32 HID_JOYSTICK_MAX = 0x7fff; 23constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
24constexpr s32 HID_TRIGGER_MAX = 0x7fff;
24[[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff; 25[[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff;
25constexpr std::size_t NPAD_OFFSET = 0x9A00; 26constexpr std::size_t NPAD_OFFSET = 0x9A00;
26constexpr u32 BATTERY_FULL = 2; 27constexpr u32 BATTERY_FULL = 2;
@@ -48,6 +49,8 @@ Controller_NPad::NPadControllerType Controller_NPad::MapSettingsTypeToNPad(
48 return NPadControllerType::JoyRight; 49 return NPadControllerType::JoyRight;
49 case Settings::ControllerType::Handheld: 50 case Settings::ControllerType::Handheld:
50 return NPadControllerType::Handheld; 51 return NPadControllerType::Handheld;
52 case Settings::ControllerType::GameCube:
53 return NPadControllerType::GameCube;
51 default: 54 default:
52 UNREACHABLE(); 55 UNREACHABLE();
53 return NPadControllerType::ProController; 56 return NPadControllerType::ProController;
@@ -67,6 +70,8 @@ Settings::ControllerType Controller_NPad::MapNPadToSettingsType(
67 return Settings::ControllerType::RightJoycon; 70 return Settings::ControllerType::RightJoycon;
68 case NPadControllerType::Handheld: 71 case NPadControllerType::Handheld:
69 return Settings::ControllerType::Handheld; 72 return Settings::ControllerType::Handheld;
73 case NPadControllerType::GameCube:
74 return Settings::ControllerType::GameCube;
70 default: 75 default:
71 UNREACHABLE(); 76 UNREACHABLE();
72 return Settings::ControllerType::ProController; 77 return Settings::ControllerType::ProController;
@@ -209,6 +214,13 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
209 controller.assignment_mode = NpadAssignments::Single; 214 controller.assignment_mode = NpadAssignments::Single;
210 controller.footer_type = AppletFooterUiType::JoyRightHorizontal; 215 controller.footer_type = AppletFooterUiType::JoyRightHorizontal;
211 break; 216 break;
217 case NPadControllerType::GameCube:
218 controller.style_set.gamecube.Assign(1);
219 // The GC Controller behaves like a wired Pro Controller
220 controller.device_type.fullkey.Assign(1);
221 controller.system_properties.is_vertical.Assign(1);
222 controller.system_properties.use_plus.Assign(1);
223 break;
212 case NPadControllerType::Pokeball: 224 case NPadControllerType::Pokeball:
213 controller.style_set.palma.Assign(1); 225 controller.style_set.palma.Assign(1);
214 controller.device_type.palma.Assign(1); 226 controller.device_type.palma.Assign(1);
@@ -259,6 +271,7 @@ void Controller_NPad::OnInit() {
259 style.joycon_right.Assign(1); 271 style.joycon_right.Assign(1);
260 style.joycon_dual.Assign(1); 272 style.joycon_dual.Assign(1);
261 style.fullkey.Assign(1); 273 style.fullkey.Assign(1);
274 style.gamecube.Assign(1);
262 style.palma.Assign(1); 275 style.palma.Assign(1);
263 } 276 }
264 277
@@ -339,6 +352,7 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
339 auto& pad_state = npad_pad_states[controller_idx].pad_states; 352 auto& pad_state = npad_pad_states[controller_idx].pad_states;
340 auto& lstick_entry = npad_pad_states[controller_idx].l_stick; 353 auto& lstick_entry = npad_pad_states[controller_idx].l_stick;
341 auto& rstick_entry = npad_pad_states[controller_idx].r_stick; 354 auto& rstick_entry = npad_pad_states[controller_idx].r_stick;
355 auto& trigger_entry = npad_trigger_states[controller_idx];
342 const auto& button_state = buttons[controller_idx]; 356 const auto& button_state = buttons[controller_idx];
343 const auto& analog_state = sticks[controller_idx]; 357 const auto& analog_state = sticks[controller_idx];
344 const auto [stick_l_x_f, stick_l_y_f] = 358 const auto [stick_l_x_f, stick_l_y_f] =
@@ -404,6 +418,17 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
404 pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus()); 418 pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus());
405 pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus()); 419 pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus());
406 } 420 }
421
422 if (controller_type == NPadControllerType::GameCube) {
423 trigger_entry.l_analog = static_cast<s32>(
424 button_state[ZL - BUTTON_HID_BEGIN]->GetStatus() ? HID_TRIGGER_MAX : 0);
425 trigger_entry.r_analog = static_cast<s32>(
426 button_state[ZR - BUTTON_HID_BEGIN]->GetStatus() ? HID_TRIGGER_MAX : 0);
427 pad_state.zl.Assign(false);
428 pad_state.zr.Assign(button_state[R - BUTTON_HID_BEGIN]->GetStatus());
429 pad_state.l.Assign(button_state[ZL - BUTTON_HID_BEGIN]->GetStatus());
430 pad_state.r.Assign(button_state[ZR - BUTTON_HID_BEGIN]->GetStatus());
431 }
407} 432}
408 433
409void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, 434void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
@@ -418,6 +443,11 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
418 &npad.joy_left_states, &npad.joy_right_states, &npad.palma_states, 443 &npad.joy_left_states, &npad.joy_right_states, &npad.palma_states,
419 &npad.system_ext_states}; 444 &npad.system_ext_states};
420 445
446 // There is the posibility to have more controllers with analog triggers
447 const std::array<TriggerGeneric*, 1> controller_triggers{
448 &npad.gc_trigger_states,
449 };
450
421 for (auto* main_controller : controller_npads) { 451 for (auto* main_controller : controller_npads) {
422 main_controller->common.entry_count = 16; 452 main_controller->common.entry_count = 16;
423 main_controller->common.total_entry_count = 17; 453 main_controller->common.total_entry_count = 17;
@@ -435,6 +465,21 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
435 cur_entry.timestamp2 = cur_entry.timestamp; 465 cur_entry.timestamp2 = cur_entry.timestamp;
436 } 466 }
437 467
468 for (auto* analog_trigger : controller_triggers) {
469 analog_trigger->entry_count = 16;
470 analog_trigger->total_entry_count = 17;
471
472 const auto& last_entry = analog_trigger->trigger[analog_trigger->last_entry_index];
473
474 analog_trigger->timestamp = core_timing.GetCPUTicks();
475 analog_trigger->last_entry_index = (analog_trigger->last_entry_index + 1) % 17;
476
477 auto& cur_entry = analog_trigger->trigger[analog_trigger->last_entry_index];
478
479 cur_entry.timestamp = last_entry.timestamp + 1;
480 cur_entry.timestamp2 = cur_entry.timestamp;
481 }
482
438 const auto& controller_type = connected_controllers[i].type; 483 const auto& controller_type = connected_controllers[i].type;
439 484
440 if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) { 485 if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) {
@@ -444,6 +489,7 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
444 489
445 RequestPadStateUpdate(npad_index); 490 RequestPadStateUpdate(npad_index);
446 auto& pad_state = npad_pad_states[npad_index]; 491 auto& pad_state = npad_pad_states[npad_index];
492 auto& trigger_state = npad_trigger_states[npad_index];
447 493
448 auto& main_controller = 494 auto& main_controller =
449 npad.fullkey_states.npad[npad.fullkey_states.common.last_entry_index]; 495 npad.fullkey_states.npad[npad.fullkey_states.common.last_entry_index];
@@ -456,6 +502,8 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
456 auto& pokeball_entry = npad.palma_states.npad[npad.palma_states.common.last_entry_index]; 502 auto& pokeball_entry = npad.palma_states.npad[npad.palma_states.common.last_entry_index];
457 auto& libnx_entry = 503 auto& libnx_entry =
458 npad.system_ext_states.npad[npad.system_ext_states.common.last_entry_index]; 504 npad.system_ext_states.npad[npad.system_ext_states.common.last_entry_index];
505 auto& trigger_entry =
506 npad.gc_trigger_states.trigger[npad.gc_trigger_states.last_entry_index];
459 507
460 libnx_entry.connection_status.raw = 0; 508 libnx_entry.connection_status.raw = 0;
461 libnx_entry.connection_status.is_connected.Assign(1); 509 libnx_entry.connection_status.is_connected.Assign(1);
@@ -524,6 +572,18 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
524 572
525 libnx_entry.connection_status.is_right_connected.Assign(1); 573 libnx_entry.connection_status.is_right_connected.Assign(1);
526 break; 574 break;
575 case NPadControllerType::GameCube:
576 main_controller.connection_status.raw = 0;
577 main_controller.connection_status.is_connected.Assign(1);
578 main_controller.connection_status.is_wired.Assign(1);
579 main_controller.pad.pad_states.raw = pad_state.pad_states.raw;
580 main_controller.pad.l_stick = pad_state.l_stick;
581 main_controller.pad.r_stick = pad_state.r_stick;
582 trigger_entry.l_analog = trigger_state.l_analog;
583 trigger_entry.r_analog = trigger_state.r_analog;
584
585 libnx_entry.connection_status.is_wired.Assign(1);
586 break;
527 case NPadControllerType::Pokeball: 587 case NPadControllerType::Pokeball:
528 pokeball_entry.connection_status.raw = 0; 588 pokeball_entry.connection_status.raw = 0;
529 pokeball_entry.connection_status.is_connected.Assign(1); 589 pokeball_entry.connection_status.is_connected.Assign(1);
@@ -674,6 +734,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing
674 right_sixaxis_entry.orientation = motion_devices[1].orientation; 734 right_sixaxis_entry.orientation = motion_devices[1].orientation;
675 } 735 }
676 break; 736 break;
737 case NPadControllerType::GameCube:
677 case NPadControllerType::Pokeball: 738 case NPadControllerType::Pokeball:
678 break; 739 break;
679 } 740 }
@@ -1135,6 +1196,8 @@ bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const
1135 return style.joycon_left; 1196 return style.joycon_left;
1136 case NPadControllerType::JoyRight: 1197 case NPadControllerType::JoyRight:
1137 return style.joycon_right; 1198 return style.joycon_right;
1199 case NPadControllerType::GameCube:
1200 return style.gamecube;
1138 case NPadControllerType::Pokeball: 1201 case NPadControllerType::Pokeball:
1139 return style.palma; 1202 return style.palma;
1140 default: 1203 default:
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 48bab988c..bc2e6779d 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -51,6 +51,7 @@ public:
51 JoyDual, 51 JoyDual,
52 JoyLeft, 52 JoyLeft,
53 JoyRight, 53 JoyRight,
54 GameCube,
54 Pokeball, 55 Pokeball,
55 }; 56 };
56 57
@@ -60,6 +61,7 @@ public:
60 JoyconDual = 5, 61 JoyconDual = 5,
61 JoyconLeft = 6, 62 JoyconLeft = 6,
62 JoyconRight = 7, 63 JoyconRight = 7,
64 GameCube = 8,
63 Pokeball = 9, 65 Pokeball = 9,
64 MaxNpadType = 10, 66 MaxNpadType = 10,
65 }; 67 };
@@ -389,6 +391,25 @@ private:
389 }; 391 };
390 static_assert(sizeof(SixAxisGeneric) == 0x708, "SixAxisGeneric is an invalid size"); 392 static_assert(sizeof(SixAxisGeneric) == 0x708, "SixAxisGeneric is an invalid size");
391 393
394 struct TriggerState {
395 s64_le timestamp{};
396 s64_le timestamp2{};
397 s32_le l_analog{};
398 s32_le r_analog{};
399 };
400 static_assert(sizeof(TriggerState) == 0x18, "TriggerState is an invalid size");
401
402 struct TriggerGeneric {
403 INSERT_PADDING_BYTES(0x4);
404 s64_le timestamp;
405 INSERT_PADDING_BYTES(0x4);
406 s64_le total_entry_count;
407 s64_le last_entry_index;
408 s64_le entry_count;
409 std::array<TriggerState, 17> trigger{};
410 };
411 static_assert(sizeof(TriggerGeneric) == 0x1C8, "TriggerGeneric is an invalid size");
412
392 struct NPadSystemProperties { 413 struct NPadSystemProperties {
393 union { 414 union {
394 s64_le raw{}; 415 s64_le raw{};
@@ -509,7 +530,9 @@ private:
509 AppletFooterUiType footer_type; 530 AppletFooterUiType footer_type;
510 // nfc_states needs to be checked switchbrew does not match with HW 531 // nfc_states needs to be checked switchbrew does not match with HW
511 NfcXcdHandle nfc_states; 532 NfcXcdHandle nfc_states;
512 INSERT_PADDING_BYTES(0xdef); 533 INSERT_PADDING_BYTES(0x8); // Mutex
534 TriggerGeneric gc_trigger_states;
535 INSERT_PADDING_BYTES(0xc1f);
513 }; 536 };
514 static_assert(sizeof(NPadEntry) == 0x5000, "NPadEntry is an invalid size"); 537 static_assert(sizeof(NPadEntry) == 0x5000, "NPadEntry is an invalid size");
515 538
@@ -560,6 +583,7 @@ private:
560 f32 sixaxis_fusion_parameter2{}; 583 f32 sixaxis_fusion_parameter2{};
561 bool sixaxis_at_rest{true}; 584 bool sixaxis_at_rest{true};
562 std::array<ControllerPad, 10> npad_pad_states{}; 585 std::array<ControllerPad, 10> npad_pad_states{};
586 std::array<TriggerState, 10> npad_trigger_states{};
563 bool is_in_lr_assignment_mode{false}; 587 bool is_in_lr_assignment_mode{false};
564 Core::System& system; 588 Core::System& system;
565}; 589};
diff --git a/src/input_common/settings.h b/src/input_common/settings.h
index 75486554b..a59f5d461 100644
--- a/src/input_common/settings.h
+++ b/src/input_common/settings.h
@@ -340,6 +340,7 @@ enum class ControllerType {
340 LeftJoycon, 340 LeftJoycon,
341 RightJoycon, 341 RightJoycon,
342 Handheld, 342 Handheld,
343 GameCube,
343}; 344};
344 345
345struct PlayerInput { 346struct PlayerInput {
diff --git a/src/yuzu/applets/controller.cpp b/src/yuzu/applets/controller.cpp
index c680fd2c2..b92cd6886 100644
--- a/src/yuzu/applets/controller.cpp
+++ b/src/yuzu/applets/controller.cpp
@@ -67,6 +67,8 @@ bool IsControllerCompatible(Settings::ControllerType controller_type,
67 return parameters.allow_right_joycon; 67 return parameters.allow_right_joycon;
68 case Settings::ControllerType::Handheld: 68 case Settings::ControllerType::Handheld:
69 return parameters.enable_single_mode && parameters.allow_handheld; 69 return parameters.enable_single_mode && parameters.allow_handheld;
70 case Settings::ControllerType::GameCube:
71 return parameters.allow_gamecube_controller;
70 default: 72 default:
71 return false; 73 return false;
72 } 74 }
@@ -370,7 +372,7 @@ void QtControllerSelectorDialog::SetSupportedControllers() {
370 QStringLiteral("image: url(:/controller/applet_joycon_right%0_disabled); ").arg(theme)); 372 QStringLiteral("image: url(:/controller/applet_joycon_right%0_disabled); ").arg(theme));
371 } 373 }
372 374
373 if (parameters.allow_pro_controller) { 375 if (parameters.allow_pro_controller || parameters.allow_gamecube_controller) {
374 ui->controllerSupported5->setStyleSheet( 376 ui->controllerSupported5->setStyleSheet(
375 QStringLiteral("image: url(:/controller/applet_pro_controller%0); ").arg(theme)); 377 QStringLiteral("image: url(:/controller/applet_pro_controller%0); ").arg(theme));
376 } else { 378 } else {
@@ -420,6 +422,10 @@ void QtControllerSelectorDialog::SetEmulatedControllers(std::size_t player_index
420 Settings::ControllerType::Handheld); 422 Settings::ControllerType::Handheld);
421 emulated_controllers[player_index]->addItem(tr("Handheld")); 423 emulated_controllers[player_index]->addItem(tr("Handheld"));
422 } 424 }
425
426 pairs.emplace_back(emulated_controllers[player_index]->count(),
427 Settings::ControllerType::GameCube);
428 emulated_controllers[player_index]->addItem(tr("GameCube Controller"));
423} 429}
424 430
425Settings::ControllerType QtControllerSelectorDialog::GetControllerTypeFromIndex( 431Settings::ControllerType QtControllerSelectorDialog::GetControllerTypeFromIndex(
@@ -461,6 +467,7 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index)
461 switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(), 467 switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(),
462 player_index)) { 468 player_index)) {
463 case Settings::ControllerType::ProController: 469 case Settings::ControllerType::ProController:
470 case Settings::ControllerType::GameCube:
464 return QStringLiteral("image: url(:/controller/applet_pro_controller%0); "); 471 return QStringLiteral("image: url(:/controller/applet_pro_controller%0); ");
465 case Settings::ControllerType::DualJoyconDetached: 472 case Settings::ControllerType::DualJoyconDetached:
466 return QStringLiteral("image: url(:/controller/applet_dual_joycon%0); "); 473 return QStringLiteral("image: url(:/controller/applet_dual_joycon%0); ");
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index c9d19c948..21d0d3449 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -467,10 +467,14 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
467 467
468 UpdateControllerIcon(); 468 UpdateControllerIcon();
469 UpdateControllerAvailableButtons(); 469 UpdateControllerAvailableButtons();
470 UpdateControllerEnabledButtons();
471 UpdateControllerButtonNames();
470 UpdateMotionButtons(); 472 UpdateMotionButtons();
471 connect(ui->comboControllerType, qOverload<int>(&QComboBox::currentIndexChanged), [this](int) { 473 connect(ui->comboControllerType, qOverload<int>(&QComboBox::currentIndexChanged), [this](int) {
472 UpdateControllerIcon(); 474 UpdateControllerIcon();
473 UpdateControllerAvailableButtons(); 475 UpdateControllerAvailableButtons();
476 UpdateControllerEnabledButtons();
477 UpdateControllerButtonNames();
474 UpdateMotionButtons(); 478 UpdateMotionButtons();
475 }); 479 });
476 480
@@ -558,9 +562,6 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
558 &ConfigureInputPlayer::SaveProfile); 562 &ConfigureInputPlayer::SaveProfile);
559 563
560 LoadConfiguration(); 564 LoadConfiguration();
561
562 // TODO(wwylele): enable this when we actually emulate it
563 ui->buttonHome->setEnabled(false);
564 ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); 565 ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param);
565 ui->controllerFrame->SetConnectedStatus(ui->groupConnectedController->isChecked()); 566 ui->controllerFrame->SetConnectedStatus(ui->groupConnectedController->isChecked());
566} 567}
@@ -924,6 +925,12 @@ void ConfigureInputPlayer::SetConnectableControllers() {
924 Settings::ControllerType::Handheld); 925 Settings::ControllerType::Handheld);
925 ui->comboControllerType->addItem(tr("Handheld")); 926 ui->comboControllerType->addItem(tr("Handheld"));
926 } 927 }
928
929 if (enable_all || npad_style_set.gamecube == 1) {
930 index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
931 Settings::ControllerType::GameCube);
932 ui->comboControllerType->addItem(tr("GameCube Controller"));
933 }
927 }; 934 };
928 935
929 Core::System& system{Core::System::GetInstance()}; 936 Core::System& system{Core::System::GetInstance()};
@@ -1014,7 +1021,7 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() {
1014 1021
1015 // List of all the widgets that will be hidden by any of the following layouts that need 1022 // List of all the widgets that will be hidden by any of the following layouts that need
1016 // "unhidden" after the controller type changes 1023 // "unhidden" after the controller type changes
1017 const std::array<QWidget*, 9> layout_show = { 1024 const std::array<QWidget*, 11> layout_show = {
1018 ui->buttonShoulderButtonsSLSR, 1025 ui->buttonShoulderButtonsSLSR,
1019 ui->horizontalSpacerShoulderButtonsWidget, 1026 ui->horizontalSpacerShoulderButtonsWidget,
1020 ui->horizontalSpacerShoulderButtonsWidget2, 1027 ui->horizontalSpacerShoulderButtonsWidget2,
@@ -1024,6 +1031,8 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() {
1024 ui->buttonShoulderButtonsRight, 1031 ui->buttonShoulderButtonsRight,
1025 ui->buttonMiscButtonsPlusHome, 1032 ui->buttonMiscButtonsPlusHome,
1026 ui->bottomRight, 1033 ui->bottomRight,
1034 ui->buttonMiscButtonsMinusGroup,
1035 ui->buttonMiscButtonsScreenshotGroup,
1027 }; 1036 };
1028 1037
1029 for (auto* widget : layout_show) { 1038 for (auto* widget : layout_show) {
@@ -1056,6 +1065,14 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() {
1056 ui->bottomLeft, 1065 ui->bottomLeft,
1057 }; 1066 };
1058 break; 1067 break;
1068 case Settings::ControllerType::GameCube:
1069 layout_hidden = {
1070 ui->buttonShoulderButtonsSLSR,
1071 ui->horizontalSpacerShoulderButtonsWidget2,
1072 ui->buttonMiscButtonsMinusGroup,
1073 ui->buttonMiscButtonsScreenshotGroup,
1074 };
1075 break;
1059 } 1076 }
1060 1077
1061 for (auto* widget : layout_hidden) { 1078 for (auto* widget : layout_hidden) {
@@ -1063,6 +1080,52 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() {
1063 } 1080 }
1064} 1081}
1065 1082
1083void ConfigureInputPlayer::UpdateControllerEnabledButtons() {
1084 auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex());
1085 if (debug) {
1086 layout = Settings::ControllerType::ProController;
1087 }
1088
1089 // List of all the widgets that will be disabled by any of the following layouts that need
1090 // "enabled" after the controller type changes
1091 const std::array<QWidget*, 4> layout_enable = {
1092 ui->buttonHome,
1093 ui->buttonLStickPressedGroup,
1094 ui->groupRStickPressed,
1095 ui->buttonShoulderButtonsButtonLGroup,
1096 };
1097
1098 for (auto* widget : layout_enable) {
1099 widget->setEnabled(true);
1100 }
1101
1102 std::vector<QWidget*> layout_disable;
1103 switch (layout) {
1104 case Settings::ControllerType::ProController:
1105 case Settings::ControllerType::DualJoyconDetached:
1106 case Settings::ControllerType::Handheld:
1107 case Settings::ControllerType::LeftJoycon:
1108 case Settings::ControllerType::RightJoycon:
1109 // TODO(wwylele): enable this when we actually emulate it
1110 layout_disable = {
1111 ui->buttonHome,
1112 };
1113 break;
1114 case Settings::ControllerType::GameCube:
1115 layout_disable = {
1116 ui->buttonHome,
1117 ui->buttonLStickPressedGroup,
1118 ui->groupRStickPressed,
1119 ui->buttonShoulderButtonsButtonLGroup,
1120 };
1121 break;
1122 }
1123
1124 for (auto* widget : layout_disable) {
1125 widget->setEnabled(false);
1126 }
1127}
1128
1066void ConfigureInputPlayer::UpdateMotionButtons() { 1129void ConfigureInputPlayer::UpdateMotionButtons() {
1067 if (debug) { 1130 if (debug) {
1068 // Motion isn't used with the debug controller, hide both groupboxes. 1131 // Motion isn't used with the debug controller, hide both groupboxes.
@@ -1085,6 +1148,11 @@ void ConfigureInputPlayer::UpdateMotionButtons() {
1085 ui->buttonMotionLeftGroup->hide(); 1148 ui->buttonMotionLeftGroup->hide();
1086 ui->buttonMotionRightGroup->show(); 1149 ui->buttonMotionRightGroup->show();
1087 break; 1150 break;
1151 case Settings::ControllerType::GameCube:
1152 // Hide both "Motion 1/2".
1153 ui->buttonMotionLeftGroup->hide();
1154 ui->buttonMotionRightGroup->hide();
1155 break;
1088 case Settings::ControllerType::DualJoyconDetached: 1156 case Settings::ControllerType::DualJoyconDetached:
1089 default: 1157 default:
1090 // Show both "Motion 1/2". 1158 // Show both "Motion 1/2".
@@ -1094,6 +1162,36 @@ void ConfigureInputPlayer::UpdateMotionButtons() {
1094 } 1162 }
1095} 1163}
1096 1164
1165void ConfigureInputPlayer::UpdateControllerButtonNames() {
1166 auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex());
1167 if (debug) {
1168 layout = Settings::ControllerType::ProController;
1169 }
1170
1171 switch (layout) {
1172 case Settings::ControllerType::ProController:
1173 case Settings::ControllerType::DualJoyconDetached:
1174 case Settings::ControllerType::Handheld:
1175 case Settings::ControllerType::LeftJoycon:
1176 case Settings::ControllerType::RightJoycon:
1177 ui->buttonMiscButtonsPlusGroup->setTitle(tr("Plus"));
1178 ui->buttonShoulderButtonsButtonZLGroup->setTitle(tr("ZL"));
1179 ui->buttonShoulderButtonsZRGroup->setTitle(tr("ZR"));
1180 ui->buttonShoulderButtonsRGroup->setTitle(tr("R"));
1181 ui->LStick->setTitle(tr("Left Stick"));
1182 ui->RStick->setTitle(tr("Right Stick"));
1183 break;
1184 case Settings::ControllerType::GameCube:
1185 ui->buttonMiscButtonsPlusGroup->setTitle(tr("Start / Pause"));
1186 ui->buttonShoulderButtonsButtonZLGroup->setTitle(tr("L"));
1187 ui->buttonShoulderButtonsZRGroup->setTitle(tr("R"));
1188 ui->buttonShoulderButtonsRGroup->setTitle(tr("Z"));
1189 ui->LStick->setTitle(tr("Control Stick"));
1190 ui->RStick->setTitle(tr("C-Stick"));
1191 break;
1192 }
1193}
1194
1097void ConfigureInputPlayer::UpdateMappingWithDefaults() { 1195void ConfigureInputPlayer::UpdateMappingWithDefaults() {
1098 if (ui->comboDevices->currentIndex() == 0) { 1196 if (ui->comboDevices->currentIndex() == 0) {
1099 return; 1197 return;
diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h
index da2b89136..efe953fbc 100644
--- a/src/yuzu/configuration/configure_input_player.h
+++ b/src/yuzu/configuration/configure_input_player.h
@@ -143,9 +143,15 @@ private:
143 /// Hides and disables controller settings based on the current controller type. 143 /// Hides and disables controller settings based on the current controller type.
144 void UpdateControllerAvailableButtons(); 144 void UpdateControllerAvailableButtons();
145 145
146 /// Disables controller settings based on the current controller type.
147 void UpdateControllerEnabledButtons();
148
146 /// Shows or hides motion groupboxes based on the current controller type. 149 /// Shows or hides motion groupboxes based on the current controller type.
147 void UpdateMotionButtons(); 150 void UpdateMotionButtons();
148 151
152 /// Alters the button names based on the current controller type.
153 void UpdateControllerButtonNames();
154
149 /// Gets the default controller mapping for this device and auto configures the input to match. 155 /// Gets the default controller mapping for this device and auto configures the input to match.
150 void UpdateMappingWithDefaults(); 156 void UpdateMappingWithDefaults();
151 157
diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp
index 0e8a964d2..61ba91cef 100644
--- a/src/yuzu/configuration/configure_input_player_widget.cpp
+++ b/src/yuzu/configuration/configure_input_player_widget.cpp
@@ -227,6 +227,9 @@ void PlayerControlPreview::paintEvent(QPaintEvent* event) {
227 case Settings::ControllerType::RightJoycon: 227 case Settings::ControllerType::RightJoycon:
228 DrawRightController(p, center); 228 DrawRightController(p, center);
229 break; 229 break;
230 case Settings::ControllerType::GameCube:
231 DrawGCController(p, center);
232 break;
230 case Settings::ControllerType::ProController: 233 case Settings::ControllerType::ProController:
231 default: 234 default:
232 DrawProController(p, center); 235 DrawProController(p, center);