|
|
@@ -21,6 +21,7 @@
|
|
|
|
|
|
namespace Service::HID {
|
|
|
constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
|
|
|
+constexpr s32 HID_TRIGGER_MAX = 0x7fff;
|
|
|
[[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff;
|
|
|
constexpr std::size_t NPAD_OFFSET = 0x9A00;
|
|
|
constexpr u32 BATTERY_FULL = 2;
|
|
|
@@ -48,6 +49,8 @@ Controller_NPad::NPadControllerType Controller_NPad::MapSettingsTypeToNPad(
|
|
|
return NPadControllerType::JoyRight;
|
|
|
case Settings::ControllerType::Handheld:
|
|
|
return NPadControllerType::Handheld;
|
|
|
+ case Settings::ControllerType::GameCube:
|
|
|
+ return NPadControllerType::GameCube;
|
|
|
default:
|
|
|
UNREACHABLE();
|
|
|
return NPadControllerType::ProController;
|
|
|
@@ -67,6 +70,8 @@ Settings::ControllerType Controller_NPad::MapNPadToSettingsType(
|
|
|
return Settings::ControllerType::RightJoycon;
|
|
|
case NPadControllerType::Handheld:
|
|
|
return Settings::ControllerType::Handheld;
|
|
|
+ case NPadControllerType::GameCube:
|
|
|
+ return Settings::ControllerType::GameCube;
|
|
|
default:
|
|
|
UNREACHABLE();
|
|
|
return Settings::ControllerType::ProController;
|
|
|
@@ -209,6 +214,13 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
|
|
|
controller.assignment_mode = NpadAssignments::Single;
|
|
|
controller.footer_type = AppletFooterUiType::JoyRightHorizontal;
|
|
|
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:
|
|
|
controller.style_set.palma.Assign(1);
|
|
|
controller.device_type.palma.Assign(1);
|
|
|
@@ -259,6 +271,7 @@ void Controller_NPad::OnInit() {
|
|
|
style.joycon_right.Assign(1);
|
|
|
style.joycon_dual.Assign(1);
|
|
|
style.fullkey.Assign(1);
|
|
|
+ style.gamecube.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& lstick_entry = npad_pad_states[controller_idx].l_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& analog_state = sticks[controller_idx];
|
|
|
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_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,
|
|
|
@@ -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.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) {
|
|
|
main_controller->common.entry_count = 16;
|
|
|
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;
|
|
|
}
|
|
|
|
|
|
+ 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;
|
|
|
|
|
|
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);
|
|
|
auto& pad_state = npad_pad_states[npad_index];
|
|
|
+ auto& trigger_state = npad_trigger_states[npad_index];
|
|
|
|
|
|
auto& main_controller =
|
|
|
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& libnx_entry =
|
|
|
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.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);
|
|
|
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:
|
|
|
pokeball_entry.connection_status.raw = 0;
|
|
|
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;
|
|
|
}
|
|
|
break;
|
|
|
+ case NPadControllerType::GameCube:
|
|
|
case NPadControllerType::Pokeball:
|
|
|
break;
|
|
|
}
|
|
|
@@ -1135,6 +1196,8 @@ bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const
|
|
|
return style.joycon_left;
|
|
|
case NPadControllerType::JoyRight:
|
|
|
return style.joycon_right;
|
|
|
+ case NPadControllerType::GameCube:
|
|
|
+ return style.gamecube;
|
|
|
case NPadControllerType::Pokeball:
|
|
|
return style.palma;
|
|
|
default:
|