forked from suyu/suyu
Merge pull request #4940 from german77/nativeGC
HID: Implement GC controller in game
This commit is contained in:
commit
b53b50adec
8 changed files with 209 additions and 6 deletions
|
@ -31,6 +31,7 @@ struct ControllerParameters {
|
||||||
bool allow_dual_joycons{};
|
bool allow_dual_joycons{};
|
||||||
bool allow_left_joycon{};
|
bool allow_left_joycon{};
|
||||||
bool allow_right_joycon{};
|
bool allow_right_joycon{};
|
||||||
|
bool allow_gamecube_controller{};
|
||||||
};
|
};
|
||||||
|
|
||||||
class ControllerApplet {
|
class ControllerApplet {
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
namespace Service::HID {
|
namespace Service::HID {
|
||||||
constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
|
constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
|
||||||
|
constexpr s32 HID_TRIGGER_MAX = 0x7fff;
|
||||||
[[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff;
|
[[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff;
|
||||||
constexpr std::size_t NPAD_OFFSET = 0x9A00;
|
constexpr std::size_t NPAD_OFFSET = 0x9A00;
|
||||||
constexpr u32 BATTERY_FULL = 2;
|
constexpr u32 BATTERY_FULL = 2;
|
||||||
|
@ -48,6 +49,8 @@ Controller_NPad::NPadControllerType Controller_NPad::MapSettingsTypeToNPad(
|
||||||
return NPadControllerType::JoyRight;
|
return NPadControllerType::JoyRight;
|
||||||
case Settings::ControllerType::Handheld:
|
case Settings::ControllerType::Handheld:
|
||||||
return NPadControllerType::Handheld;
|
return NPadControllerType::Handheld;
|
||||||
|
case Settings::ControllerType::GameCube:
|
||||||
|
return NPadControllerType::GameCube;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
return NPadControllerType::ProController;
|
return NPadControllerType::ProController;
|
||||||
|
@ -67,6 +70,8 @@ Settings::ControllerType Controller_NPad::MapNPadToSettingsType(
|
||||||
return Settings::ControllerType::RightJoycon;
|
return Settings::ControllerType::RightJoycon;
|
||||||
case NPadControllerType::Handheld:
|
case NPadControllerType::Handheld:
|
||||||
return Settings::ControllerType::Handheld;
|
return Settings::ControllerType::Handheld;
|
||||||
|
case NPadControllerType::GameCube:
|
||||||
|
return Settings::ControllerType::GameCube;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
return Settings::ControllerType::ProController;
|
return Settings::ControllerType::ProController;
|
||||||
|
@ -209,6 +214,13 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
|
||||||
controller.assignment_mode = NpadAssignments::Single;
|
controller.assignment_mode = NpadAssignments::Single;
|
||||||
controller.footer_type = AppletFooterUiType::JoyRightHorizontal;
|
controller.footer_type = AppletFooterUiType::JoyRightHorizontal;
|
||||||
break;
|
break;
|
||||||
|
case NPadControllerType::GameCube:
|
||||||
|
controller.style_set.gamecube.Assign(1);
|
||||||
|
// The GC Controller behaves like a wired Pro Controller
|
||||||
|
controller.device_type.fullkey.Assign(1);
|
||||||
|
controller.system_properties.is_vertical.Assign(1);
|
||||||
|
controller.system_properties.use_plus.Assign(1);
|
||||||
|
break;
|
||||||
case NPadControllerType::Pokeball:
|
case NPadControllerType::Pokeball:
|
||||||
controller.style_set.palma.Assign(1);
|
controller.style_set.palma.Assign(1);
|
||||||
controller.device_type.palma.Assign(1);
|
controller.device_type.palma.Assign(1);
|
||||||
|
@ -259,6 +271,7 @@ void Controller_NPad::OnInit() {
|
||||||
style.joycon_right.Assign(1);
|
style.joycon_right.Assign(1);
|
||||||
style.joycon_dual.Assign(1);
|
style.joycon_dual.Assign(1);
|
||||||
style.fullkey.Assign(1);
|
style.fullkey.Assign(1);
|
||||||
|
style.gamecube.Assign(1);
|
||||||
style.palma.Assign(1);
|
style.palma.Assign(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,6 +352,7 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
|
||||||
auto& pad_state = npad_pad_states[controller_idx].pad_states;
|
auto& pad_state = npad_pad_states[controller_idx].pad_states;
|
||||||
auto& lstick_entry = npad_pad_states[controller_idx].l_stick;
|
auto& lstick_entry = npad_pad_states[controller_idx].l_stick;
|
||||||
auto& rstick_entry = npad_pad_states[controller_idx].r_stick;
|
auto& rstick_entry = npad_pad_states[controller_idx].r_stick;
|
||||||
|
auto& trigger_entry = npad_trigger_states[controller_idx];
|
||||||
const auto& button_state = buttons[controller_idx];
|
const auto& button_state = buttons[controller_idx];
|
||||||
const auto& analog_state = sticks[controller_idx];
|
const auto& analog_state = sticks[controller_idx];
|
||||||
const auto [stick_l_x_f, stick_l_y_f] =
|
const auto [stick_l_x_f, stick_l_y_f] =
|
||||||
|
@ -404,6 +418,17 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
|
||||||
pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus());
|
pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus());
|
||||||
pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus());
|
pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (controller_type == NPadControllerType::GameCube) {
|
||||||
|
trigger_entry.l_analog = static_cast<s32>(
|
||||||
|
button_state[ZL - BUTTON_HID_BEGIN]->GetStatus() ? HID_TRIGGER_MAX : 0);
|
||||||
|
trigger_entry.r_analog = static_cast<s32>(
|
||||||
|
button_state[ZR - BUTTON_HID_BEGIN]->GetStatus() ? HID_TRIGGER_MAX : 0);
|
||||||
|
pad_state.zl.Assign(false);
|
||||||
|
pad_state.zr.Assign(button_state[R - BUTTON_HID_BEGIN]->GetStatus());
|
||||||
|
pad_state.l.Assign(button_state[ZL - BUTTON_HID_BEGIN]->GetStatus());
|
||||||
|
pad_state.r.Assign(button_state[ZR - BUTTON_HID_BEGIN]->GetStatus());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
|
void 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*
|
||||||
&npad.joy_left_states, &npad.joy_right_states, &npad.palma_states,
|
&npad.joy_left_states, &npad.joy_right_states, &npad.palma_states,
|
||||||
&npad.system_ext_states};
|
&npad.system_ext_states};
|
||||||
|
|
||||||
|
// There is the posibility to have more controllers with analog triggers
|
||||||
|
const std::array<TriggerGeneric*, 1> controller_triggers{
|
||||||
|
&npad.gc_trigger_states,
|
||||||
|
};
|
||||||
|
|
||||||
for (auto* main_controller : controller_npads) {
|
for (auto* main_controller : controller_npads) {
|
||||||
main_controller->common.entry_count = 16;
|
main_controller->common.entry_count = 16;
|
||||||
main_controller->common.total_entry_count = 17;
|
main_controller->common.total_entry_count = 17;
|
||||||
|
@ -435,6 +465,21 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
|
||||||
cur_entry.timestamp2 = cur_entry.timestamp;
|
cur_entry.timestamp2 = cur_entry.timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto* analog_trigger : controller_triggers) {
|
||||||
|
analog_trigger->entry_count = 16;
|
||||||
|
analog_trigger->total_entry_count = 17;
|
||||||
|
|
||||||
|
const auto& last_entry = analog_trigger->trigger[analog_trigger->last_entry_index];
|
||||||
|
|
||||||
|
analog_trigger->timestamp = core_timing.GetCPUTicks();
|
||||||
|
analog_trigger->last_entry_index = (analog_trigger->last_entry_index + 1) % 17;
|
||||||
|
|
||||||
|
auto& cur_entry = analog_trigger->trigger[analog_trigger->last_entry_index];
|
||||||
|
|
||||||
|
cur_entry.timestamp = last_entry.timestamp + 1;
|
||||||
|
cur_entry.timestamp2 = cur_entry.timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
const auto& controller_type = connected_controllers[i].type;
|
const auto& controller_type = connected_controllers[i].type;
|
||||||
|
|
||||||
if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) {
|
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*
|
||||||
|
|
||||||
RequestPadStateUpdate(npad_index);
|
RequestPadStateUpdate(npad_index);
|
||||||
auto& pad_state = npad_pad_states[npad_index];
|
auto& pad_state = npad_pad_states[npad_index];
|
||||||
|
auto& trigger_state = npad_trigger_states[npad_index];
|
||||||
|
|
||||||
auto& main_controller =
|
auto& main_controller =
|
||||||
npad.fullkey_states.npad[npad.fullkey_states.common.last_entry_index];
|
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*
|
||||||
auto& pokeball_entry = npad.palma_states.npad[npad.palma_states.common.last_entry_index];
|
auto& pokeball_entry = npad.palma_states.npad[npad.palma_states.common.last_entry_index];
|
||||||
auto& libnx_entry =
|
auto& libnx_entry =
|
||||||
npad.system_ext_states.npad[npad.system_ext_states.common.last_entry_index];
|
npad.system_ext_states.npad[npad.system_ext_states.common.last_entry_index];
|
||||||
|
auto& trigger_entry =
|
||||||
|
npad.gc_trigger_states.trigger[npad.gc_trigger_states.last_entry_index];
|
||||||
|
|
||||||
libnx_entry.connection_status.raw = 0;
|
libnx_entry.connection_status.raw = 0;
|
||||||
libnx_entry.connection_status.is_connected.Assign(1);
|
libnx_entry.connection_status.is_connected.Assign(1);
|
||||||
|
@ -524,6 +572,18 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
|
||||||
|
|
||||||
libnx_entry.connection_status.is_right_connected.Assign(1);
|
libnx_entry.connection_status.is_right_connected.Assign(1);
|
||||||
break;
|
break;
|
||||||
|
case NPadControllerType::GameCube:
|
||||||
|
main_controller.connection_status.raw = 0;
|
||||||
|
main_controller.connection_status.is_connected.Assign(1);
|
||||||
|
main_controller.connection_status.is_wired.Assign(1);
|
||||||
|
main_controller.pad.pad_states.raw = pad_state.pad_states.raw;
|
||||||
|
main_controller.pad.l_stick = pad_state.l_stick;
|
||||||
|
main_controller.pad.r_stick = pad_state.r_stick;
|
||||||
|
trigger_entry.l_analog = trigger_state.l_analog;
|
||||||
|
trigger_entry.r_analog = trigger_state.r_analog;
|
||||||
|
|
||||||
|
libnx_entry.connection_status.is_wired.Assign(1);
|
||||||
|
break;
|
||||||
case NPadControllerType::Pokeball:
|
case NPadControllerType::Pokeball:
|
||||||
pokeball_entry.connection_status.raw = 0;
|
pokeball_entry.connection_status.raw = 0;
|
||||||
pokeball_entry.connection_status.is_connected.Assign(1);
|
pokeball_entry.connection_status.is_connected.Assign(1);
|
||||||
|
@ -674,6 +734,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing
|
||||||
right_sixaxis_entry.orientation = motion_devices[1].orientation;
|
right_sixaxis_entry.orientation = motion_devices[1].orientation;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case NPadControllerType::GameCube:
|
||||||
case NPadControllerType::Pokeball:
|
case NPadControllerType::Pokeball:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1135,6 +1196,8 @@ bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const
|
||||||
return style.joycon_left;
|
return style.joycon_left;
|
||||||
case NPadControllerType::JoyRight:
|
case NPadControllerType::JoyRight:
|
||||||
return style.joycon_right;
|
return style.joycon_right;
|
||||||
|
case NPadControllerType::GameCube:
|
||||||
|
return style.gamecube;
|
||||||
case NPadControllerType::Pokeball:
|
case NPadControllerType::Pokeball:
|
||||||
return style.palma;
|
return style.palma;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -51,6 +51,7 @@ public:
|
||||||
JoyDual,
|
JoyDual,
|
||||||
JoyLeft,
|
JoyLeft,
|
||||||
JoyRight,
|
JoyRight,
|
||||||
|
GameCube,
|
||||||
Pokeball,
|
Pokeball,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -60,6 +61,7 @@ public:
|
||||||
JoyconDual = 5,
|
JoyconDual = 5,
|
||||||
JoyconLeft = 6,
|
JoyconLeft = 6,
|
||||||
JoyconRight = 7,
|
JoyconRight = 7,
|
||||||
|
GameCube = 8,
|
||||||
Pokeball = 9,
|
Pokeball = 9,
|
||||||
MaxNpadType = 10,
|
MaxNpadType = 10,
|
||||||
};
|
};
|
||||||
|
@ -389,6 +391,25 @@ private:
|
||||||
};
|
};
|
||||||
static_assert(sizeof(SixAxisGeneric) == 0x708, "SixAxisGeneric is an invalid size");
|
static_assert(sizeof(SixAxisGeneric) == 0x708, "SixAxisGeneric is an invalid size");
|
||||||
|
|
||||||
|
struct TriggerState {
|
||||||
|
s64_le timestamp{};
|
||||||
|
s64_le timestamp2{};
|
||||||
|
s32_le l_analog{};
|
||||||
|
s32_le r_analog{};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(TriggerState) == 0x18, "TriggerState is an invalid size");
|
||||||
|
|
||||||
|
struct TriggerGeneric {
|
||||||
|
INSERT_PADDING_BYTES(0x4);
|
||||||
|
s64_le timestamp;
|
||||||
|
INSERT_PADDING_BYTES(0x4);
|
||||||
|
s64_le total_entry_count;
|
||||||
|
s64_le last_entry_index;
|
||||||
|
s64_le entry_count;
|
||||||
|
std::array<TriggerState, 17> trigger{};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(TriggerGeneric) == 0x1C8, "TriggerGeneric is an invalid size");
|
||||||
|
|
||||||
struct NPadSystemProperties {
|
struct NPadSystemProperties {
|
||||||
union {
|
union {
|
||||||
s64_le raw{};
|
s64_le raw{};
|
||||||
|
@ -509,7 +530,9 @@ private:
|
||||||
AppletFooterUiType footer_type;
|
AppletFooterUiType footer_type;
|
||||||
// nfc_states needs to be checked switchbrew does not match with HW
|
// nfc_states needs to be checked switchbrew does not match with HW
|
||||||
NfcXcdHandle nfc_states;
|
NfcXcdHandle nfc_states;
|
||||||
INSERT_PADDING_BYTES(0xdef);
|
INSERT_PADDING_BYTES(0x8); // Mutex
|
||||||
|
TriggerGeneric gc_trigger_states;
|
||||||
|
INSERT_PADDING_BYTES(0xc1f);
|
||||||
};
|
};
|
||||||
static_assert(sizeof(NPadEntry) == 0x5000, "NPadEntry is an invalid size");
|
static_assert(sizeof(NPadEntry) == 0x5000, "NPadEntry is an invalid size");
|
||||||
|
|
||||||
|
@ -560,6 +583,7 @@ private:
|
||||||
f32 sixaxis_fusion_parameter2{};
|
f32 sixaxis_fusion_parameter2{};
|
||||||
bool sixaxis_at_rest{true};
|
bool sixaxis_at_rest{true};
|
||||||
std::array<ControllerPad, 10> npad_pad_states{};
|
std::array<ControllerPad, 10> npad_pad_states{};
|
||||||
|
std::array<TriggerState, 10> npad_trigger_states{};
|
||||||
bool is_in_lr_assignment_mode{false};
|
bool is_in_lr_assignment_mode{false};
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
};
|
};
|
||||||
|
|
|
@ -340,6 +340,7 @@ enum class ControllerType {
|
||||||
LeftJoycon,
|
LeftJoycon,
|
||||||
RightJoycon,
|
RightJoycon,
|
||||||
Handheld,
|
Handheld,
|
||||||
|
GameCube,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PlayerInput {
|
struct PlayerInput {
|
||||||
|
|
|
@ -67,6 +67,8 @@ bool IsControllerCompatible(Settings::ControllerType controller_type,
|
||||||
return parameters.allow_right_joycon;
|
return parameters.allow_right_joycon;
|
||||||
case Settings::ControllerType::Handheld:
|
case Settings::ControllerType::Handheld:
|
||||||
return parameters.enable_single_mode && parameters.allow_handheld;
|
return parameters.enable_single_mode && parameters.allow_handheld;
|
||||||
|
case Settings::ControllerType::GameCube:
|
||||||
|
return parameters.allow_gamecube_controller;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -370,7 +372,7 @@ void QtControllerSelectorDialog::SetSupportedControllers() {
|
||||||
QStringLiteral("image: url(:/controller/applet_joycon_right%0_disabled); ").arg(theme));
|
QStringLiteral("image: url(:/controller/applet_joycon_right%0_disabled); ").arg(theme));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parameters.allow_pro_controller) {
|
if (parameters.allow_pro_controller || parameters.allow_gamecube_controller) {
|
||||||
ui->controllerSupported5->setStyleSheet(
|
ui->controllerSupported5->setStyleSheet(
|
||||||
QStringLiteral("image: url(:/controller/applet_pro_controller%0); ").arg(theme));
|
QStringLiteral("image: url(:/controller/applet_pro_controller%0); ").arg(theme));
|
||||||
} else {
|
} else {
|
||||||
|
@ -420,6 +422,10 @@ void QtControllerSelectorDialog::SetEmulatedControllers(std::size_t player_index
|
||||||
Settings::ControllerType::Handheld);
|
Settings::ControllerType::Handheld);
|
||||||
emulated_controllers[player_index]->addItem(tr("Handheld"));
|
emulated_controllers[player_index]->addItem(tr("Handheld"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pairs.emplace_back(emulated_controllers[player_index]->count(),
|
||||||
|
Settings::ControllerType::GameCube);
|
||||||
|
emulated_controllers[player_index]->addItem(tr("GameCube Controller"));
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings::ControllerType QtControllerSelectorDialog::GetControllerTypeFromIndex(
|
Settings::ControllerType QtControllerSelectorDialog::GetControllerTypeFromIndex(
|
||||||
|
@ -461,6 +467,7 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index)
|
||||||
switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(),
|
switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(),
|
||||||
player_index)) {
|
player_index)) {
|
||||||
case Settings::ControllerType::ProController:
|
case Settings::ControllerType::ProController:
|
||||||
|
case Settings::ControllerType::GameCube:
|
||||||
return QStringLiteral("image: url(:/controller/applet_pro_controller%0); ");
|
return QStringLiteral("image: url(:/controller/applet_pro_controller%0); ");
|
||||||
case Settings::ControllerType::DualJoyconDetached:
|
case Settings::ControllerType::DualJoyconDetached:
|
||||||
return QStringLiteral("image: url(:/controller/applet_dual_joycon%0); ");
|
return QStringLiteral("image: url(:/controller/applet_dual_joycon%0); ");
|
||||||
|
|
|
@ -467,10 +467,14 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
||||||
|
|
||||||
UpdateControllerIcon();
|
UpdateControllerIcon();
|
||||||
UpdateControllerAvailableButtons();
|
UpdateControllerAvailableButtons();
|
||||||
|
UpdateControllerEnabledButtons();
|
||||||
|
UpdateControllerButtonNames();
|
||||||
UpdateMotionButtons();
|
UpdateMotionButtons();
|
||||||
connect(ui->comboControllerType, qOverload<int>(&QComboBox::currentIndexChanged), [this](int) {
|
connect(ui->comboControllerType, qOverload<int>(&QComboBox::currentIndexChanged), [this](int) {
|
||||||
UpdateControllerIcon();
|
UpdateControllerIcon();
|
||||||
UpdateControllerAvailableButtons();
|
UpdateControllerAvailableButtons();
|
||||||
|
UpdateControllerEnabledButtons();
|
||||||
|
UpdateControllerButtonNames();
|
||||||
UpdateMotionButtons();
|
UpdateMotionButtons();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -558,9 +562,6 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
||||||
&ConfigureInputPlayer::SaveProfile);
|
&ConfigureInputPlayer::SaveProfile);
|
||||||
|
|
||||||
LoadConfiguration();
|
LoadConfiguration();
|
||||||
|
|
||||||
// TODO(wwylele): enable this when we actually emulate it
|
|
||||||
ui->buttonHome->setEnabled(false);
|
|
||||||
ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param);
|
ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param);
|
||||||
ui->controllerFrame->SetConnectedStatus(ui->groupConnectedController->isChecked());
|
ui->controllerFrame->SetConnectedStatus(ui->groupConnectedController->isChecked());
|
||||||
}
|
}
|
||||||
|
@ -924,6 +925,12 @@ void ConfigureInputPlayer::SetConnectableControllers() {
|
||||||
Settings::ControllerType::Handheld);
|
Settings::ControllerType::Handheld);
|
||||||
ui->comboControllerType->addItem(tr("Handheld"));
|
ui->comboControllerType->addItem(tr("Handheld"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (enable_all || npad_style_set.gamecube == 1) {
|
||||||
|
index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
|
||||||
|
Settings::ControllerType::GameCube);
|
||||||
|
ui->comboControllerType->addItem(tr("GameCube Controller"));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Core::System& system{Core::System::GetInstance()};
|
Core::System& system{Core::System::GetInstance()};
|
||||||
|
@ -1014,7 +1021,7 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() {
|
||||||
|
|
||||||
// List of all the widgets that will be hidden by any of the following layouts that need
|
// List of all the widgets that will be hidden by any of the following layouts that need
|
||||||
// "unhidden" after the controller type changes
|
// "unhidden" after the controller type changes
|
||||||
const std::array<QWidget*, 9> layout_show = {
|
const std::array<QWidget*, 11> layout_show = {
|
||||||
ui->buttonShoulderButtonsSLSR,
|
ui->buttonShoulderButtonsSLSR,
|
||||||
ui->horizontalSpacerShoulderButtonsWidget,
|
ui->horizontalSpacerShoulderButtonsWidget,
|
||||||
ui->horizontalSpacerShoulderButtonsWidget2,
|
ui->horizontalSpacerShoulderButtonsWidget2,
|
||||||
|
@ -1024,6 +1031,8 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() {
|
||||||
ui->buttonShoulderButtonsRight,
|
ui->buttonShoulderButtonsRight,
|
||||||
ui->buttonMiscButtonsPlusHome,
|
ui->buttonMiscButtonsPlusHome,
|
||||||
ui->bottomRight,
|
ui->bottomRight,
|
||||||
|
ui->buttonMiscButtonsMinusGroup,
|
||||||
|
ui->buttonMiscButtonsScreenshotGroup,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto* widget : layout_show) {
|
for (auto* widget : layout_show) {
|
||||||
|
@ -1056,6 +1065,14 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() {
|
||||||
ui->bottomLeft,
|
ui->bottomLeft,
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
|
case Settings::ControllerType::GameCube:
|
||||||
|
layout_hidden = {
|
||||||
|
ui->buttonShoulderButtonsSLSR,
|
||||||
|
ui->horizontalSpacerShoulderButtonsWidget2,
|
||||||
|
ui->buttonMiscButtonsMinusGroup,
|
||||||
|
ui->buttonMiscButtonsScreenshotGroup,
|
||||||
|
};
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto* widget : layout_hidden) {
|
for (auto* widget : layout_hidden) {
|
||||||
|
@ -1063,6 +1080,52 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConfigureInputPlayer::UpdateControllerEnabledButtons() {
|
||||||
|
auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex());
|
||||||
|
if (debug) {
|
||||||
|
layout = Settings::ControllerType::ProController;
|
||||||
|
}
|
||||||
|
|
||||||
|
// List of all the widgets that will be disabled by any of the following layouts that need
|
||||||
|
// "enabled" after the controller type changes
|
||||||
|
const std::array<QWidget*, 4> layout_enable = {
|
||||||
|
ui->buttonHome,
|
||||||
|
ui->buttonLStickPressedGroup,
|
||||||
|
ui->groupRStickPressed,
|
||||||
|
ui->buttonShoulderButtonsButtonLGroup,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto* widget : layout_enable) {
|
||||||
|
widget->setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<QWidget*> layout_disable;
|
||||||
|
switch (layout) {
|
||||||
|
case Settings::ControllerType::ProController:
|
||||||
|
case Settings::ControllerType::DualJoyconDetached:
|
||||||
|
case Settings::ControllerType::Handheld:
|
||||||
|
case Settings::ControllerType::LeftJoycon:
|
||||||
|
case Settings::ControllerType::RightJoycon:
|
||||||
|
// TODO(wwylele): enable this when we actually emulate it
|
||||||
|
layout_disable = {
|
||||||
|
ui->buttonHome,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case Settings::ControllerType::GameCube:
|
||||||
|
layout_disable = {
|
||||||
|
ui->buttonHome,
|
||||||
|
ui->buttonLStickPressedGroup,
|
||||||
|
ui->groupRStickPressed,
|
||||||
|
ui->buttonShoulderButtonsButtonLGroup,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto* widget : layout_disable) {
|
||||||
|
widget->setEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ConfigureInputPlayer::UpdateMotionButtons() {
|
void ConfigureInputPlayer::UpdateMotionButtons() {
|
||||||
if (debug) {
|
if (debug) {
|
||||||
// Motion isn't used with the debug controller, hide both groupboxes.
|
// Motion isn't used with the debug controller, hide both groupboxes.
|
||||||
|
@ -1085,6 +1148,11 @@ void ConfigureInputPlayer::UpdateMotionButtons() {
|
||||||
ui->buttonMotionLeftGroup->hide();
|
ui->buttonMotionLeftGroup->hide();
|
||||||
ui->buttonMotionRightGroup->show();
|
ui->buttonMotionRightGroup->show();
|
||||||
break;
|
break;
|
||||||
|
case Settings::ControllerType::GameCube:
|
||||||
|
// Hide both "Motion 1/2".
|
||||||
|
ui->buttonMotionLeftGroup->hide();
|
||||||
|
ui->buttonMotionRightGroup->hide();
|
||||||
|
break;
|
||||||
case Settings::ControllerType::DualJoyconDetached:
|
case Settings::ControllerType::DualJoyconDetached:
|
||||||
default:
|
default:
|
||||||
// Show both "Motion 1/2".
|
// Show both "Motion 1/2".
|
||||||
|
@ -1094,6 +1162,36 @@ void ConfigureInputPlayer::UpdateMotionButtons() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConfigureInputPlayer::UpdateControllerButtonNames() {
|
||||||
|
auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex());
|
||||||
|
if (debug) {
|
||||||
|
layout = Settings::ControllerType::ProController;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (layout) {
|
||||||
|
case Settings::ControllerType::ProController:
|
||||||
|
case Settings::ControllerType::DualJoyconDetached:
|
||||||
|
case Settings::ControllerType::Handheld:
|
||||||
|
case Settings::ControllerType::LeftJoycon:
|
||||||
|
case Settings::ControllerType::RightJoycon:
|
||||||
|
ui->buttonMiscButtonsPlusGroup->setTitle(tr("Plus"));
|
||||||
|
ui->buttonShoulderButtonsButtonZLGroup->setTitle(tr("ZL"));
|
||||||
|
ui->buttonShoulderButtonsZRGroup->setTitle(tr("ZR"));
|
||||||
|
ui->buttonShoulderButtonsRGroup->setTitle(tr("R"));
|
||||||
|
ui->LStick->setTitle(tr("Left Stick"));
|
||||||
|
ui->RStick->setTitle(tr("Right Stick"));
|
||||||
|
break;
|
||||||
|
case Settings::ControllerType::GameCube:
|
||||||
|
ui->buttonMiscButtonsPlusGroup->setTitle(tr("Start / Pause"));
|
||||||
|
ui->buttonShoulderButtonsButtonZLGroup->setTitle(tr("L"));
|
||||||
|
ui->buttonShoulderButtonsZRGroup->setTitle(tr("R"));
|
||||||
|
ui->buttonShoulderButtonsRGroup->setTitle(tr("Z"));
|
||||||
|
ui->LStick->setTitle(tr("Control Stick"));
|
||||||
|
ui->RStick->setTitle(tr("C-Stick"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ConfigureInputPlayer::UpdateMappingWithDefaults() {
|
void ConfigureInputPlayer::UpdateMappingWithDefaults() {
|
||||||
if (ui->comboDevices->currentIndex() == 0) {
|
if (ui->comboDevices->currentIndex() == 0) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -143,9 +143,15 @@ private:
|
||||||
/// Hides and disables controller settings based on the current controller type.
|
/// Hides and disables controller settings based on the current controller type.
|
||||||
void UpdateControllerAvailableButtons();
|
void UpdateControllerAvailableButtons();
|
||||||
|
|
||||||
|
/// Disables controller settings based on the current controller type.
|
||||||
|
void UpdateControllerEnabledButtons();
|
||||||
|
|
||||||
/// Shows or hides motion groupboxes based on the current controller type.
|
/// Shows or hides motion groupboxes based on the current controller type.
|
||||||
void UpdateMotionButtons();
|
void UpdateMotionButtons();
|
||||||
|
|
||||||
|
/// Alters the button names based on the current controller type.
|
||||||
|
void UpdateControllerButtonNames();
|
||||||
|
|
||||||
/// Gets the default controller mapping for this device and auto configures the input to match.
|
/// Gets the default controller mapping for this device and auto configures the input to match.
|
||||||
void UpdateMappingWithDefaults();
|
void UpdateMappingWithDefaults();
|
||||||
|
|
||||||
|
|
|
@ -227,6 +227,9 @@ void PlayerControlPreview::paintEvent(QPaintEvent* event) {
|
||||||
case Settings::ControllerType::RightJoycon:
|
case Settings::ControllerType::RightJoycon:
|
||||||
DrawRightController(p, center);
|
DrawRightController(p, center);
|
||||||
break;
|
break;
|
||||||
|
case Settings::ControllerType::GameCube:
|
||||||
|
DrawGCController(p, center);
|
||||||
|
break;
|
||||||
case Settings::ControllerType::ProController:
|
case Settings::ControllerType::ProController:
|
||||||
default:
|
default:
|
||||||
DrawProController(p, center);
|
DrawProController(p, center);
|
||||||
|
|
Loading…
Reference in a new issue