summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/service')
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp1100
-rw-r--r--src/core/hle/service/hid/controllers/npad.h395
2 files changed, 605 insertions, 890 deletions
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 196876810..03cbd42f4 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -12,7 +12,6 @@
#include "common/settings.h"
#include "core/core.h"
#include "core/core_timing.h"
-#include "core/frontend/input.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/k_writable_event.h"
@@ -20,64 +19,13 @@
#include "core/hle/service/kernel_helpers.h"
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;
constexpr u32 MAX_NPAD_ID = 7;
constexpr std::size_t HANDHELD_INDEX = 8;
constexpr std::array<u32, 10> npad_id_list{
0, 1, 2, 3, 4, 5, 6, 7, NPAD_HANDHELD, NPAD_UNKNOWN,
};
-enum class JoystickId : std::size_t {
- Joystick_Left,
- Joystick_Right,
-};
-
-Controller_NPad::NPadControllerType Controller_NPad::MapSettingsTypeToNPad(
- Settings::ControllerType type) {
- switch (type) {
- case Settings::ControllerType::ProController:
- return NPadControllerType::ProController;
- case Settings::ControllerType::DualJoyconDetached:
- return NPadControllerType::JoyDual;
- case Settings::ControllerType::LeftJoycon:
- return NPadControllerType::JoyLeft;
- case Settings::ControllerType::RightJoycon:
- return NPadControllerType::JoyRight;
- case Settings::ControllerType::Handheld:
- return NPadControllerType::Handheld;
- case Settings::ControllerType::GameCube:
- return NPadControllerType::GameCube;
- default:
- UNREACHABLE();
- return NPadControllerType::ProController;
- }
-}
-
-Settings::ControllerType Controller_NPad::MapNPadToSettingsType(
- Controller_NPad::NPadControllerType type) {
- switch (type) {
- case NPadControllerType::ProController:
- return Settings::ControllerType::ProController;
- case NPadControllerType::JoyDual:
- return Settings::ControllerType::DualJoyconDetached;
- case NPadControllerType::JoyLeft:
- return Settings::ControllerType::LeftJoycon;
- case NPadControllerType::JoyRight:
- return Settings::ControllerType::RightJoycon;
- case NPadControllerType::Handheld:
- return Settings::ControllerType::Handheld;
- case NPadControllerType::GameCube:
- return Settings::ControllerType::GameCube;
- default:
- UNREACHABLE();
- return Settings::ControllerType::ProController;
- }
-}
-
std::size_t Controller_NPad::NPadIdToIndex(u32 npad_id) {
switch (npad_id) {
case 0:
@@ -143,118 +91,157 @@ bool Controller_NPad::IsNpadIdValid(u32 npad_id) {
bool Controller_NPad::IsDeviceHandleValid(const DeviceHandle& device_handle) {
return IsNpadIdValid(device_handle.npad_id) &&
- device_handle.npad_type < NpadType::MaxNpadType &&
+ device_handle.npad_type < Core::HID::NpadType::MaxNpadType &&
device_handle.device_index < DeviceIndex::MaxDeviceIndex;
}
Controller_NPad::Controller_NPad(Core::System& system_,
KernelHelpers::ServiceContext& service_context_)
: ControllerBase{system_}, service_context{service_context_} {
- latest_vibration_values.fill({DEFAULT_VIBRATION_VALUE, DEFAULT_VIBRATION_VALUE});
+ for (std::size_t i = 0; i < controller_data.size(); ++i) {
+ auto& controller = controller_data[i];
+ controller.device = system.HIDCore().GetEmulatedControllerByIndex(i);
+ controller.vibration[0].latest_vibration_value = DEFAULT_VIBRATION_VALUE;
+ controller.vibration[1].latest_vibration_value = DEFAULT_VIBRATION_VALUE;
+ Core::HID::ControllerUpdateCallback engine_callback{
+ [this, i](Core::HID::ControllerTriggerType type) { ControllerUpdate(type, i); }};
+ controller.callback_key = controller.device->SetCallback(engine_callback);
+ }
}
Controller_NPad::~Controller_NPad() {
+ for (std::size_t i = 0; i < controller_data.size(); ++i) {
+ auto& controller = controller_data[i];
+ controller.device->DeleteCallback(controller.callback_key);
+ }
OnRelease();
}
+void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type,
+ std::size_t controller_idx) {
+ if (type == Core::HID::ControllerTriggerType::All) {
+ ControllerUpdate(Core::HID::ControllerTriggerType::Type, controller_idx);
+ ControllerUpdate(Core::HID::ControllerTriggerType::Connected, controller_idx);
+ return;
+ }
+
+ switch (type) {
+ case Core::HID::ControllerTriggerType::Connected:
+ InitNewlyAddedController(controller_idx);
+ break;
+ case Core::HID::ControllerTriggerType::Disconnected:
+ DisconnectNpadAtIndex(controller_idx);
+ break;
+ case Core::HID::ControllerTriggerType::Type: {
+ auto& controller = controller_data[controller_idx];
+ if (controller.device->IsConnected()) {
+ LOG_ERROR(Service_HID, "Controller type changed without turning off the controller");
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
- const auto controller_type = connected_controllers[controller_idx].type;
- auto& controller = shared_memory_entries[controller_idx];
- if (controller_type == NPadControllerType::None) {
- styleset_changed_events[controller_idx]->GetWritableEvent().Signal();
+ auto& controller = controller_data[controller_idx];
+ const auto controller_type = controller.device->GetNpadType();
+ auto& shared_memory = controller.shared_memory_entry;
+ if (controller_type == Core::HID::NpadType::None) {
+ controller.styleset_changed_event->GetWritableEvent().Signal();
return;
}
- controller.style_set.raw = 0; // Zero out
- controller.device_type.raw = 0;
- controller.system_properties.raw = 0;
+ shared_memory.style_set.raw = 0; // Zero out
+ shared_memory.device_type.raw = 0;
+ shared_memory.system_properties.raw = 0;
switch (controller_type) {
- case NPadControllerType::None:
+ case Core::HID::NpadType::None:
UNREACHABLE();
break;
- case NPadControllerType::ProController:
- controller.style_set.fullkey.Assign(1);
- controller.device_type.fullkey.Assign(1);
- controller.system_properties.is_vertical.Assign(1);
- controller.system_properties.use_plus.Assign(1);
- controller.system_properties.use_minus.Assign(1);
- controller.assignment_mode = NpadAssignments::Single;
- controller.footer_type = AppletFooterUiType::SwitchProController;
+ case Core::HID::NpadType::ProController:
+ shared_memory.style_set.fullkey.Assign(1);
+ shared_memory.device_type.fullkey.Assign(1);
+ shared_memory.system_properties.is_vertical.Assign(1);
+ shared_memory.system_properties.use_plus.Assign(1);
+ shared_memory.system_properties.use_minus.Assign(1);
+ shared_memory.assignment_mode = NpadJoyAssignmentMode::Single;
+ shared_memory.footer_type = AppletFooterUiType::SwitchProController;
break;
- case NPadControllerType::Handheld:
- controller.style_set.handheld.Assign(1);
- controller.device_type.handheld_left.Assign(1);
- controller.device_type.handheld_right.Assign(1);
- controller.system_properties.is_vertical.Assign(1);
- controller.system_properties.use_plus.Assign(1);
- controller.system_properties.use_minus.Assign(1);
- controller.assignment_mode = NpadAssignments::Dual;
- controller.footer_type = AppletFooterUiType::HandheldJoyConLeftJoyConRight;
+ case Core::HID::NpadType::Handheld:
+ shared_memory.style_set.handheld.Assign(1);
+ shared_memory.device_type.handheld_left.Assign(1);
+ shared_memory.device_type.handheld_right.Assign(1);
+ shared_memory.system_properties.is_vertical.Assign(1);
+ shared_memory.system_properties.use_plus.Assign(1);
+ shared_memory.system_properties.use_minus.Assign(1);
+ shared_memory.assignment_mode = NpadJoyAssignmentMode::Dual;
+ shared_memory.footer_type = AppletFooterUiType::HandheldJoyConLeftJoyConRight;
break;
- case NPadControllerType::JoyDual:
- controller.style_set.joycon_dual.Assign(1);
- controller.device_type.joycon_left.Assign(1);
- controller.device_type.joycon_right.Assign(1);
- controller.system_properties.is_vertical.Assign(1);
- controller.system_properties.use_plus.Assign(1);
- controller.system_properties.use_minus.Assign(1);
- controller.assignment_mode = NpadAssignments::Dual;
- controller.footer_type = AppletFooterUiType::JoyDual;
+ case Core::HID::NpadType::JoyconDual:
+ shared_memory.style_set.joycon_dual.Assign(1);
+ shared_memory.device_type.joycon_left.Assign(1);
+ shared_memory.device_type.joycon_right.Assign(1);
+ shared_memory.system_properties.is_vertical.Assign(1);
+ shared_memory.system_properties.use_plus.Assign(1);
+ shared_memory.system_properties.use_minus.Assign(1);
+ shared_memory.assignment_mode = NpadJoyAssignmentMode::Dual;
+ shared_memory.footer_type = AppletFooterUiType::JoyDual;
break;
- case NPadControllerType::JoyLeft:
- controller.style_set.joycon_left.Assign(1);
- controller.device_type.joycon_left.Assign(1);
- controller.system_properties.is_horizontal.Assign(1);
- controller.system_properties.use_minus.Assign(1);
- controller.assignment_mode = NpadAssignments::Single;
- controller.footer_type = AppletFooterUiType::JoyLeftHorizontal;
+ case Core::HID::NpadType::JoyconLeft:
+ shared_memory.style_set.joycon_left.Assign(1);
+ shared_memory.device_type.joycon_left.Assign(1);
+ shared_memory.system_properties.is_horizontal.Assign(1);
+ shared_memory.system_properties.use_minus.Assign(1);
+ shared_memory.assignment_mode = NpadJoyAssignmentMode::Single;
+ shared_memory.footer_type = AppletFooterUiType::JoyLeftHorizontal;
break;
- case NPadControllerType::JoyRight:
- controller.style_set.joycon_right.Assign(1);
- controller.device_type.joycon_right.Assign(1);
- controller.system_properties.is_horizontal.Assign(1);
- controller.system_properties.use_plus.Assign(1);
- controller.assignment_mode = NpadAssignments::Single;
- controller.footer_type = AppletFooterUiType::JoyRightHorizontal;
+ case Core::HID::NpadType::JoyconRight:
+ shared_memory.style_set.joycon_right.Assign(1);
+ shared_memory.device_type.joycon_right.Assign(1);
+ shared_memory.system_properties.is_horizontal.Assign(1);
+ shared_memory.system_properties.use_plus.Assign(1);
+ shared_memory.assignment_mode = NpadJoyAssignmentMode::Single;
+ shared_memory.footer_type = AppletFooterUiType::JoyRightHorizontal;
break;
- case NPadControllerType::GameCube:
- controller.style_set.gamecube.Assign(1);
+ case Core::HID::NpadType::GameCube:
+ shared_memory.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);
+ shared_memory.device_type.fullkey.Assign(1);
+ shared_memory.system_properties.is_vertical.Assign(1);
+ shared_memory.system_properties.use_plus.Assign(1);
break;
- case NPadControllerType::Pokeball:
- controller.style_set.palma.Assign(1);
- controller.device_type.palma.Assign(1);
- controller.assignment_mode = NpadAssignments::Single;
+ case Core::HID::NpadType::Pokeball:
+ shared_memory.style_set.palma.Assign(1);
+ shared_memory.device_type.palma.Assign(1);
+ shared_memory.assignment_mode = NpadJoyAssignmentMode::Single;
+ break;
+ default:
break;
}
- controller.fullkey_color.attribute = ColorAttributes::Ok;
- controller.fullkey_color.fullkey.body = 0;
- controller.fullkey_color.fullkey.button = 0;
+ const auto& body_colors = controller.device->GetColors();
- controller.joycon_color.attribute = ColorAttributes::Ok;
- controller.joycon_color.left.body =
- Settings::values.players.GetValue()[controller_idx].body_color_left;
- controller.joycon_color.left.button =
- Settings::values.players.GetValue()[controller_idx].button_color_left;
- controller.joycon_color.right.body =
- Settings::values.players.GetValue()[controller_idx].body_color_right;
- controller.joycon_color.right.button =
- Settings::values.players.GetValue()[controller_idx].button_color_right;
+ shared_memory.fullkey_color.attribute = ColorAttribute::Ok;
+ shared_memory.fullkey_color.fullkey = body_colors.fullkey;
+
+ shared_memory.joycon_color.attribute = ColorAttribute::Ok;
+ shared_memory.joycon_color.left = body_colors.left;
+ shared_memory.joycon_color.right = body_colors.right;
// TODO: Investigate when we should report all batery types
- controller.battery_level_dual = BATTERY_FULL;
- controller.battery_level_left = BATTERY_FULL;
- controller.battery_level_right = BATTERY_FULL;
+ const auto& battery_level = controller.device->GetBattery();
+ shared_memory.battery_level_dual = battery_level.dual.battery_level;
+ shared_memory.battery_level_left = battery_level.left.battery_level;
+ shared_memory.battery_level_right = battery_level.right.battery_level;
SignalStyleSetChangedEvent(IndexToNPad(controller_idx));
}
void Controller_NPad::OnInit() {
- for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) {
- styleset_changed_events[i] =
+ for (std::size_t i = 0; i < controller_data.size(); ++i) {
+ auto& controller = controller_data[i];
+ controller.styleset_changed_event =
service_context.CreateEvent(fmt::format("npad:NpadStyleSetChanged_{}", i));
}
@@ -262,10 +249,9 @@ void Controller_NPad::OnInit() {
return;
}
- OnLoadInputDevices();
-
- if (style.raw == 0) {
+ if (system.HIDCore().GetSupportedStyleTag().raw == 0) {
// We want to support all controllers
+ Core::HID::NpadStyleTag style{};
style.handheld.Assign(1);
style.joycon_left.Assign(1);
style.joycon_right.Assign(1);
@@ -273,173 +259,98 @@ void Controller_NPad::OnInit() {
style.fullkey.Assign(1);
style.gamecube.Assign(1);
style.palma.Assign(1);
- }
-
- std::transform(Settings::values.players.GetValue().begin(),
- Settings::values.players.GetValue().end(), connected_controllers.begin(),
- [](const Settings::PlayerInput& player) {
- return ControllerHolder{MapSettingsTypeToNPad(player.controller_type),
- player.connected};
- });
-
- // Connect the Player 1 or Handheld controller if none are connected.
- if (std::none_of(connected_controllers.begin(), connected_controllers.end(),
- [](const ControllerHolder& controller) { return controller.is_connected; })) {
- const auto controller =
- MapSettingsTypeToNPad(Settings::values.players.GetValue()[0].controller_type);
- if (controller == NPadControllerType::Handheld) {
- Settings::values.players.GetValue()[HANDHELD_INDEX].connected = true;
- connected_controllers[HANDHELD_INDEX] = {controller, true};
- } else {
- Settings::values.players.GetValue()[0].connected = true;
- connected_controllers[0] = {controller, true};
- }
- }
-
- // Account for handheld
- if (connected_controllers[HANDHELD_INDEX].is_connected) {
- connected_controllers[HANDHELD_INDEX].type = NPadControllerType::Handheld;
+ system.HIDCore().SetSupportedStyleTag(style);
}
supported_npad_id_types.resize(npad_id_list.size());
std::memcpy(supported_npad_id_types.data(), npad_id_list.data(),
npad_id_list.size() * sizeof(u32));
- for (std::size_t i = 0; i < connected_controllers.size(); ++i) {
- const auto& controller = connected_controllers[i];
- if (controller.is_connected) {
- AddNewControllerAt(controller.type, i);
+ for (std::size_t i = 0; i < controller_data.size(); ++i) {
+ auto& controller = controller_data[i].device;
+ if (controller->IsConnected()) {
+ AddNewControllerAt(controller->GetNpadType(), i);
}
}
-}
-void Controller_NPad::OnLoadInputDevices() {
- const auto& players = Settings::values.players.GetValue();
-
- std::lock_guard lock{mutex};
- for (std::size_t i = 0; i < players.size(); ++i) {
- std::transform(players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN,
- players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_END,
- buttons[i].begin(), Input::CreateDevice<Input::ButtonDevice>);
- std::transform(players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN,
- players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_END,
- sticks[i].begin(), Input::CreateDevice<Input::AnalogDevice>);
- std::transform(players[i].vibrations.begin() +
- Settings::NativeVibration::VIBRATION_HID_BEGIN,
- players[i].vibrations.begin() + Settings::NativeVibration::VIBRATION_HID_END,
- vibrations[i].begin(), Input::CreateDevice<Input::VibrationDevice>);
- std::transform(players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN,
- players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_END,
- motions[i].begin(), Input::CreateDevice<Input::MotionDevice>);
- for (std::size_t device_idx = 0; device_idx < vibrations[i].size(); ++device_idx) {
- InitializeVibrationDeviceAtIndex(i, device_idx);
+ // Prefill controller buffers
+ for (auto& controller : controller_data) {
+ NPadGenericState dummy_pad_state{};
+ auto& npad = controller.shared_memory_entry;
+ for (std::size_t i = 0; i < 17; ++i) {
+ dummy_pad_state.sampling_number =
+ npad.fullkey_lifo.ReadCurrentEntry().sampling_number + 1;
+ npad.fullkey_lifo.WriteNextEntry(dummy_pad_state);
+ npad.handheld_lifo.WriteNextEntry(dummy_pad_state);
+ npad.joy_dual_lifo.WriteNextEntry(dummy_pad_state);
+ npad.joy_left_lifo.WriteNextEntry(dummy_pad_state);
+ npad.joy_right_lifo.WriteNextEntry(dummy_pad_state);
+ npad.joy_right_lifo.WriteNextEntry(dummy_pad_state);
+ npad.palma_lifo.WriteNextEntry(dummy_pad_state);
}
}
}
void Controller_NPad::OnRelease() {
- for (std::size_t npad_idx = 0; npad_idx < vibrations.size(); ++npad_idx) {
- for (std::size_t device_idx = 0; device_idx < vibrations[npad_idx].size(); ++device_idx) {
- VibrateControllerAtIndex(npad_idx, device_idx, {});
+ for (std::size_t i = 0; i < controller_data.size(); ++i) {
+ auto& controller = controller_data[i];
+ service_context.CloseEvent(controller.styleset_changed_event);
+ for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) {
+ VibrateControllerAtIndex(i, device_idx, {});
}
}
-
- for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) {
- service_context.CloseEvent(styleset_changed_events[i]);
- }
}
void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
std::lock_guard lock{mutex};
-
const auto controller_idx = NPadIdToIndex(npad_id);
- const auto controller_type = connected_controllers[controller_idx].type;
- if (!connected_controllers[controller_idx].is_connected) {
+ auto& controller = controller_data[controller_idx];
+ const auto controller_type = controller.device->GetNpadType();
+ if (!controller.device->IsConnected()) {
return;
}
- 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] =
- analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus();
- const auto [stick_r_x_f, stick_r_y_f] =
- analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus();
-
- using namespace Settings::NativeButton;
- if (controller_type != NPadControllerType::JoyLeft) {
- pad_state.a.Assign(button_state[A - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.b.Assign(button_state[B - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.x.Assign(button_state[X - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.y.Assign(button_state[Y - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.r_stick.Assign(button_state[RStick - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.r.Assign(button_state[R - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.zr.Assign(button_state[ZR - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.plus.Assign(button_state[Plus - BUTTON_HID_BEGIN]->GetStatus());
-
- pad_state.r_stick_right.Assign(
- analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
- ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT));
- pad_state.r_stick_left.Assign(
- analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
- ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT));
- pad_state.r_stick_up.Assign(
- analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
- ->GetAnalogDirectionStatus(Input::AnalogDirection::UP));
- pad_state.r_stick_down.Assign(
- analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
- ->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN));
- rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
- rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
+
+ auto& pad_entry = controller.npad_pad_state;
+ auto& trigger_entry = controller.npad_trigger_state;
+ const auto button_state = controller.device->GetNpadButtons();
+ const auto stick_state = controller.device->GetSticks();
+
+ using btn = Core::HID::NpadButton;
+ pad_entry.npad_buttons.raw = btn::None;
+ if (controller_type != Core::HID::NpadType::JoyconLeft) {
+ constexpr btn right_button_mask = btn::A | btn::B | btn::X | btn::Y | btn::StickR | btn::R |
+ btn::ZR | btn::Plus | btn::StickRLeft | btn::StickRUp |
+ btn::StickRRight | btn::StickRDown;
+ pad_entry.npad_buttons.raw |= button_state.raw & right_button_mask;
+ pad_entry.r_stick = stick_state.right;
}
- if (controller_type != NPadControllerType::JoyRight) {
- pad_state.d_left.Assign(button_state[DLeft - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.d_up.Assign(button_state[DUp - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.d_right.Assign(button_state[DRight - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.d_down.Assign(button_state[DDown - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.l_stick.Assign(button_state[LStick - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.l.Assign(button_state[L - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.zl.Assign(button_state[ZL - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.minus.Assign(button_state[Minus - BUTTON_HID_BEGIN]->GetStatus());
-
- pad_state.l_stick_right.Assign(
- analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]
- ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT));
- pad_state.l_stick_left.Assign(
- analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]
- ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT));
- pad_state.l_stick_up.Assign(
- analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]
- ->GetAnalogDirectionStatus(Input::AnalogDirection::UP));
- pad_state.l_stick_down.Assign(
- analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]
- ->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN));
- lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
- lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
+ if (controller_type != Core::HID::NpadType::JoyconRight) {
+ constexpr btn left_button_mask =
+ btn::Left | btn::Up | btn::Right | btn::Down | btn::StickL | btn::L | btn::ZL |
+ btn::Minus | btn::StickLLeft | btn::StickLUp | btn::StickLRight | btn::StickLDown;
+ pad_entry.npad_buttons.raw |= button_state.raw & left_button_mask;
+ pad_entry.l_stick = stick_state.left;
}
- if (controller_type == NPadControllerType::JoyLeft) {
- 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 == Core::HID::NpadType::JoyconLeft) {
+ pad_entry.npad_buttons.left_sl.Assign(button_state.left_sl);
+ pad_entry.npad_buttons.left_sr.Assign(button_state.left_sr);
}
- if (controller_type == NPadControllerType::JoyRight) {
- pad_state.right_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.right_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus());
+ if (controller_type == Core::HID::NpadType::JoyconRight) {
+ pad_entry.npad_buttons.right_sl.Assign(button_state.right_sl);
+ pad_entry.npad_buttons.right_sr.Assign(button_state.right_sr);
}
- 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());
+ if (controller_type == Core::HID::NpadType::GameCube) {
+ const auto& trigger_state = controller.device->GetTriggers();
+ trigger_entry.l_analog = trigger_state.left;
+ trigger_entry.r_analog = trigger_state.right;
+ pad_entry.npad_buttons.zl.Assign(false);
+ pad_entry.npad_buttons.zr.Assign(button_state.r);
+ pad_entry.npad_buttons.l.Assign(button_state.zl);
+ pad_entry.npad_buttons.r.Assign(button_state.zr);
}
}
@@ -448,173 +359,124 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
if (!IsControllerActivated()) {
return;
}
- for (std::size_t i = 0; i < shared_memory_entries.size(); ++i) {
- auto& npad = shared_memory_entries[i];
- const std::array<NPadGeneric*, 7> controller_npads{
- &npad.fullkey_states, &npad.handheld_states, &npad.joy_dual_states,
- &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;
-
- const auto& last_entry =
- main_controller->npad[main_controller->common.last_entry_index];
-
- main_controller->common.timestamp = core_timing.GetCPUTicks();
- main_controller->common.last_entry_index =
- (main_controller->common.last_entry_index + 1) % 17;
-
- auto& cur_entry = main_controller->npad[main_controller->common.last_entry_index];
-
- cur_entry.timestamp = last_entry.timestamp + 1;
- cur_entry.timestamp2 = cur_entry.timestamp;
- }
+ for (std::size_t i = 0; i < controller_data.size(); ++i) {
+ auto& controller = controller_data[i];
+ auto& npad = controller.shared_memory_entry;
- for (auto* analog_trigger : controller_triggers) {
- analog_trigger->entry_count = 16;
- analog_trigger->total_entry_count = 17;
+ const auto& controller_type = controller.device->GetNpadType();
- 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) {
+ if (controller_type == Core::HID::NpadType::None || !controller.device->IsConnected()) {
continue;
}
const u32 npad_index = static_cast<u32>(i);
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];
- auto& handheld_entry =
- npad.handheld_states.npad[npad.handheld_states.common.last_entry_index];
- auto& dual_entry = npad.joy_dual_states.npad[npad.joy_dual_states.common.last_entry_index];
- auto& left_entry = npad.joy_left_states.npad[npad.joy_left_states.common.last_entry_index];
- auto& right_entry =
- npad.joy_right_states.npad[npad.joy_right_states.common.last_entry_index];
- 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);
+ auto& pad_state = controller.npad_pad_state;
+ auto& libnx_state = controller.npad_libnx_state;
+ auto& trigger_state = controller.npad_trigger_state;
+ // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate
+ // any controllers.
+ libnx_state.connection_status.raw = 0;
+ libnx_state.connection_status.is_connected.Assign(1);
switch (controller_type) {
- case NPadControllerType::None:
+ case Core::HID::NpadType::None:
UNREACHABLE();
break;
- case NPadControllerType::ProController:
- 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;
-
- libnx_entry.connection_status.is_wired.Assign(1);
+ case Core::HID::NpadType::ProController:
+ pad_state.connection_status.raw = 0;
+ pad_state.connection_status.is_connected.Assign(1);
+ pad_state.connection_status.is_wired.Assign(1);
+
+ libnx_state.connection_status.is_wired.Assign(1);
+ pad_state.sampling_number =
+ npad.fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1;
+ npad.fullkey_lifo.WriteNextEntry(pad_state);
break;
- case NPadControllerType::Handheld:
- handheld_entry.connection_status.raw = 0;
- handheld_entry.connection_status.is_connected.Assign(1);
- handheld_entry.connection_status.is_wired.Assign(1);
- handheld_entry.connection_status.is_left_connected.Assign(1);
- handheld_entry.connection_status.is_right_connected.Assign(1);
- handheld_entry.connection_status.is_left_wired.Assign(1);
- handheld_entry.connection_status.is_right_wired.Assign(1);
- handheld_entry.pad.pad_states.raw = pad_state.pad_states.raw;
- handheld_entry.pad.l_stick = pad_state.l_stick;
- handheld_entry.pad.r_stick = pad_state.r_stick;
-
- libnx_entry.connection_status.is_wired.Assign(1);
- libnx_entry.connection_status.is_left_connected.Assign(1);
- libnx_entry.connection_status.is_right_connected.Assign(1);
- libnx_entry.connection_status.is_left_wired.Assign(1);
- libnx_entry.connection_status.is_right_wired.Assign(1);
+ case Core::HID::NpadType::Handheld:
+ pad_state.connection_status.raw = 0;
+ pad_state.connection_status.is_connected.Assign(1);
+ pad_state.connection_status.is_wired.Assign(1);
+ pad_state.connection_status.is_left_connected.Assign(1);
+ pad_state.connection_status.is_right_connected.Assign(1);
+ pad_state.connection_status.is_left_wired.Assign(1);
+ pad_state.connection_status.is_right_wired.Assign(1);
+
+ libnx_state.connection_status.is_wired.Assign(1);
+ libnx_state.connection_status.is_left_connected.Assign(1);
+ libnx_state.connection_status.is_right_connected.Assign(1);
+ libnx_state.connection_status.is_left_wired.Assign(1);
+ libnx_state.connection_status.is_right_wired.Assign(1);
+ pad_state.sampling_number =
+ npad.handheld_lifo.ReadCurrentEntry().state.sampling_number + 1;
+ npad.handheld_lifo.WriteNextEntry(pad_state);
break;
- case NPadControllerType::JoyDual:
- dual_entry.connection_status.raw = 0;
- dual_entry.connection_status.is_connected.Assign(1);
- dual_entry.connection_status.is_left_connected.Assign(1);
- dual_entry.connection_status.is_right_connected.Assign(1);
- dual_entry.pad.pad_states.raw = pad_state.pad_states.raw;
- dual_entry.pad.l_stick = pad_state.l_stick;
- dual_entry.pad.r_stick = pad_state.r_stick;
-
- libnx_entry.connection_status.is_left_connected.Assign(1);
- libnx_entry.connection_status.is_right_connected.Assign(1);
+ case Core::HID::NpadType::JoyconDual:
+ pad_state.connection_status.raw = 0;
+ pad_state.connection_status.is_connected.Assign(1);
+ pad_state.connection_status.is_left_connected.Assign(1);
+ pad_state.connection_status.is_right_connected.Assign(1);
+
+ libnx_state.connection_status.is_left_connected.Assign(1);
+ libnx_state.connection_status.is_right_connected.Assign(1);
+ pad_state.sampling_number =
+ npad.joy_dual_lifo.ReadCurrentEntry().state.sampling_number + 1;
+ npad.joy_dual_lifo.WriteNextEntry(pad_state);
break;
- case NPadControllerType::JoyLeft:
- left_entry.connection_status.raw = 0;
- left_entry.connection_status.is_connected.Assign(1);
- left_entry.connection_status.is_left_connected.Assign(1);
- left_entry.pad.pad_states.raw = pad_state.pad_states.raw;
- left_entry.pad.l_stick = pad_state.l_stick;
- left_entry.pad.r_stick = pad_state.r_stick;
-
- libnx_entry.connection_status.is_left_connected.Assign(1);
+ case Core::HID::NpadType::JoyconLeft:
+ pad_state.connection_status.raw = 0;
+ pad_state.connection_status.is_connected.Assign(1);
+ pad_state.connection_status.is_left_connected.Assign(1);
+
+ libnx_state.connection_status.is_left_connected.Assign(1);
+ pad_state.sampling_number =
+ npad.joy_left_lifo.ReadCurrentEntry().state.sampling_number + 1;
+ npad.joy_left_lifo.WriteNextEntry(pad_state);
break;
- case NPadControllerType::JoyRight:
- right_entry.connection_status.raw = 0;
- right_entry.connection_status.is_connected.Assign(1);
- right_entry.connection_status.is_right_connected.Assign(1);
- right_entry.pad.pad_states.raw = pad_state.pad_states.raw;
- right_entry.pad.l_stick = pad_state.l_stick;
- right_entry.pad.r_stick = pad_state.r_stick;
-
- libnx_entry.connection_status.is_right_connected.Assign(1);
+ case Core::HID::NpadType::JoyconRight:
+ pad_state.connection_status.raw = 0;
+ pad_state.connection_status.is_connected.Assign(1);
+ pad_state.connection_status.is_right_connected.Assign(1);
+
+ libnx_state.connection_status.is_right_connected.Assign(1);
+ pad_state.sampling_number =
+ npad.joy_right_lifo.ReadCurrentEntry().state.sampling_number + 1;
+ npad.joy_right_lifo.WriteNextEntry(pad_state);
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);
+ case Core::HID::NpadType::GameCube:
+ pad_state.connection_status.raw = 0;
+ pad_state.connection_status.is_connected.Assign(1);
+ pad_state.connection_status.is_wired.Assign(1);
+
+ libnx_state.connection_status.is_wired.Assign(1);
+ pad_state.sampling_number =
+ npad.fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1;
+ trigger_state.sampling_number =
+ npad.gc_trigger_lifo.ReadCurrentEntry().state.sampling_number + 1;
+ npad.fullkey_lifo.WriteNextEntry(pad_state);
+ npad.gc_trigger_lifo.WriteNextEntry(trigger_state);
break;
- case NPadControllerType::Pokeball:
- pokeball_entry.connection_status.raw = 0;
- pokeball_entry.connection_status.is_connected.Assign(1);
- pokeball_entry.pad.pad_states.raw = pad_state.pad_states.raw;
- pokeball_entry.pad.l_stick = pad_state.l_stick;
- pokeball_entry.pad.r_stick = pad_state.r_stick;
+ case Core::HID::NpadType::Pokeball:
+ pad_state.connection_status.raw = 0;
+ pad_state.connection_status.is_connected.Assign(1);
+ pad_state.sampling_number =
+ npad.palma_lifo.ReadCurrentEntry().state.sampling_number + 1;
+ npad.palma_lifo.WriteNextEntry(pad_state);
+ break;
+ default:
break;
}
- // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate
- // any controllers.
- libnx_entry.pad.pad_states.raw = pad_state.pad_states.raw;
- libnx_entry.pad.l_stick = pad_state.l_stick;
- libnx_entry.pad.r_stick = pad_state.r_stick;
+ libnx_state.npad_buttons.raw = pad_state.npad_buttons.raw;
+ libnx_state.l_stick = pad_state.l_stick;
+ libnx_state.r_stick = pad_state.r_stick;
+ npad.system_ext_lifo.WriteNextEntry(pad_state);
+
+ press_state |= static_cast<u32>(pad_state.npad_buttons.raw);
- press_state |= static_cast<u32>(pad_state.pad_states.raw);
+ std::memcpy(data + NPAD_OFFSET + (i * sizeof(NpadInternalState)),
+ &controller.shared_memory_entry, sizeof(NpadInternalState));
}
- std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(),
- shared_memory_entries.size() * sizeof(NPadEntry));
}
void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
@@ -622,145 +484,130 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing
if (!IsControllerActivated()) {
return;
}
- for (std::size_t i = 0; i < shared_memory_entries.size(); ++i) {
- auto& npad = shared_memory_entries[i];
- const auto& controller_type = connected_controllers[i].type;
-
- if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) {
- continue;
- }
+ for (std::size_t i = 0; i < controller_data.size(); ++i) {
+ auto& controller = controller_data[i];
- const std::array<SixAxisGeneric*, 6> controller_sixaxes{
- &npad.sixaxis_fullkey, &npad.sixaxis_handheld, &npad.sixaxis_dual_left,
- &npad.sixaxis_dual_right, &npad.sixaxis_left, &npad.sixaxis_right,
- };
+ const auto& controller_type = controller.device->GetNpadType();
- for (auto* sixaxis_sensor : controller_sixaxes) {
- sixaxis_sensor->common.entry_count = 16;
- sixaxis_sensor->common.total_entry_count = 17;
-
- const auto& last_entry =
- sixaxis_sensor->sixaxis[sixaxis_sensor->common.last_entry_index];
-
- sixaxis_sensor->common.timestamp = core_timing.GetCPUTicks();
- sixaxis_sensor->common.last_entry_index =
- (sixaxis_sensor->common.last_entry_index + 1) % 17;
-
- auto& cur_entry = sixaxis_sensor->sixaxis[sixaxis_sensor->common.last_entry_index];
-
- cur_entry.timestamp = last_entry.timestamp + 1;
- cur_entry.timestamp2 = cur_entry.timestamp;
+ if (controller_type == Core::HID::NpadType::None || !controller.device->IsConnected()) {
+ continue;
}
- // Try to read sixaxis sensor states
- std::array<MotionDevice, 2> motion_devices;
+ auto& npad = controller.shared_memory_entry;
+ const auto& motion_state = controller.device->GetMotions();
+ auto& sixaxis_fullkey_state = controller.sixaxis_fullkey_state;
+ auto& sixaxis_handheld_state = controller.sixaxis_handheld_state;
+ auto& sixaxis_dual_left_state = controller.sixaxis_dual_left_state;
+ auto& sixaxis_dual_right_state = controller.sixaxis_dual_right_state;
+ auto& sixaxis_left_lifo_state = controller.sixaxis_left_lifo_state;
+ auto& sixaxis_right_lifo_state = controller.sixaxis_right_lifo_state;
if (sixaxis_sensors_enabled && Settings::values.motion_enabled.GetValue()) {
sixaxis_at_rest = true;
- for (std::size_t e = 0; e < motion_devices.size(); ++e) {
- const auto& device = motions[i][e];
- if (device) {
- std::tie(motion_devices[e].accel, motion_devices[e].gyro,
- motion_devices[e].rotation, motion_devices[e].orientation,
- motion_devices[e].quaternion) = device->GetStatus();
- sixaxis_at_rest = sixaxis_at_rest && motion_devices[e].gyro.Length2() < 0.0001f;
- }
+ for (std::size_t e = 0; e < motion_state.size(); ++e) {
+ sixaxis_at_rest = sixaxis_at_rest && motion_state[e].is_at_rest;
}
}
- auto& full_sixaxis_entry =
- npad.sixaxis_fullkey.sixaxis[npad.sixaxis_fullkey.common.last_entry_index];
- auto& handheld_sixaxis_entry =
- npad.sixaxis_handheld.sixaxis[npad.sixaxis_handheld.common.last_entry_index];
- auto& dual_left_sixaxis_entry =
- npad.sixaxis_dual_left.sixaxis[npad.sixaxis_dual_left.common.last_entry_index];
- auto& dual_right_sixaxis_entry =
- npad.sixaxis_dual_right.sixaxis[npad.sixaxis_dual_right.common.last_entry_index];
- auto& left_sixaxis_entry =
- npad.sixaxis_left.sixaxis[npad.sixaxis_left.common.last_entry_index];
- auto& right_sixaxis_entry =
- npad.sixaxis_right.sixaxis[npad.sixaxis_right.common.last_entry_index];
-
switch (controller_type) {
- case NPadControllerType::None:
+ case Core::HID::NpadType::None:
UNREACHABLE();
break;
- case NPadControllerType::ProController:
- full_sixaxis_entry.attribute.raw = 0;
- if (sixaxis_sensors_enabled && motions[i][0]) {
- full_sixaxis_entry.attribute.is_connected.Assign(1);
- full_sixaxis_entry.accel = motion_devices[0].accel;
- full_sixaxis_entry.gyro = motion_devices[0].gyro;
- full_sixaxis_entry.rotation = motion_devices[0].rotation;
- full_sixaxis_entry.orientation = motion_devices[0].orientation;
+ case Core::HID::NpadType::ProController:
+ sixaxis_fullkey_state.attribute.raw = 0;
+ if (sixaxis_sensors_enabled) {
+ sixaxis_fullkey_state.attribute.is_connected.Assign(1);
+ sixaxis_fullkey_state.accel = motion_state[0].accel;
+ sixaxis_fullkey_state.gyro = motion_state[0].gyro;
+ sixaxis_fullkey_state.rotation = motion_state[0].rotation;
+ sixaxis_fullkey_state.orientation = motion_state[0].orientation;
}
break;
- case NPadControllerType::Handheld:
- handheld_sixaxis_entry.attribute.raw = 0;
- if (sixaxis_sensors_enabled && motions[i][0]) {
- handheld_sixaxis_entry.attribute.is_connected.Assign(1);
- handheld_sixaxis_entry.accel = motion_devices[0].accel;
- handheld_sixaxis_entry.gyro = motion_devices[0].gyro;
- handheld_sixaxis_entry.rotation = motion_devices[0].rotation;
- handheld_sixaxis_entry.orientation = motion_devices[0].orientation;
+ case Core::HID::NpadType::Handheld:
+ sixaxis_handheld_state.attribute.raw = 0;
+ if (sixaxis_sensors_enabled) {
+ sixaxis_handheld_state.attribute.is_connected.Assign(1);
+ sixaxis_handheld_state.accel = motion_state[0].accel;
+ sixaxis_handheld_state.gyro = motion_state[0].gyro;
+ sixaxis_handheld_state.rotation = motion_state[0].rotation;
+ sixaxis_handheld_state.orientation = motion_state[0].orientation;
}
break;
- case NPadControllerType::JoyDual:
- dual_left_sixaxis_entry.attribute.raw = 0;
- dual_right_sixaxis_entry.attribute.raw = 0;
- if (sixaxis_sensors_enabled && motions[i][0]) {
+ case Core::HID::NpadType::JoyconDual:
+ sixaxis_dual_left_state.attribute.raw = 0;
+ sixaxis_dual_right_state.attribute.raw = 0;
+ if (sixaxis_sensors_enabled) {
// Set motion for the left joycon
- dual_left_sixaxis_entry.attribute.is_connected.Assign(1);
- dual_left_sixaxis_entry.accel = motion_devices[0].accel;
- dual_left_sixaxis_entry.gyro = motion_devices[0].gyro;
- dual_left_sixaxis_entry.rotation = motion_devices[0].rotation;
- dual_left_sixaxis_entry.orientation = motion_devices[0].orientation;
+ sixaxis_dual_left_state.attribute.is_connected.Assign(1);
+ sixaxis_dual_left_state.accel = motion_state[0].accel;
+ sixaxis_dual_left_state.gyro = motion_state[0].gyro;
+ sixaxis_dual_left_state.rotation = motion_state[0].rotation;
+ sixaxis_dual_left_state.orientation = motion_state[0].orientation;
}
- if (sixaxis_sensors_enabled && motions[i][1]) {
+ if (sixaxis_sensors_enabled) {
// Set motion for the right joycon
- dual_right_sixaxis_entry.attribute.is_connected.Assign(1);
- dual_right_sixaxis_entry.accel = motion_devices[1].accel;
- dual_right_sixaxis_entry.gyro = motion_devices[1].gyro;
- dual_right_sixaxis_entry.rotation = motion_devices[1].rotation;
- dual_right_sixaxis_entry.orientation = motion_devices[1].orientation;
+ sixaxis_dual_right_state.attribute.is_connected.Assign(1);
+ sixaxis_dual_right_state.accel = motion_state[1].accel;
+ sixaxis_dual_right_state.gyro = motion_state[1].gyro;
+ sixaxis_dual_right_state.rotation = motion_state[1].rotation;
+ sixaxis_dual_right_state.orientation = motion_state[1].orientation;
}
break;
- case NPadControllerType::JoyLeft:
- left_sixaxis_entry.attribute.raw = 0;
- if (sixaxis_sensors_enabled && motions[i][0]) {
- left_sixaxis_entry.attribute.is_connected.Assign(1);
- left_sixaxis_entry.accel = motion_devices[0].accel;
- left_sixaxis_entry.gyro = motion_devices[0].gyro;
- left_sixaxis_entry.rotation = motion_devices[0].rotation;
- left_sixaxis_entry.orientation = motion_devices[0].orientation;
+ case Core::HID::NpadType::JoyconLeft:
+ sixaxis_left_lifo_state.attribute.raw = 0;
+ if (sixaxis_sensors_enabled) {
+ sixaxis_left_lifo_state.attribute.is_connected.Assign(1);
+ sixaxis_left_lifo_state.accel = motion_state[0].accel;
+ sixaxis_left_lifo_state.gyro = motion_state[0].gyro;
+ sixaxis_left_lifo_state.rotation = motion_state[0].rotation;
+ sixaxis_left_lifo_state.orientation = motion_state[0].orientation;
}
break;
- case NPadControllerType::JoyRight:
- right_sixaxis_entry.attribute.raw = 0;
- if (sixaxis_sensors_enabled && motions[i][1]) {
- right_sixaxis_entry.attribute.is_connected.Assign(1);
- right_sixaxis_entry.accel = motion_devices[1].accel;
- right_sixaxis_entry.gyro = motion_devices[1].gyro;
- right_sixaxis_entry.rotation = motion_devices[1].rotation;
- right_sixaxis_entry.orientation = motion_devices[1].orientation;
+ case Core::HID::NpadType::JoyconRight:
+ sixaxis_right_lifo_state.attribute.raw = 0;
+ if (sixaxis_sensors_enabled) {
+ sixaxis_right_lifo_state.attribute.is_connected.Assign(1);
+ sixaxis_right_lifo_state.accel = motion_state[1].accel;
+ sixaxis_right_lifo_state.gyro = motion_state[1].gyro;
+ sixaxis_right_lifo_state.rotation = motion_state[1].rotation;
+ sixaxis_right_lifo_state.orientation = motion_state[1].orientation;
}
break;
- case NPadControllerType::GameCube:
- case NPadControllerType::Pokeball:
+ default:
break;
}
+
+ sixaxis_fullkey_state.sampling_number =
+ npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1;
+ sixaxis_handheld_state.sampling_number =
+ npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1;
+ sixaxis_dual_left_state.sampling_number =
+ npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1;
+ sixaxis_dual_right_state.sampling_number =
+ npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1;
+ sixaxis_left_lifo_state.sampling_number =
+ npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1;
+ sixaxis_right_lifo_state.sampling_number =
+ npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1;
+
+ npad.sixaxis_fullkey_lifo.WriteNextEntry(sixaxis_fullkey_state);
+ npad.sixaxis_handheld_lifo.WriteNextEntry(sixaxis_handheld_state);
+ npad.sixaxis_dual_left_lifo.WriteNextEntry(sixaxis_dual_left_state);
+ npad.sixaxis_dual_right_lifo.WriteNextEntry(sixaxis_dual_right_state);
+ npad.sixaxis_left_lifo.WriteNextEntry(sixaxis_left_lifo_state);
+ npad.sixaxis_right_lifo.WriteNextEntry(sixaxis_right_lifo_state);
+ std::memcpy(data + NPAD_OFFSET + (i * sizeof(NpadInternalState)),
+ &controller.shared_memory_entry, sizeof(NpadInternalState));
}
- std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(),
- shared_memory_entries.size() * sizeof(NPadEntry));
}
-void Controller_NPad::SetSupportedStyleSet(NpadStyleSet style_set) {
- style.raw = style_set.raw;
+void Controller_NPad::SetSupportedStyleSet(Core::HID::NpadStyleTag style_set) {
+ system.HIDCore().SetSupportedStyleTag(style_set);
}
-Controller_NPad::NpadStyleSet Controller_NPad::GetSupportedStyleSet() const {
- return style;
+Core::HID::NpadStyleTag Controller_NPad::GetSupportedStyleSet() const {
+ return system.HIDCore().GetSupportedStyleTag();
}
void Controller_NPad::SetSupportedNpadIdTypes(u8* data, std::size_t length) {
@@ -779,11 +626,11 @@ std::size_t Controller_NPad::GetSupportedNpadIdTypesSize() const {
return supported_npad_id_types.size();
}
-void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) {
+void Controller_NPad::SetHoldType(NpadJoyHoldType joy_hold_type) {
hold_type = joy_hold_type;
}
-Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const {
+Controller_NPad::NpadJoyHoldType Controller_NPad::GetHoldType() const {
return hold_type;
}
@@ -803,29 +650,31 @@ Controller_NPad::NpadCommunicationMode Controller_NPad::GetNpadCommunicationMode
return communication_mode;
}
-void Controller_NPad::SetNpadMode(u32 npad_id, NpadAssignments assignment_mode) {
+void Controller_NPad::SetNpadMode(u32 npad_id, NpadJoyAssignmentMode assignment_mode) {
const std::size_t npad_index = NPadIdToIndex(npad_id);
- ASSERT(npad_index < shared_memory_entries.size());
- if (shared_memory_entries[npad_index].assignment_mode != assignment_mode) {
- shared_memory_entries[npad_index].assignment_mode = assignment_mode;
+ ASSERT(npad_index < controller_data.size());
+ auto& controller = controller_data[npad_index];
+ if (controller.shared_memory_entry.assignment_mode != assignment_mode) {
+ controller.shared_memory_entry.assignment_mode = assignment_mode;
}
}
bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index, std::size_t device_index,
const VibrationValue& vibration_value) {
- if (!connected_controllers[npad_index].is_connected || !vibrations[npad_index][device_index]) {
+ auto& controller = controller_data[npad_index];
+
+ if (!controller.device->IsConnected()) {
return false;
}
- const auto& player = Settings::values.players.GetValue()[npad_index];
-
- if (!player.vibration_enabled) {
- if (latest_vibration_values[npad_index][device_index].amp_low != 0.0f ||
- latest_vibration_values[npad_index][device_index].amp_high != 0.0f) {
+ if (!controller.device->IsVibrationEnabled()) {
+ if (controller.vibration[device_index].latest_vibration_value.amp_low != 0.0f ||
+ controller.vibration[device_index].latest_vibration_value.amp_high != 0.0f) {
// Send an empty vibration to stop any vibrations.
- vibrations[npad_index][device_index]->SetRumblePlay(0.0f, 160.0f, 0.0f, 320.0f);
+ Core::HID::VibrationValue vibration{0.0f, 160.0f, 0.0f, 320.0f};
+ controller.device->SetVibration(device_index, vibration);
// Then reset the vibration value to its default value.
- latest_vibration_values[npad_index][device_index] = DEFAULT_VIBRATION_VALUE;
+ controller.vibration[device_index].latest_vibration_value = DEFAULT_VIBRATION_VALUE;
}
return false;
@@ -840,22 +689,18 @@ bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index, std::size
// Filter out non-zero vibrations that are within 10ms of each other.
if ((vibration_value.amp_low != 0.0f || vibration_value.amp_high != 0.0f) &&
- duration_cast<milliseconds>(now - last_vibration_timepoints[npad_index][device_index]) <
+ duration_cast<milliseconds>(
+ now - controller.vibration[device_index].last_vibration_timepoint) <
milliseconds(10)) {
return false;
}
- last_vibration_timepoints[npad_index][device_index] = now;
+ controller.vibration[device_index].last_vibration_timepoint = now;
}
- auto& vibration = vibrations[npad_index][device_index];
- const auto player_vibration_strength = static_cast<f32>(player.vibration_strength);
- const auto amp_low =
- std::min(vibration_value.amp_low * player_vibration_strength / 100.0f, 1.0f);
- const auto amp_high =
- std::min(vibration_value.amp_high * player_vibration_strength / 100.0f, 1.0f);
- return vibration->SetRumblePlay(amp_low, vibration_value.freq_low, amp_high,
- vibration_value.freq_high);
+ Core::HID::VibrationValue vibration{vibration_value.amp_low, vibration_value.freq_low,
+ vibration_value.amp_high, vibration_value.freq_high};
+ return controller.device->SetVibration(device_index, vibration);
}
void Controller_NPad::VibrateController(const DeviceHandle& vibration_device_handle,
@@ -869,10 +714,10 @@ void Controller_NPad::VibrateController(const DeviceHandle& vibration_device_han
}
const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id);
+ auto& controller = controller_data[npad_index];
const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
- if (!vibration_devices_mounted[npad_index][device_index] ||
- !connected_controllers[npad_index].is_connected) {
+ if (!controller.vibration[device_index].device_mounted || !controller.device->IsConnected()) {
return;
}
@@ -882,23 +727,25 @@ void Controller_NPad::VibrateController(const DeviceHandle& vibration_device_han
}
// Some games try to send mismatched parameters in the device handle, block these.
- if ((connected_controllers[npad_index].type == NPadControllerType::JoyLeft &&
- (vibration_device_handle.npad_type == NpadType::JoyconRight ||
+ if ((controller.device->GetNpadType() == Core::HID::NpadType::JoyconLeft &&
+ (vibration_device_handle.npad_type == Core::HID::NpadType::JoyconRight ||
vibration_device_handle.device_index == DeviceIndex::Right)) ||
- (connected_controllers[npad_index].type == NPadControllerType::JoyRight &&
- (vibration_device_handle.npad_type == NpadType::JoyconLeft ||
+ (controller.device->GetNpadType() == Core::HID::NpadType::JoyconRight &&
+ (vibration_device_handle.npad_type == Core::HID::NpadType::JoyconLeft ||
vibration_device_handle.device_index == DeviceIndex::Left))) {
return;
}
// Filter out vibrations with equivalent values to reduce unnecessary state changes.
- if (vibration_value.amp_low == latest_vibration_values[npad_index][device_index].amp_low &&
- vibration_value.amp_high == latest_vibration_values[npad_index][device_index].amp_high) {
+ if (vibration_value.amp_low ==
+ controller.vibration[device_index].latest_vibration_value.amp_low &&
+ vibration_value.amp_high ==
+ controller.vibration[device_index].latest_vibration_value.amp_high) {
return;
}
if (VibrateControllerAtIndex(npad_index, device_index, vibration_value)) {
- latest_vibration_values[npad_index][device_index] = vibration_value;
+ controller.vibration[device_index].latest_vibration_value = vibration_value;
}
}
@@ -925,8 +772,9 @@ Controller_NPad::VibrationValue Controller_NPad::GetLastVibration(
}
const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id);
+ const auto& controller = controller_data[npad_index];
const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
- return latest_vibration_values[npad_index][device_index];
+ return controller.vibration[device_index].latest_vibration_value;
}
void Controller_NPad::InitializeVibrationDevice(const DeviceHandle& vibration_device_handle) {
@@ -941,17 +789,14 @@ void Controller_NPad::InitializeVibrationDevice(const DeviceHandle& vibration_de
void Controller_NPad::InitializeVibrationDeviceAtIndex(std::size_t npad_index,
std::size_t device_index) {
+ auto& controller = controller_data[npad_index];
if (!Settings::values.vibration_enabled.GetValue()) {
- vibration_devices_mounted[npad_index][device_index] = false;
+ controller.vibration[device_index].device_mounted = false;
return;
}
- if (vibrations[npad_index][device_index]) {
- vibration_devices_mounted[npad_index][device_index] =
- vibrations[npad_index][device_index]->GetStatus() == 1;
- } else {
- vibration_devices_mounted[npad_index][device_index] = false;
- }
+ controller.vibration[device_index].device_mounted =
+ controller.device->TestVibration(device_index) == 1;
}
void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) {
@@ -964,42 +809,35 @@ bool Controller_NPad::IsVibrationDeviceMounted(const DeviceHandle& vibration_dev
}
const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id);
+ const auto& controller = controller_data[npad_index];
const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
- return vibration_devices_mounted[npad_index][device_index];
+ return controller.vibration[device_index].device_mounted;
}
Kernel::KReadableEvent& Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) {
- return styleset_changed_events[NPadIdToIndex(npad_id)]->GetReadableEvent();
+ const auto& controller = controller_data[NPadIdToIndex(npad_id)];
+ return controller.styleset_changed_event->GetReadableEvent();
}
void Controller_NPad::SignalStyleSetChangedEvent(u32 npad_id) const {
- styleset_changed_events[NPadIdToIndex(npad_id)]->GetWritableEvent().Signal();
+ const auto& controller = controller_data[NPadIdToIndex(npad_id)];
+ controller.styleset_changed_event->GetWritableEvent().Signal();
}
-void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::size_t npad_index) {
+void Controller_NPad::AddNewControllerAt(Core::HID::NpadType controller, std::size_t npad_index) {
UpdateControllerAt(controller, npad_index, true);
}
-void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::size_t npad_index,
+void Controller_NPad::UpdateControllerAt(Core::HID::NpadType type, std::size_t npad_index,
bool connected) {
+ auto& controller = controller_data[npad_index].device;
if (!connected) {
DisconnectNpadAtIndex(npad_index);
return;
}
- if (controller == NPadControllerType::Handheld && npad_index == HANDHELD_INDEX) {
- Settings::values.players.GetValue()[HANDHELD_INDEX].controller_type =
- MapNPadToSettingsType(controller);
- Settings::values.players.GetValue()[HANDHELD_INDEX].connected = true;
- connected_controllers[HANDHELD_INDEX] = {controller, true};
- InitNewlyAddedController(HANDHELD_INDEX);
- return;
- }
-
- Settings::values.players.GetValue()[npad_index].controller_type =
- MapNPadToSettingsType(controller);
- Settings::values.players.GetValue()[npad_index].connected = true;
- connected_controllers[npad_index] = {controller, true};
+ controller->SetNpadType(type);
+ controller->Connect();
InitNewlyAddedController(npad_index);
}
@@ -1008,27 +846,27 @@ void Controller_NPad::DisconnectNpad(u32 npad_id) {
}
void Controller_NPad::DisconnectNpadAtIndex(std::size_t npad_index) {
- for (std::size_t device_idx = 0; device_idx < vibrations[npad_index].size(); ++device_idx) {
+ auto& controller = controller_data[npad_index];
+ for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) {
// Send an empty vibration to stop any vibrations.
VibrateControllerAtIndex(npad_index, device_idx, {});
- vibration_devices_mounted[npad_index][device_idx] = false;
+ controller.vibration[device_idx].device_mounted = false;
}
- Settings::values.players.GetValue()[npad_index].connected = false;
- connected_controllers[npad_index].is_connected = false;
-
- auto& controller = shared_memory_entries[npad_index];
- controller.style_set.raw = 0; // Zero out
- controller.device_type.raw = 0;
- controller.system_properties.raw = 0;
- controller.button_properties.raw = 0;
- controller.battery_level_dual = 0;
- controller.battery_level_left = 0;
- controller.battery_level_right = 0;
- controller.fullkey_color = {};
- controller.joycon_color = {};
- controller.assignment_mode = NpadAssignments::Dual;
- controller.footer_type = AppletFooterUiType::None;
+ controller.device->Disconnect();
+
+ auto& shared_memory_entry = controller.shared_memory_entry;
+ shared_memory_entry.style_set.raw = 0; // Zero out
+ shared_memory_entry.device_type.raw = 0;
+ shared_memory_entry.system_properties.raw = 0;
+ shared_memory_entry.button_properties.raw = 0;
+ shared_memory_entry.battery_level_dual = 0;
+ shared_memory_entry.battery_level_left = 0;
+ shared_memory_entry.battery_level_right = 0;
+ shared_memory_entry.fullkey_color = {};
+ shared_memory_entry.joycon_color = {};
+ shared_memory_entry.assignment_mode = NpadJoyAssignmentMode::Dual;
+ shared_memory_entry.footer_type = AppletFooterUiType::None;
SignalStyleSetChangedEvent(IndexToNPad(npad_index));
}
@@ -1069,16 +907,18 @@ void Controller_NPad::ResetSixAxisFusionParameters() {
void Controller_NPad::MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2) {
const auto npad_index_1 = NPadIdToIndex(npad_id_1);
const auto npad_index_2 = NPadIdToIndex(npad_id_2);
+ const auto& controller_1 = controller_data[npad_index_1].device;
+ const auto& controller_2 = controller_data[npad_index_2].device;
// If the controllers at both npad indices form a pair of left and right joycons, merge them.
// Otherwise, do nothing.
- if ((connected_controllers[npad_index_1].type == NPadControllerType::JoyLeft &&
- connected_controllers[npad_index_2].type == NPadControllerType::JoyRight) ||
- (connected_controllers[npad_index_2].type == NPadControllerType::JoyLeft &&
- connected_controllers[npad_index_1].type == NPadControllerType::JoyRight)) {
+ if ((controller_1->GetNpadType() == Core::HID::NpadType::JoyconLeft &&
+ controller_2->GetNpadType() == Core::HID::NpadType::JoyconRight) ||
+ (controller_2->GetNpadType() == Core::HID::NpadType::JoyconLeft &&
+ controller_1->GetNpadType() == Core::HID::NpadType::JoyconRight)) {
// Disconnect the joycon at the second id and connect the dual joycon at the first index.
DisconnectNpad(npad_id_2);
- AddNewControllerAt(NPadControllerType::JoyDual, npad_index_1);
+ AddNewControllerAt(Core::HID::NpadType::JoyconDual, npad_index_1);
}
}
@@ -1099,16 +939,17 @@ bool Controller_NPad::SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2) {
}
const auto npad_index_1 = NPadIdToIndex(npad_id_1);
const auto npad_index_2 = NPadIdToIndex(npad_id_2);
+ const auto& controller_1 = controller_data[npad_index_1].device;
+ const auto& controller_2 = controller_data[npad_index_2].device;
+ const auto type_index_1 = controller_1->GetNpadType();
+ const auto type_index_2 = controller_2->GetNpadType();
- if (!IsControllerSupported(connected_controllers[npad_index_1].type) ||
- !IsControllerSupported(connected_controllers[npad_index_2].type)) {
+ if (!IsControllerSupported(type_index_1) || !IsControllerSupported(type_index_2)) {
return false;
}
- std::swap(connected_controllers[npad_index_1].type, connected_controllers[npad_index_2].type);
-
- AddNewControllerAt(connected_controllers[npad_index_1].type, npad_index_1);
- AddNewControllerAt(connected_controllers[npad_index_2].type, npad_index_2);
+ AddNewControllerAt(type_index_2, npad_index_1);
+ AddNewControllerAt(type_index_1, npad_index_2);
return true;
}
@@ -1141,12 +982,14 @@ Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) {
}
bool Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const {
- return unintended_home_button_input_protection[NPadIdToIndex(npad_id)];
+ auto& controller = controller_data[NPadIdToIndex(npad_id)];
+ return controller.unintended_home_button_input_protection;
}
void Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled,
u32 npad_id) {
- unintended_home_button_input_protection[NPadIdToIndex(npad_id)] = is_protection_enabled;
+ auto& controller = controller_data[NPadIdToIndex(npad_id)];
+ controller.unintended_home_button_input_protection = is_protection_enabled;
}
void Controller_NPad::SetAnalogStickUseCenterClamp(bool use_center_clamp) {
@@ -1154,32 +997,34 @@ void Controller_NPad::SetAnalogStickUseCenterClamp(bool use_center_clamp) {
}
void Controller_NPad::ClearAllConnectedControllers() {
- for (auto& controller : connected_controllers) {
- if (controller.is_connected && controller.type != NPadControllerType::None) {
- controller.type = NPadControllerType::None;
- controller.is_connected = false;
+ for (auto& controller : controller_data) {
+ if (controller.device->IsConnected() &&
+ controller.device->GetNpadType() != Core::HID::NpadType::None) {
+ controller.device->SetNpadType(Core::HID::NpadType::None);
+ controller.device->Disconnect();
}
}
}
void Controller_NPad::DisconnectAllConnectedControllers() {
- for (auto& controller : connected_controllers) {
- controller.is_connected = false;
+ for (auto& controller : controller_data) {
+ controller.device->Disconnect();
}
}
void Controller_NPad::ConnectAllDisconnectedControllers() {
- for (auto& controller : connected_controllers) {
- if (controller.type != NPadControllerType::None && !controller.is_connected) {
- controller.is_connected = true;
+ for (auto& controller : controller_data) {
+ if (controller.device->GetNpadType() != Core::HID::NpadType::None &&
+ !controller.device->IsConnected()) {
+ controller.device->Connect();
}
}
}
void Controller_NPad::ClearAllControllers() {
- for (auto& controller : connected_controllers) {
- controller.type = NPadControllerType::None;
- controller.is_connected = false;
+ for (auto& controller : controller_data) {
+ controller.device->SetNpadType(Core::HID::NpadType::None);
+ controller.device->Disconnect();
}
}
@@ -1187,8 +1032,8 @@ u32 Controller_NPad::GetAndResetPressState() {
return press_state.exchange(0);
}
-bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const {
- if (controller == NPadControllerType::Handheld) {
+bool Controller_NPad::IsControllerSupported(Core::HID::NpadType controller) const {
+ if (controller == Core::HID::NpadType::Handheld) {
const bool support_handheld =
std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(),
NPAD_HANDHELD) != supported_npad_id_types.end();
@@ -1196,7 +1041,7 @@ bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const
if (!support_handheld) {
return false;
}
- // Handheld should not be supported in docked mode
+ // Handheld shouldn't be supported in docked mode
if (Settings::values.use_docked_mode.GetValue()) {
return false;
}
@@ -1206,18 +1051,19 @@ bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const
if (std::any_of(supported_npad_id_types.begin(), supported_npad_id_types.end(),
[](u32 npad_id) { return npad_id <= MAX_NPAD_ID; })) {
+ Core::HID::NpadStyleTag style = GetSupportedStyleSet();
switch (controller) {
- case NPadControllerType::ProController:
+ case Core::HID::NpadType::ProController:
return style.fullkey;
- case NPadControllerType::JoyDual:
+ case Core::HID::NpadType::JoyconDual:
return style.joycon_dual;
- case NPadControllerType::JoyLeft:
+ case Core::HID::NpadType::JoyconLeft:
return style.joycon_left;
- case NPadControllerType::JoyRight:
+ case Core::HID::NpadType::JoyconRight:
return style.joycon_right;
- case NPadControllerType::GameCube:
+ case Core::HID::NpadType::GameCube:
return style.gamecube;
- case NPadControllerType::Pokeball:
+ case Core::HID::NpadType::Pokeball:
return style.palma;
default:
return false;
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index f3e868bdb..483cae5b6 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -12,8 +12,10 @@
#include "common/common_types.h"
#include "common/quaternion.h"
#include "common/settings.h"
-#include "core/frontend/input.h"
+#include "core/hid/hid_core.h"
+#include "core/hid/hid_types.h"
#include "core/hle/service/hid/controllers/controller_base.h"
+#include "core/hle/service/hid/ring_lifo.h"
namespace Kernel {
class KEvent;
@@ -48,31 +50,6 @@ public:
void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
std::size_t size) override;
- // Called when input devices should be loaded
- void OnLoadInputDevices() override;
-
- enum class NPadControllerType {
- None,
- ProController,
- Handheld,
- JoyDual,
- JoyLeft,
- JoyRight,
- GameCube,
- Pokeball,
- };
-
- enum class NpadType : u8 {
- ProController = 3,
- Handheld = 4,
- JoyconDual = 5,
- JoyconLeft = 6,
- JoyconRight = 7,
- GameCube = 8,
- Pokeball = 9,
- MaxNpadType = 10,
- };
-
enum class DeviceIndex : u8 {
Left = 0,
Right = 1,
@@ -80,28 +57,33 @@ public:
MaxDeviceIndex = 3,
};
+ // This is nn::hid::GyroscopeZeroDriftMode
enum class GyroscopeZeroDriftMode : u32 {
Loose = 0,
Standard = 1,
Tight = 2,
};
- enum class NpadHoldType : u64 {
+ // This is nn::hid::NpadJoyHoldType
+ enum class NpadJoyHoldType : u64 {
Vertical = 0,
Horizontal = 1,
};
- enum class NpadAssignments : u32 {
+ // This is nn::hid::NpadJoyAssignmentMode
+ enum class NpadJoyAssignmentMode : u32 {
Dual = 0,
Single = 1,
};
+ // This is nn::hid::NpadHandheldActivationMode
enum class NpadHandheldActivationMode : u64 {
Dual = 0,
Single = 1,
None = 2,
};
+ // This is nn::hid::NpadCommunicationMode
enum class NpadCommunicationMode : u64 {
Mode_5ms = 0,
Mode_10ms = 1,
@@ -110,33 +92,14 @@ public:
};
struct DeviceHandle {
- NpadType npad_type;
+ Core::HID::NpadType npad_type;
u8 npad_id;
DeviceIndex device_index;
INSERT_PADDING_BYTES_NOINIT(1);
};
static_assert(sizeof(DeviceHandle) == 4, "DeviceHandle is an invalid size");
- struct NpadStyleSet {
- union {
- u32_le raw{};
-
- BitField<0, 1, u32> fullkey;
- BitField<1, 1, u32> handheld;
- BitField<2, 1, u32> joycon_dual;
- BitField<3, 1, u32> joycon_left;
- BitField<4, 1, u32> joycon_right;
- BitField<5, 1, u32> gamecube;
- BitField<6, 1, u32> palma;
- BitField<7, 1, u32> lark;
- BitField<8, 1, u32> handheld_lark;
- BitField<9, 1, u32> lucia;
- BitField<29, 1, u32> system_ext;
- BitField<30, 1, u32> system;
- };
- };
- static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size");
-
+ // This is nn::hid::VibrationValue
struct VibrationValue {
f32 amp_low;
f32 freq_low;
@@ -168,15 +131,15 @@ public:
};
};
- void SetSupportedStyleSet(NpadStyleSet style_set);
- NpadStyleSet GetSupportedStyleSet() const;
+ void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set);
+ Core::HID::NpadStyleTag GetSupportedStyleSet() const;
void SetSupportedNpadIdTypes(u8* data, std::size_t length);
void GetSupportedNpadIdTypes(u32* data, std::size_t max_length);
std::size_t GetSupportedNpadIdTypesSize() const;
- void SetHoldType(NpadHoldType joy_hold_type);
- NpadHoldType GetHoldType() const;
+ void SetHoldType(NpadJoyHoldType joy_hold_type);
+ NpadJoyHoldType GetHoldType() const;
void SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode);
NpadHandheldActivationMode GetNpadHandheldActivationMode() const;
@@ -184,7 +147,7 @@ public:
void SetNpadCommunicationMode(NpadCommunicationMode communication_mode_);
NpadCommunicationMode GetNpadCommunicationMode() const;
- void SetNpadMode(u32 npad_id, NpadAssignments assignment_mode);
+ void SetNpadMode(u32 npad_id, NpadJoyAssignmentMode assignment_mode);
bool VibrateControllerAtIndex(std::size_t npad_index, std::size_t device_index,
const VibrationValue& vibration_value);
@@ -209,9 +172,9 @@ public:
void SignalStyleSetChangedEvent(u32 npad_id) const;
// Adds a new controller at an index.
- void AddNewControllerAt(NPadControllerType controller, std::size_t npad_index);
+ void AddNewControllerAt(Core::HID::NpadType controller, std::size_t npad_index);
// Adds a new controller at an index with connection status.
- void UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, bool connected);
+ void UpdateControllerAt(Core::HID::NpadType controller, std::size_t npad_index, bool connected);
void DisconnectNpad(u32 npad_id);
void DisconnectNpadAtIndex(std::size_t index);
@@ -241,103 +204,37 @@ public:
// Specifically for cheat engine and other features.
u32 GetAndResetPressState();
- static Controller_NPad::NPadControllerType MapSettingsTypeToNPad(Settings::ControllerType type);
- static Settings::ControllerType MapNPadToSettingsType(Controller_NPad::NPadControllerType type);
static std::size_t NPadIdToIndex(u32 npad_id);
static u32 IndexToNPad(std::size_t index);
static bool IsNpadIdValid(u32 npad_id);
static bool IsDeviceHandleValid(const DeviceHandle& device_handle);
private:
- struct CommonHeader {
- s64_le timestamp;
- s64_le total_entry_count;
- s64_le last_entry_index;
- s64_le entry_count;
- };
- static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size");
-
- enum class ColorAttributes : u32_le {
+ // This is nn::hid::detail::ColorAttribute
+ enum class ColorAttribute : u32_le {
Ok = 0,
ReadError = 1,
NoController = 2,
};
- static_assert(sizeof(ColorAttributes) == 4, "ColorAttributes is an invalid size");
-
- struct ControllerColor {
- u32_le body;
- u32_le button;
- };
- static_assert(sizeof(ControllerColor) == 8, "ControllerColor is an invalid size");
-
- struct FullKeyColor {
- ColorAttributes attribute;
- ControllerColor fullkey;
- };
- static_assert(sizeof(FullKeyColor) == 0xC, "FullKeyColor is an invalid size");
-
- struct JoyconColor {
- ColorAttributes attribute;
- ControllerColor left;
- ControllerColor right;
- };
- static_assert(sizeof(JoyconColor) == 0x14, "JoyconColor is an invalid size");
+ static_assert(sizeof(ColorAttribute) == 4, "ColorAttribute is an invalid size");
- struct ControllerPadState {
- union {
- u64_le raw{};
- // Button states
- BitField<0, 1, u64> a;
- BitField<1, 1, u64> b;
- BitField<2, 1, u64> x;
- BitField<3, 1, u64> y;
- BitField<4, 1, u64> l_stick;
- BitField<5, 1, u64> r_stick;
- BitField<6, 1, u64> l;
- BitField<7, 1, u64> r;
- BitField<8, 1, u64> zl;
- BitField<9, 1, u64> zr;
- BitField<10, 1, u64> plus;
- BitField<11, 1, u64> minus;
-
- // D-Pad
- BitField<12, 1, u64> d_left;
- BitField<13, 1, u64> d_up;
- BitField<14, 1, u64> d_right;
- BitField<15, 1, u64> d_down;
-
- // Left JoyStick
- BitField<16, 1, u64> l_stick_left;
- BitField<17, 1, u64> l_stick_up;
- BitField<18, 1, u64> l_stick_right;
- BitField<19, 1, u64> l_stick_down;
-
- // Right JoyStick
- BitField<20, 1, u64> r_stick_left;
- BitField<21, 1, u64> r_stick_up;
- BitField<22, 1, u64> r_stick_right;
- BitField<23, 1, u64> r_stick_down;
-
- // Not always active?
- BitField<24, 1, u64> left_sl;
- BitField<25, 1, u64> left_sr;
-
- BitField<26, 1, u64> right_sl;
- BitField<27, 1, u64> right_sr;
-
- BitField<28, 1, u64> palma;
- BitField<30, 1, u64> handheld_left_b;
- };
+ // This is nn::hid::detail::NpadFullKeyColorState
+ struct NpadFullKeyColorState {
+ ColorAttribute attribute;
+ Core::HID::NpadControllerColor fullkey;
};
- static_assert(sizeof(ControllerPadState) == 8, "ControllerPadState is an invalid size");
+ static_assert(sizeof(NpadFullKeyColorState) == 0xC, "NpadFullKeyColorState is an invalid size");
- struct AnalogPosition {
- s32_le x;
- s32_le y;
+ // This is nn::hid::detail::NpadJoyColorState
+ struct NpadJoyColorState {
+ ColorAttribute attribute;
+ Core::HID::NpadControllerColor left;
+ Core::HID::NpadControllerColor right;
};
- static_assert(sizeof(AnalogPosition) == 8, "AnalogPosition is an invalid size");
+ static_assert(sizeof(NpadJoyColorState) == 0x14, "NpadJoyColorState is an invalid size");
- struct ConnectionState {
+ // This is nn::hid::NpadAttribute
+ struct NpadAttribute {
union {
u32_le raw{};
BitField<0, 1, u32> is_connected;
@@ -348,76 +245,57 @@ private:
BitField<5, 1, u32> is_right_wired;
};
};
- static_assert(sizeof(ConnectionState) == 4, "ConnectionState is an invalid size");
-
- struct ControllerPad {
- ControllerPadState pad_states;
- AnalogPosition l_stick;
- AnalogPosition r_stick;
- };
- static_assert(sizeof(ControllerPad) == 0x18, "ControllerPad is an invalid size");
-
- struct GenericStates {
- s64_le timestamp;
- s64_le timestamp2;
- ControllerPad pad;
- ConnectionState connection_status;
- };
- static_assert(sizeof(GenericStates) == 0x30, "NPadGenericStates is an invalid size");
-
- struct NPadGeneric {
- CommonHeader common;
- std::array<GenericStates, 17> npad;
+ static_assert(sizeof(NpadAttribute) == 4, "NpadAttribute is an invalid size");
+
+ // This is nn::hid::NpadFullKeyState
+ // This is nn::hid::NpadHandheldState
+ // This is nn::hid::NpadJoyDualState
+ // This is nn::hid::NpadJoyLeftState
+ // This is nn::hid::NpadJoyRightState
+ // This is nn::hid::NpadPalmaState
+ // This is nn::hid::NpadSystemExtState
+ struct NPadGenericState {
+ s64_le sampling_number;
+ Core::HID::NpadButtonState npad_buttons;
+ Core::HID::AnalogStickState l_stick;
+ Core::HID::AnalogStickState r_stick;
+ NpadAttribute connection_status;
+ INSERT_PADDING_BYTES(4); // Reserved
};
- static_assert(sizeof(NPadGeneric) == 0x350, "NPadGeneric is an invalid size");
+ static_assert(sizeof(NPadGenericState) == 0x28, "NPadGenericState is an invalid size");
- struct SixAxisAttributes {
+ // This is nn::hid::SixAxisSensorAttribute
+ struct SixAxisSensorAttribute {
union {
u32_le raw{};
BitField<0, 1, u32> is_connected;
BitField<1, 1, u32> is_interpolated;
};
};
- static_assert(sizeof(SixAxisAttributes) == 4, "SixAxisAttributes is an invalid size");
+ static_assert(sizeof(SixAxisSensorAttribute) == 4, "SixAxisSensorAttribute is an invalid size");
- struct SixAxisStates {
- s64_le timestamp{};
- INSERT_PADDING_WORDS(2);
- s64_le timestamp2{};
+ // This is nn::hid::SixAxisSensorState
+ struct SixAxisSensorState {
+ s64_le delta_time{};
+ s64_le sampling_number{};
Common::Vec3f accel{};
Common::Vec3f gyro{};
Common::Vec3f rotation{};
std::array<Common::Vec3f, 3> orientation{};
- SixAxisAttributes attribute;
+ SixAxisSensorAttribute attribute;
INSERT_PADDING_BYTES(4); // Reserved
};
- static_assert(sizeof(SixAxisStates) == 0x68, "SixAxisStates is an invalid size");
-
- struct SixAxisGeneric {
- CommonHeader common{};
- std::array<SixAxisStates, 17> sixaxis{};
- };
- static_assert(sizeof(SixAxisGeneric) == 0x708, "SixAxisGeneric is an invalid size");
+ static_assert(sizeof(SixAxisSensorState) == 0x60, "SixAxisSensorState is an invalid size");
- struct TriggerState {
- s64_le timestamp{};
- s64_le timestamp2{};
+ // This is nn::hid::server::NpadGcTriggerState
+ struct NpadGcTriggerState {
+ s64_le sampling_number{};
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");
+ static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size");
+ // This is nn::hid::NpadSystemProperties
struct NPadSystemProperties {
union {
s64_le raw{};
@@ -438,15 +316,18 @@ private:
};
static_assert(sizeof(NPadSystemProperties) == 0x8, "NPadSystemProperties is an invalid size");
- struct NPadButtonProperties {
+ // This is nn::hid::NpadSystemButtonProperties
+ struct NpadSystemButtonProperties {
union {
s32_le raw{};
BitField<0, 1, s32> is_home_button_protection_enabled;
};
};
- static_assert(sizeof(NPadButtonProperties) == 0x4, "NPadButtonProperties is an invalid size");
+ static_assert(sizeof(NpadSystemButtonProperties) == 0x4,
+ "NPadButtonProperties is an invalid size");
- struct NPadDevice {
+ // This is nn::hid::system::DeviceType
+ struct DeviceType {
union {
u32_le raw{};
BitField<0, 1, s32> fullkey;
@@ -469,14 +350,6 @@ private:
};
};
- struct MotionDevice {
- Common::Vec3f accel;
- Common::Vec3f gyro;
- Common::Vec3f rotation;
- std::array<Common::Vec3f, 3> orientation;
- Common::Quaternion<f32> quaternion;
- };
-
struct NfcXcdHandle {
INSERT_PADDING_BYTES(0x60);
};
@@ -485,6 +358,7 @@ private:
INSERT_PADDING_BYTES(0x4);
};
+ // This is nn::hid::server::NpadGcTriggerState
enum class AppletFooterUiType : u8 {
None = 0,
HandheldNone = 1,
@@ -510,95 +384,90 @@ private:
Lagon = 21,
};
- struct NPadEntry {
- NpadStyleSet style_set;
- NpadAssignments assignment_mode;
- FullKeyColor fullkey_color;
- JoyconColor joycon_color;
-
- NPadGeneric fullkey_states;
- NPadGeneric handheld_states;
- NPadGeneric joy_dual_states;
- NPadGeneric joy_left_states;
- NPadGeneric joy_right_states;
- NPadGeneric palma_states;
- NPadGeneric system_ext_states;
- SixAxisGeneric sixaxis_fullkey;
- SixAxisGeneric sixaxis_handheld;
- SixAxisGeneric sixaxis_dual_left;
- SixAxisGeneric sixaxis_dual_right;
- SixAxisGeneric sixaxis_left;
- SixAxisGeneric sixaxis_right;
- NPadDevice device_type;
- INSERT_PADDING_BYTES(0x4); // reserved
+ // This is nn::hid::detail::NpadInternalState
+ struct NpadInternalState {
+ Core::HID::NpadStyleTag style_set;
+ NpadJoyAssignmentMode assignment_mode;
+ NpadFullKeyColorState fullkey_color;
+ NpadJoyColorState joycon_color;
+ Lifo<NPadGenericState> fullkey_lifo;
+ Lifo<NPadGenericState> handheld_lifo;
+ Lifo<NPadGenericState> joy_dual_lifo;
+ Lifo<NPadGenericState> joy_left_lifo;
+ Lifo<NPadGenericState> joy_right_lifo;
+ Lifo<NPadGenericState> palma_lifo;
+ Lifo<NPadGenericState> system_ext_lifo;
+ Lifo<SixAxisSensorState> sixaxis_fullkey_lifo;
+ Lifo<SixAxisSensorState> sixaxis_handheld_lifo;
+ Lifo<SixAxisSensorState> sixaxis_dual_left_lifo;
+ Lifo<SixAxisSensorState> sixaxis_dual_right_lifo;
+ Lifo<SixAxisSensorState> sixaxis_left_lifo;
+ Lifo<SixAxisSensorState> sixaxis_right_lifo;
+ DeviceType device_type;
+ INSERT_PADDING_BYTES(0x4); // Reserved
NPadSystemProperties system_properties;
- NPadButtonProperties button_properties;
- u32 battery_level_dual;
- u32 battery_level_left;
- u32 battery_level_right;
+ NpadSystemButtonProperties button_properties;
+ Core::HID::BatteryLevel battery_level_dual;
+ Core::HID::BatteryLevel battery_level_left;
+ Core::HID::BatteryLevel battery_level_right;
AppletFooterUiAttributes footer_attributes;
AppletFooterUiType footer_type;
- // nfc_states needs to be checked switchbrew does not match with HW
+ // nfc_states needs to be checked switchbrew doesn't match with HW
NfcXcdHandle nfc_states;
- INSERT_PADDING_BYTES(0x8); // Mutex
- TriggerGeneric gc_trigger_states;
- INSERT_PADDING_BYTES(0xc1f);
+ INSERT_PADDING_BYTES(0x18); // Unknown
+ Lifo<NpadGcTriggerState> gc_trigger_lifo;
+ INSERT_PADDING_BYTES(0xc1f); // Unknown
};
- static_assert(sizeof(NPadEntry) == 0x5000, "NPadEntry is an invalid size");
+ static_assert(sizeof(NpadInternalState) == 0x5000, "NpadInternalState is an invalid size");
- struct ControllerHolder {
- NPadControllerType type;
- bool is_connected;
+ struct VibrationData {
+ bool device_mounted{};
+ VibrationValue latest_vibration_value{};
+ std::chrono::steady_clock::time_point last_vibration_timepoint{};
};
+ struct ControllerData {
+ Core::HID::EmulatedController* device;
+ Kernel::KEvent* styleset_changed_event{};
+ NpadInternalState shared_memory_entry{};
+
+ std::array<VibrationData, 2> vibration{};
+ bool unintended_home_button_input_protection{};
+
+ // Current pad state
+ NPadGenericState npad_pad_state{};
+ NPadGenericState npad_libnx_state{};
+ NpadGcTriggerState npad_trigger_state{};
+ SixAxisSensorState sixaxis_fullkey_state{};
+ SixAxisSensorState sixaxis_handheld_state{};
+ SixAxisSensorState sixaxis_dual_left_state{};
+ SixAxisSensorState sixaxis_dual_right_state{};
+ SixAxisSensorState sixaxis_left_lifo_state{};
+ SixAxisSensorState sixaxis_right_lifo_state{};
+ int callback_key;
+ };
+
+ void ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t controller_idx);
void InitNewlyAddedController(std::size_t controller_idx);
- bool IsControllerSupported(NPadControllerType controller) const;
+ bool IsControllerSupported(Core::HID::NpadType controller) const;
void RequestPadStateUpdate(u32 npad_id);
std::atomic<u32> press_state{};
- NpadStyleSet style{};
- std::array<NPadEntry, 10> shared_memory_entries{};
- using ButtonArray = std::array<
- std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>,
- 10>;
- using StickArray = std::array<
- std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NumAnalogs>,
- 10>;
- using VibrationArray = std::array<std::array<std::unique_ptr<Input::VibrationDevice>,
- Settings::NativeVibration::NUM_VIBRATIONS_HID>,
- 10>;
- using MotionArray = std::array<
- std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTIONS_HID>,
- 10>;
-
+ std::array<ControllerData, 10> controller_data{};
KernelHelpers::ServiceContext& service_context;
std::mutex mutex;
- ButtonArray buttons;
- StickArray sticks;
- VibrationArray vibrations;
- MotionArray motions;
std::vector<u32> supported_npad_id_types{};
- NpadHoldType hold_type{NpadHoldType::Vertical};
+ NpadJoyHoldType hold_type{NpadJoyHoldType::Vertical};
NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual};
NpadCommunicationMode communication_mode{NpadCommunicationMode::Default};
- // Each controller should have their own styleset changed event
- std::array<Kernel::KEvent*, 10> styleset_changed_events{};
- std::array<std::array<std::chrono::steady_clock::time_point, 2>, 10>
- last_vibration_timepoints{};
- std::array<std::array<VibrationValue, 2>, 10> latest_vibration_values{};
bool permit_vibration_session_enabled{false};
- std::array<std::array<bool, 2>, 10> vibration_devices_mounted{};
- std::array<ControllerHolder, 10> connected_controllers{};
- std::array<bool, 10> unintended_home_button_input_protection{};
bool analog_stick_use_center_clamp{};
GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard};
bool sixaxis_sensors_enabled{true};
f32 sixaxis_fusion_parameter1{};
f32 sixaxis_fusion_parameter2{};
bool sixaxis_at_rest{true};
- std::array<ControllerPad, 10> npad_pad_states{};
- std::array<TriggerState, 10> npad_trigger_states{};
bool is_in_lr_assignment_mode{false};
};
} // namespace Service::HID