diff options
Diffstat (limited to 'src/core/hle/service/hid')
23 files changed, 2004 insertions, 2205 deletions
diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.cpp b/src/core/hle/service/hid/controllers/console_sixaxis.cpp index bda6e2557..f0f3105dc 100644 --- a/src/core/hle/service/hid/controllers/console_sixaxis.cpp +++ b/src/core/hle/service/hid/controllers/console_sixaxis.cpp @@ -4,13 +4,18 @@ #include "common/settings.h" #include "core/core_timing.h" +#include "core/hid/emulated_console.h" +#include "core/hid/hid_core.h" #include "core/hle/service/hid/controllers/console_sixaxis.h" namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200; -Controller_ConsoleSixAxis::Controller_ConsoleSixAxis(Core::System& system_) - : ControllerBase{system_} {} +Controller_ConsoleSixAxis::Controller_ConsoleSixAxis(Core::HID::HIDCore& hid_core_) + : ControllerBase{hid_core_} { + console = hid_core.GetEmulatedConsole(); +} + Controller_ConsoleSixAxis::~Controller_ConsoleSixAxis() = default; void Controller_ConsoleSixAxis::OnInit() {} @@ -19,44 +24,31 @@ void Controller_ConsoleSixAxis::OnRelease() {} void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { - seven_six_axis.header.timestamp = core_timing.GetCPUTicks(); - seven_six_axis.header.total_entry_count = 17; - if (!IsControllerActivated() || !is_transfer_memory_set) { - seven_six_axis.header.entry_count = 0; - seven_six_axis.header.last_entry_index = 0; + seven_sixaxis_lifo.buffer_count = 0; + seven_sixaxis_lifo.buffer_tail = 0; return; } - seven_six_axis.header.entry_count = 16; - - const auto& last_entry = - seven_six_axis.sevensixaxis_states[seven_six_axis.header.last_entry_index]; - seven_six_axis.header.last_entry_index = (seven_six_axis.header.last_entry_index + 1) % 17; - auto& cur_entry = seven_six_axis.sevensixaxis_states[seven_six_axis.header.last_entry_index]; - cur_entry.sampling_number = last_entry.sampling_number + 1; - cur_entry.sampling_number2 = cur_entry.sampling_number; + const auto& last_entry = seven_sixaxis_lifo.ReadCurrentEntry().state; + next_seven_sixaxis_state.sampling_number = last_entry.sampling_number + 1; // Try to read sixaxis sensor states - MotionDevice motion_device{}; - const auto& device = motions[0]; - if (device) { - std::tie(motion_device.accel, motion_device.gyro, motion_device.rotation, - motion_device.orientation, motion_device.quaternion) = device->GetStatus(); - console_six_axis.is_seven_six_axis_sensor_at_rest = motion_device.gyro.Length2() < 0.0001f; - } + const auto motion_status = console->GetMotion(); + + console_six_axis.is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest; - cur_entry.accel = motion_device.accel; + next_seven_sixaxis_state.accel = motion_status.accel; // Zero gyro values as they just mess up with the camera // Note: Probably a correct sensivity setting must be set - cur_entry.gyro = {}; - cur_entry.quaternion = { + next_seven_sixaxis_state.gyro = {}; + next_seven_sixaxis_state.quaternion = { { - motion_device.quaternion.xyz.y, - motion_device.quaternion.xyz.x, - -motion_device.quaternion.w, + motion_status.quaternion.xyz.y, + motion_status.quaternion.xyz.x, + -motion_status.quaternion.w, }, - -motion_device.quaternion.xyz.z, + -motion_status.quaternion.xyz.z, }; console_six_axis.sampling_number++; @@ -67,14 +59,8 @@ void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_ti // Update console six axis shared memory std::memcpy(data + SHARED_MEMORY_OFFSET, &console_six_axis, sizeof(console_six_axis)); // Update seven six axis transfer memory - std::memcpy(transfer_memory, &seven_six_axis, sizeof(seven_six_axis)); -} - -void Controller_ConsoleSixAxis::OnLoadInputDevices() { - const auto player = Settings::values.players.GetValue()[0]; - std::transform(player.motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN, - player.motions.begin() + Settings::NativeMotion::MOTION_HID_END, motions.begin(), - Input::CreateDevice<Input::MotionDevice>); + seven_sixaxis_lifo.WriteNextEntry(next_seven_sixaxis_state); + std::memcpy(transfer_memory, &seven_sixaxis_lifo, sizeof(seven_sixaxis_lifo)); } void Controller_ConsoleSixAxis::SetTransferMemoryPointer(u8* t_mem) { @@ -83,8 +69,7 @@ void Controller_ConsoleSixAxis::SetTransferMemoryPointer(u8* t_mem) { } void Controller_ConsoleSixAxis::ResetTimestamp() { - auto& cur_entry = seven_six_axis.sevensixaxis_states[seven_six_axis.header.last_entry_index]; - cur_entry.sampling_number = 0; - cur_entry.sampling_number2 = 0; + seven_sixaxis_lifo.buffer_count = 0; + seven_sixaxis_lifo.buffer_tail = 0; } } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.h b/src/core/hle/service/hid/controllers/console_sixaxis.h index fd8a427af..279241858 100644 --- a/src/core/hle/service/hid/controllers/console_sixaxis.h +++ b/src/core/hle/service/hid/controllers/console_sixaxis.h @@ -5,16 +5,21 @@ #pragma once #include <array> -#include "common/bit_field.h" + #include "common/common_types.h" #include "common/quaternion.h" -#include "core/frontend/input.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 Core::HID { +class EmulatedConsole; +} // namespace Core::HID namespace Service::HID { class Controller_ConsoleSixAxis final : public ControllerBase { public: - explicit Controller_ConsoleSixAxis(Core::System& system_); + explicit Controller_ConsoleSixAxis(Core::HID::HIDCore& hid_core_); ~Controller_ConsoleSixAxis() override; // Called when the controller is initialized @@ -26,9 +31,6 @@ public: // When the controller is requesting an update for the shared memory void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, size_t size) override; - // Called when input devices should be loaded - void OnLoadInputDevices() override; - // Called on InitializeSevenSixAxisSensor void SetTransferMemoryPointer(u8* t_mem); @@ -38,43 +40,31 @@ public: private: struct SevenSixAxisState { INSERT_PADDING_WORDS(4); // unused - s64_le sampling_number{}; - s64_le sampling_number2{}; + s64 sampling_number{}; u64 unknown{}; Common::Vec3f accel{}; Common::Vec3f gyro{}; Common::Quaternion<f32> quaternion{}; }; - static_assert(sizeof(SevenSixAxisState) == 0x50, "SevenSixAxisState is an invalid size"); - - struct SevenSixAxisMemory { - CommonHeader header{}; - std::array<SevenSixAxisState, 0x21> sevensixaxis_states{}; - }; - static_assert(sizeof(SevenSixAxisMemory) == 0xA70, "SevenSixAxisMemory is an invalid size"); + static_assert(sizeof(SevenSixAxisState) == 0x48, "SevenSixAxisState is an invalid size"); + // This is nn::hid::detail::ConsoleSixAxisSensorSharedMemoryFormat struct ConsoleSharedMemory { - u64_le sampling_number{}; + u64 sampling_number{}; bool is_seven_six_axis_sensor_at_rest{}; + INSERT_PADDING_BYTES(4); // padding f32 verticalization_error{}; Common::Vec3f gyro_bias{}; }; static_assert(sizeof(ConsoleSharedMemory) == 0x20, "ConsoleSharedMemory is an invalid size"); - struct MotionDevice { - Common::Vec3f accel; - Common::Vec3f gyro; - Common::Vec3f rotation; - std::array<Common::Vec3f, 3> orientation; - Common::Quaternion<f32> quaternion; - }; + Lifo<SevenSixAxisState, 0x21> seven_sixaxis_lifo{}; + static_assert(sizeof(seven_sixaxis_lifo) == 0xA70, "SevenSixAxisState is an invalid size"); - using MotionArray = - std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTIONS_HID>; - MotionArray motions; + Core::HID::EmulatedConsole* console; u8* transfer_memory = nullptr; bool is_transfer_memory_set = false; ConsoleSharedMemory console_six_axis{}; - SevenSixAxisMemory seven_six_axis{}; + SevenSixAxisState next_seven_sixaxis_state{}; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/controller_base.cpp b/src/core/hle/service/hid/controllers/controller_base.cpp index 9d1e6db6a..788ae9ae7 100644 --- a/src/core/hle/service/hid/controllers/controller_base.cpp +++ b/src/core/hle/service/hid/controllers/controller_base.cpp @@ -6,12 +6,12 @@ namespace Service::HID { -ControllerBase::ControllerBase(Core::System& system_) : system(system_) {} +ControllerBase::ControllerBase(Core::HID::HIDCore& hid_core_) : hid_core(hid_core_) {} ControllerBase::~ControllerBase() = default; void ControllerBase::ActivateController() { if (is_activated) { - OnRelease(); + return; } is_activated = true; OnInit(); diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h index 1556fb08e..7450eb20a 100644 --- a/src/core/hle/service/hid/controllers/controller_base.h +++ b/src/core/hle/service/hid/controllers/controller_base.h @@ -11,14 +11,14 @@ namespace Core::Timing { class CoreTiming; } -namespace Core { -class System; +namespace Core::HID { +class HIDCore; } namespace Service::HID { class ControllerBase { public: - explicit ControllerBase(Core::System& system_); + explicit ControllerBase(Core::HID::HIDCore& hid_core_); virtual ~ControllerBase(); // Called when the controller is initialized @@ -35,26 +35,17 @@ public: virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) {} - // Called when input devices should be loaded - virtual void OnLoadInputDevices() = 0; - void ActivateController(); void DeactivateController(); bool IsControllerActivated() const; + static const std::size_t hid_entry_count = 17; + protected: bool is_activated{false}; - 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"); - - Core::System& system; + Core::HID::HIDCore& hid_core; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp index d439b8fb0..6a6fb9cab 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.cpp +++ b/src/core/hle/service/hid/controllers/debug_pad.cpp @@ -6,15 +6,19 @@ #include "common/common_types.h" #include "common/settings.h" #include "core/core_timing.h" +#include "core/hid/emulated_controller.h" +#include "core/hid/hid_core.h" +#include "core/hid/hid_types.h" #include "core/hle/service/hid/controllers/debug_pad.h" namespace Service::HID { +constexpr std::size_t SHARED_MEMORY_OFFSET = 0x00000; -constexpr s32 HID_JOYSTICK_MAX = 0x7fff; -[[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff; -enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right }; +Controller_DebugPad::Controller_DebugPad(Core::HID::HIDCore& hid_core_) + : ControllerBase{hid_core_} { + controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other); +} -Controller_DebugPad::Controller_DebugPad(Core::System& system_) : ControllerBase{system_} {} Controller_DebugPad::~Controller_DebugPad() = default; void Controller_DebugPad::OnInit() {} @@ -23,63 +27,29 @@ void Controller_DebugPad::OnRelease() {} void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { - shared_memory.header.timestamp = core_timing.GetCPUTicks(); - shared_memory.header.total_entry_count = 17; - if (!IsControllerActivated()) { - shared_memory.header.entry_count = 0; - shared_memory.header.last_entry_index = 0; + debug_pad_lifo.buffer_count = 0; + debug_pad_lifo.buffer_tail = 0; + std::memcpy(data + SHARED_MEMORY_OFFSET, &debug_pad_lifo, sizeof(debug_pad_lifo)); return; } - shared_memory.header.entry_count = 16; - const auto& last_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; - shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; - auto& cur_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; - - cur_entry.sampling_number = last_entry.sampling_number + 1; - cur_entry.sampling_number2 = cur_entry.sampling_number; + const auto& last_entry = debug_pad_lifo.ReadCurrentEntry().state; + next_state.sampling_number = last_entry.sampling_number + 1; if (Settings::values.debug_pad_enabled) { - cur_entry.attribute.connected.Assign(1); - auto& pad = cur_entry.pad_state; + next_state.attribute.connected.Assign(1); - using namespace Settings::NativeButton; - pad.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus()); - pad.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus()); - pad.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus()); - pad.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus()); - pad.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus()); - pad.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus()); - pad.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus()); - pad.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus()); - pad.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus()); - pad.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus()); - pad.d_left.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus()); - pad.d_up.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus()); - pad.d_right.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus()); - pad.d_down.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus()); + const auto& button_state = controller->GetDebugPadButtons(); + const auto& stick_state = controller->GetSticks(); - const auto [stick_l_x_f, stick_l_y_f] = - analogs[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus(); - const auto [stick_r_x_f, stick_r_y_f] = - analogs[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus(); - cur_entry.l_stick.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX); - cur_entry.l_stick.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX); - cur_entry.r_stick.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX); - cur_entry.r_stick.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX); + next_state.pad_state = button_state; + next_state.l_stick = stick_state.left; + next_state.r_stick = stick_state.right; } - std::memcpy(data, &shared_memory, sizeof(SharedMemory)); + debug_pad_lifo.WriteNextEntry(next_state); + std::memcpy(data + SHARED_MEMORY_OFFSET, &debug_pad_lifo, sizeof(debug_pad_lifo)); } -void Controller_DebugPad::OnLoadInputDevices() { - std::transform(Settings::values.debug_pad_buttons.begin(), - Settings::values.debug_pad_buttons.begin() + - Settings::NativeButton::NUM_BUTTONS_HID, - buttons.begin(), Input::CreateDevice<Input::ButtonDevice>); - std::transform(Settings::values.debug_pad_analogs.begin(), - Settings::values.debug_pad_analogs.end(), analogs.begin(), - Input::CreateDevice<Input::AnalogDevice>); -} } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h index 1b1645184..afe374fc2 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.h +++ b/src/core/hle/service/hid/controllers/debug_pad.h @@ -8,15 +8,20 @@ #include "common/bit_field.h" #include "common/common_funcs.h" #include "common/common_types.h" -#include "common/settings.h" #include "common/swap.h" -#include "core/frontend/input.h" #include "core/hle/service/hid/controllers/controller_base.h" +#include "core/hle/service/hid/ring_lifo.h" + +namespace Core::HID { +class EmulatedController; +struct DebugPadButton; +struct AnalogStickState; +} // namespace Core::HID namespace Service::HID { class Controller_DebugPad final : public ControllerBase { public: - explicit Controller_DebugPad(Core::System& system_); + explicit Controller_DebugPad(Core::HID::HIDCore& hid_core_); ~Controller_DebugPad() override; // Called when the controller is initialized @@ -28,66 +33,31 @@ public: // When the controller is requesting an update for the shared memory void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; - // Called when input devices should be loaded - void OnLoadInputDevices() override; - private: - struct AnalogStick { - s32_le x; - s32_le y; - }; - static_assert(sizeof(AnalogStick) == 0x8); - - struct PadState { - union { - u32_le raw{}; - BitField<0, 1, u32> a; - BitField<1, 1, u32> b; - BitField<2, 1, u32> x; - BitField<3, 1, u32> y; - BitField<4, 1, u32> l; - BitField<5, 1, u32> r; - BitField<6, 1, u32> zl; - BitField<7, 1, u32> zr; - BitField<8, 1, u32> plus; - BitField<9, 1, u32> minus; - BitField<10, 1, u32> d_left; - BitField<11, 1, u32> d_up; - BitField<12, 1, u32> d_right; - BitField<13, 1, u32> d_down; - }; - }; - static_assert(sizeof(PadState) == 0x4, "PadState is an invalid size"); - - struct Attributes { + // This is nn::hid::DebugPadAttribute + struct DebugPadAttribute { union { - u32_le raw{}; + u32 raw{}; BitField<0, 1, u32> connected; }; }; - static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size"); - - struct PadStates { - s64_le sampling_number; - s64_le sampling_number2; - Attributes attribute; - PadState pad_state; - AnalogStick r_stick; - AnalogStick l_stick; + static_assert(sizeof(DebugPadAttribute) == 0x4, "DebugPadAttribute is an invalid size"); + + // This is nn::hid::DebugPadState + struct DebugPadState { + s64 sampling_number; + DebugPadAttribute attribute; + Core::HID::DebugPadButton pad_state; + Core::HID::AnalogStickState r_stick; + Core::HID::AnalogStickState l_stick; }; - static_assert(sizeof(PadStates) == 0x28, "PadStates is an invalid state"); + static_assert(sizeof(DebugPadState) == 0x20, "DebugPadState is an invalid state"); - struct SharedMemory { - CommonHeader header; - std::array<PadStates, 17> pad_states; - INSERT_PADDING_BYTES(0x138); - }; - static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size"); - SharedMemory shared_memory{}; + // This is nn::hid::detail::DebugPadLifo + Lifo<DebugPadState, hid_entry_count> debug_pad_lifo{}; + static_assert(sizeof(debug_pad_lifo) == 0x2C8, "debug_pad_lifo is an invalid size"); + DebugPadState next_state{}; - std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID> - buttons; - std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID> - analogs; + Core::HID::EmulatedController* controller; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp index 764abb5b6..fe895c4f6 100644 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp @@ -7,6 +7,7 @@ #include "common/settings.h" #include "core/core_timing.h" #include "core/frontend/emu_window.h" +#include "core/hid/hid_core.h" #include "core/hle/service/hid/controllers/gesture.h" namespace Service::HID { @@ -23,16 +24,14 @@ constexpr f32 Square(s32 num) { return static_cast<f32>(num * num); } -Controller_Gesture::Controller_Gesture(Core::System& system_) : ControllerBase(system_) {} +Controller_Gesture::Controller_Gesture(Core::HID::HIDCore& hid_core_) : ControllerBase(hid_core_) { + console = hid_core.GetEmulatedConsole(); +} Controller_Gesture::~Controller_Gesture() = default; void Controller_Gesture::OnInit() { - for (std::size_t id = 0; id < MAX_FINGERS; ++id) { - mouse_finger_id[id] = MAX_POINTS; - keyboard_finger_id[id] = MAX_POINTS; - udp_finger_id[id] = MAX_POINTS; - } - shared_memory.header.entry_count = 0; + gesture_lifo.buffer_count = 0; + gesture_lifo.buffer_tail = 0; force_update = true; } @@ -40,50 +39,38 @@ void Controller_Gesture::OnRelease() {} void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { - shared_memory.header.timestamp = core_timing.GetCPUTicks(); - shared_memory.header.total_entry_count = 17; - if (!IsControllerActivated()) { - shared_memory.header.entry_count = 0; - shared_memory.header.last_entry_index = 0; + gesture_lifo.buffer_count = 0; + gesture_lifo.buffer_tail = 0; + std::memcpy(data + SHARED_MEMORY_OFFSET, &gesture_lifo, sizeof(gesture_lifo)); return; } ReadTouchInput(); GestureProperties gesture = GetGestureProperties(); - f32 time_difference = static_cast<f32>(shared_memory.header.timestamp - last_update_timestamp) / - (1000 * 1000 * 1000); + f32 time_difference = + static_cast<f32>(gesture_lifo.timestamp - last_update_timestamp) / (1000 * 1000 * 1000); // Only update if necesary if (!ShouldUpdateGesture(gesture, time_difference)) { return; } - last_update_timestamp = shared_memory.header.timestamp; + last_update_timestamp = gesture_lifo.timestamp; UpdateGestureSharedMemory(data, size, gesture, time_difference); } void Controller_Gesture::ReadTouchInput() { - const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus(); - const Input::TouchStatus& udp_status = touch_udp_device->GetStatus(); - for (std::size_t id = 0; id < mouse_status.size(); ++id) { - mouse_finger_id[id] = UpdateTouchInputEvent(mouse_status[id], mouse_finger_id[id]); - udp_finger_id[id] = UpdateTouchInputEvent(udp_status[id], udp_finger_id[id]); - } - - if (Settings::values.use_touch_from_button) { - const Input::TouchStatus& keyboard_status = touch_btn_device->GetStatus(); - for (std::size_t id = 0; id < mouse_status.size(); ++id) { - keyboard_finger_id[id] = - UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]); - } + const auto touch_status = console->GetTouch(); + for (std::size_t id = 0; id < fingers.size(); ++id) { + fingers[id] = touch_status[id]; } } bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference) { - const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + const auto& last_entry = GetLastGestureEntry(); if (force_update) { force_update = false; return true; @@ -97,7 +84,7 @@ bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, } // Update on press and hold event after 0.5 seconds - if (last_entry.type == TouchType::Touch && last_entry.point_count == 1 && + if (last_entry.type == GestureType::Touch && last_entry.point_count == 1 && time_difference > press_delay) { return enable_press_and_tap; } @@ -108,27 +95,19 @@ bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, GestureProperties& gesture, f32 time_difference) { - TouchType type = TouchType::Idle; - Attribute attributes{}; + GestureType type = GestureType::Idle; + GestureAttribute attributes{}; - const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; - shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; - auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; - if (shared_memory.header.entry_count < 16) { - shared_memory.header.entry_count++; - } - - cur_entry.sampling_number = last_entry.sampling_number + 1; - cur_entry.sampling_number2 = cur_entry.sampling_number; - - // Reset values to default - cur_entry.delta = {}; - cur_entry.vel_x = 0; - cur_entry.vel_y = 0; - cur_entry.direction = Direction::None; - cur_entry.rotation_angle = 0; - cur_entry.scale = 0; + // Reset next state to default + next_state.sampling_number = last_entry.sampling_number + 1; + next_state.delta = {}; + next_state.vel_x = 0; + next_state.vel_y = 0; + next_state.direction = GestureDirection::None; + next_state.rotation_angle = 0; + next_state.scale = 0; if (gesture.active_points > 0) { if (last_gesture.active_points == 0) { @@ -141,46 +120,47 @@ void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, } // Apply attributes - cur_entry.detection_count = gesture.detection_count; - cur_entry.type = type; - cur_entry.attributes = attributes; - cur_entry.pos = gesture.mid_point; - cur_entry.point_count = static_cast<s32>(gesture.active_points); - cur_entry.points = gesture.points; + next_state.detection_count = gesture.detection_count; + next_state.type = type; + next_state.attributes = attributes; + next_state.pos = gesture.mid_point; + next_state.point_count = static_cast<s32>(gesture.active_points); + next_state.points = gesture.points; last_gesture = gesture; - std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); + gesture_lifo.WriteNextEntry(next_state); + std::memcpy(data + SHARED_MEMORY_OFFSET, &gesture_lifo, sizeof(gesture_lifo)); } -void Controller_Gesture::NewGesture(GestureProperties& gesture, TouchType& type, - Attribute& attributes) { +void Controller_Gesture::NewGesture(GestureProperties& gesture, GestureType& type, + GestureAttribute& attributes) { const auto& last_entry = GetLastGestureEntry(); gesture.detection_count++; - type = TouchType::Touch; + type = GestureType::Touch; // New touch after cancel is not considered new - if (last_entry.type != TouchType::Cancel) { + if (last_entry.type != GestureType::Cancel) { attributes.is_new_touch.Assign(1); enable_press_and_tap = true; } } -void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, TouchType& type, +void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, GestureType& type, f32 time_difference) { const auto& last_entry = GetLastGestureEntry(); // Promote to pan type if touch moved for (size_t id = 0; id < MAX_POINTS; id++) { if (gesture.points[id] != last_gesture.points[id]) { - type = TouchType::Pan; + type = GestureType::Pan; break; } } // Number of fingers changed cancel the last event and clear data if (gesture.active_points != last_gesture.active_points) { - type = TouchType::Cancel; + type = GestureType::Cancel; enable_press_and_tap = false; gesture.active_points = 0; gesture.mid_point = {}; @@ -189,41 +169,41 @@ void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, Touch } // Calculate extra parameters of panning - if (type == TouchType::Pan) { + if (type == GestureType::Pan) { UpdatePanEvent(gesture, last_gesture, type, time_difference); return; } // Promote to press type - if (last_entry.type == TouchType::Touch) { - type = TouchType::Press; + if (last_entry.type == GestureType::Touch) { + type = GestureType::Press; } } void Controller_Gesture::EndGesture(GestureProperties& gesture, - GestureProperties& last_gesture_props, TouchType& type, - Attribute& attributes, f32 time_difference) { + GestureProperties& last_gesture_props, GestureType& type, + GestureAttribute& attributes, f32 time_difference) { const auto& last_entry = GetLastGestureEntry(); if (last_gesture_props.active_points != 0) { switch (last_entry.type) { - case TouchType::Touch: + case GestureType::Touch: if (enable_press_and_tap) { SetTapEvent(gesture, last_gesture_props, type, attributes); return; } - type = TouchType::Cancel; + type = GestureType::Cancel; force_update = true; break; - case TouchType::Press: - case TouchType::Tap: - case TouchType::Swipe: - case TouchType::Pinch: - case TouchType::Rotate: - type = TouchType::Complete; + case GestureType::Press: + case GestureType::Tap: + case GestureType::Swipe: + case GestureType::Pinch: + case GestureType::Rotate: + type = GestureType::Complete; force_update = true; break; - case TouchType::Pan: + case GestureType::Pan: EndPanEvent(gesture, last_gesture_props, type, time_difference); break; default: @@ -231,15 +211,15 @@ void Controller_Gesture::EndGesture(GestureProperties& gesture, } return; } - if (last_entry.type == TouchType::Complete || last_entry.type == TouchType::Cancel) { + if (last_entry.type == GestureType::Complete || last_entry.type == GestureType::Cancel) { gesture.detection_count++; } } void Controller_Gesture::SetTapEvent(GestureProperties& gesture, - GestureProperties& last_gesture_props, TouchType& type, - Attribute& attributes) { - type = TouchType::Tap; + GestureProperties& last_gesture_props, GestureType& type, + GestureAttribute& attributes) { + type = GestureType::Tap; gesture = last_gesture_props; force_update = true; f32 tap_time_difference = @@ -251,44 +231,42 @@ void Controller_Gesture::SetTapEvent(GestureProperties& gesture, } void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture, - GestureProperties& last_gesture_props, TouchType& type, + GestureProperties& last_gesture_props, GestureType& type, f32 time_difference) { - auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; const auto& last_entry = GetLastGestureEntry(); - cur_entry.delta = gesture.mid_point - last_entry.pos; - cur_entry.vel_x = static_cast<f32>(cur_entry.delta.x) / time_difference; - cur_entry.vel_y = static_cast<f32>(cur_entry.delta.y) / time_difference; + next_state.delta = gesture.mid_point - last_entry.pos; + next_state.vel_x = static_cast<f32>(next_state.delta.x) / time_difference; + next_state.vel_y = static_cast<f32>(next_state.delta.y) / time_difference; last_pan_time_difference = time_difference; // Promote to pinch type if (std::abs(gesture.average_distance - last_gesture_props.average_distance) > pinch_threshold) { - type = TouchType::Pinch; - cur_entry.scale = gesture.average_distance / last_gesture_props.average_distance; + type = GestureType::Pinch; + next_state.scale = gesture.average_distance / last_gesture_props.average_distance; } const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture_props.angle) / (1 + (gesture.angle * last_gesture_props.angle))); // Promote to rotate type if (std::abs(angle_between_two_lines) > angle_threshold) { - type = TouchType::Rotate; - cur_entry.scale = 0; - cur_entry.rotation_angle = angle_between_two_lines * 180.0f / Common::PI; + type = GestureType::Rotate; + next_state.scale = 0; + next_state.rotation_angle = angle_between_two_lines * 180.0f / Common::PI; } } void Controller_Gesture::EndPanEvent(GestureProperties& gesture, - GestureProperties& last_gesture_props, TouchType& type, + GestureProperties& last_gesture_props, GestureType& type, f32 time_difference) { - auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; const auto& last_entry = GetLastGestureEntry(); - cur_entry.vel_x = + next_state.vel_x = static_cast<f32>(last_entry.delta.x) / (last_pan_time_difference + time_difference); - cur_entry.vel_y = + next_state.vel_y = static_cast<f32>(last_entry.delta.y) / (last_pan_time_difference + time_difference); const f32 curr_vel = - std::sqrt((cur_entry.vel_x * cur_entry.vel_x) + (cur_entry.vel_y * cur_entry.vel_y)); + std::sqrt((next_state.vel_x * next_state.vel_x) + (next_state.vel_y * next_state.vel_y)); // Set swipe event with parameters if (curr_vel > swipe_threshold) { @@ -297,105 +275,50 @@ void Controller_Gesture::EndPanEvent(GestureProperties& gesture, } // End panning without swipe - type = TouchType::Complete; - cur_entry.vel_x = 0; - cur_entry.vel_y = 0; + type = GestureType::Complete; + next_state.vel_x = 0; + next_state.vel_y = 0; force_update = true; } void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture, - GestureProperties& last_gesture_props, TouchType& type) { - auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + GestureProperties& last_gesture_props, GestureType& type) { const auto& last_entry = GetLastGestureEntry(); - type = TouchType::Swipe; + type = GestureType::Swipe; gesture = last_gesture_props; force_update = true; - cur_entry.delta = last_entry.delta; + next_state.delta = last_entry.delta; - if (std::abs(cur_entry.delta.x) > std::abs(cur_entry.delta.y)) { - if (cur_entry.delta.x > 0) { - cur_entry.direction = Direction::Right; + if (std::abs(next_state.delta.x) > std::abs(next_state.delta.y)) { + if (next_state.delta.x > 0) { + next_state.direction = GestureDirection::Right; return; } - cur_entry.direction = Direction::Left; + next_state.direction = GestureDirection::Left; return; } - if (cur_entry.delta.y > 0) { - cur_entry.direction = Direction::Down; + if (next_state.delta.y > 0) { + next_state.direction = GestureDirection::Down; return; } - cur_entry.direction = Direction::Up; -} - -void Controller_Gesture::OnLoadInputDevices() { - touch_mouse_device = Input::CreateDevice<Input::TouchDevice>("engine:emu_window"); - touch_udp_device = Input::CreateDevice<Input::TouchDevice>("engine:cemuhookudp"); - touch_btn_device = Input::CreateDevice<Input::TouchDevice>("engine:touch_from_button"); -} - -std::optional<std::size_t> Controller_Gesture::GetUnusedFingerID() const { - // Dont assign any touch input to a point if disabled - if (!Settings::values.touchscreen.enabled) { - return std::nullopt; - } - std::size_t first_free_id = 0; - while (first_free_id < MAX_POINTS) { - if (!fingers[first_free_id].pressed) { - return first_free_id; - } else { - first_free_id++; - } - } - return std::nullopt; -} - -Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() { - return shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; + next_state.direction = GestureDirection::Up; } const Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() const { - return shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; -} - -std::size_t Controller_Gesture::UpdateTouchInputEvent( - const std::tuple<float, float, bool>& touch_input, std::size_t finger_id) { - const auto& [x, y, pressed] = touch_input; - if (finger_id > MAX_POINTS) { - LOG_ERROR(Service_HID, "Invalid finger id {}", finger_id); - return MAX_POINTS; - } - if (pressed) { - if (finger_id == MAX_POINTS) { - const auto first_free_id = GetUnusedFingerID(); - if (!first_free_id) { - // Invalid finger id do nothing - return MAX_POINTS; - } - finger_id = first_free_id.value(); - fingers[finger_id].pressed = true; - } - fingers[finger_id].pos = {x, y}; - return finger_id; - } - - if (finger_id != MAX_POINTS) { - fingers[finger_id].pressed = false; - } - - return MAX_POINTS; + return gesture_lifo.ReadCurrentEntry().state; } Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() { GestureProperties gesture; - std::array<Finger, MAX_POINTS> active_fingers; + std::array<Core::HID::TouchFinger, MAX_POINTS> active_fingers; const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), [](const auto& finger) { return finger.pressed; }); gesture.active_points = static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter)); for (size_t id = 0; id < gesture.active_points; ++id) { - const auto& [active_x, active_y] = active_fingers[id].pos; + const auto& [active_x, active_y] = active_fingers[id].position; gesture.points[id] = { .x = static_cast<s32>(active_x * Layout::ScreenUndocked::Width), .y = static_cast<s32>(active_y * Layout::ScreenUndocked::Height), diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h index 7e7ae6625..0936a3fa3 100644 --- a/src/core/hle/service/hid/controllers/gesture.h +++ b/src/core/hle/service/hid/controllers/gesture.h @@ -8,13 +8,14 @@ #include "common/bit_field.h" #include "common/common_types.h" #include "common/point.h" -#include "core/frontend/input.h" +#include "core/hid/emulated_console.h" #include "core/hle/service/hid/controllers/controller_base.h" +#include "core/hle/service/hid/ring_lifo.h" namespace Service::HID { class Controller_Gesture final : public ControllerBase { public: - explicit Controller_Gesture(Core::System& system_); + explicit Controller_Gesture(Core::HID::HIDCore& hid_core_); ~Controller_Gesture() override; // Called when the controller is initialized @@ -26,14 +27,12 @@ public: // When the controller is requesting an update for the shared memory void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, size_t size) override; - // Called when input devices should be loaded - void OnLoadInputDevices() override; - private: static constexpr size_t MAX_FINGERS = 16; static constexpr size_t MAX_POINTS = 4; - enum class TouchType : u32 { + // This is nn::hid::GestureType + enum class GestureType : u32 { Idle, // Nothing touching the screen Complete, // Set at the end of a touch event Cancel, // Set when the number of fingers change @@ -46,7 +45,8 @@ private: Rotate, // All points rotating from the midpoint }; - enum class Direction : u32 { + // This is nn::hid::GestureDirection + enum class GestureDirection : u32 { None, Left, Up, @@ -54,51 +54,41 @@ private: Down, }; - struct Attribute { + // This is nn::hid::GestureAttribute + struct GestureAttribute { union { - u32_le raw{}; + u32 raw{}; BitField<4, 1, u32> is_new_touch; BitField<8, 1, u32> is_double_tap; }; }; - static_assert(sizeof(Attribute) == 4, "Attribute is an invalid size"); + static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size"); + // This is nn::hid::GestureState struct GestureState { - s64_le sampling_number; - s64_le sampling_number2; - s64_le detection_count; - TouchType type; - Direction direction; - Common::Point<s32_le> pos; - Common::Point<s32_le> delta; + s64 sampling_number; + s64 detection_count; + GestureType type; + GestureDirection direction; + Common::Point<s32> pos; + Common::Point<s32> delta; f32 vel_x; f32 vel_y; - Attribute attributes; + GestureAttribute attributes; f32 scale; f32 rotation_angle; - s32_le point_count; - std::array<Common::Point<s32_le>, 4> points; - }; - static_assert(sizeof(GestureState) == 0x68, "GestureState is an invalid size"); - - struct SharedMemory { - CommonHeader header; - std::array<GestureState, 17> gesture_states; - }; - static_assert(sizeof(SharedMemory) == 0x708, "SharedMemory is an invalid size"); - - struct Finger { - Common::Point<f32> pos{}; - bool pressed{}; + s32 point_count; + std::array<Common::Point<s32>, 4> points; }; + static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size"); struct GestureProperties { - std::array<Common::Point<s32_le>, MAX_POINTS> points{}; + std::array<Common::Point<s32>, MAX_POINTS> points{}; std::size_t active_points{}; - Common::Point<s32_le> mid_point{}; - s64_le detection_count{}; - u64_le delta_time{}; + Common::Point<s32> mid_point{}; + s64 detection_count{}; + u64 delta_time{}; f32 average_distance{}; f32 angle{}; }; @@ -114,61 +104,48 @@ private: f32 time_difference); // Initializes new gesture - void NewGesture(GestureProperties& gesture, TouchType& type, Attribute& attributes); + void NewGesture(GestureProperties& gesture, GestureType& type, GestureAttribute& attributes); // Updates existing gesture state - void UpdateExistingGesture(GestureProperties& gesture, TouchType& type, f32 time_difference); + void UpdateExistingGesture(GestureProperties& gesture, GestureType& type, f32 time_difference); // Terminates exiting gesture void EndGesture(GestureProperties& gesture, GestureProperties& last_gesture_props, - TouchType& type, Attribute& attributes, f32 time_difference); + GestureType& type, GestureAttribute& attributes, f32 time_difference); // Set current event to a tap event void SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, - TouchType& type, Attribute& attributes); + GestureType& type, GestureAttribute& attributes); // Calculates and set the extra parameters related to a pan event void UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, - TouchType& type, f32 time_difference); + GestureType& type, f32 time_difference); // Terminates the pan event void EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, - TouchType& type, f32 time_difference); + GestureType& type, f32 time_difference); // Set current event to a swipe event void SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, - TouchType& type); - - // Returns an unused finger id, if there is no fingers available std::nullopt is returned. - [[nodiscard]] std::optional<size_t> GetUnusedFingerID() const; + GestureType& type); // Retrieves the last gesture entry, as indicated by shared memory indices. - [[nodiscard]] GestureState& GetLastGestureEntry(); [[nodiscard]] const GestureState& GetLastGestureEntry() const; - /** - * If the touch is new it tries to assign a new finger id, if there is no fingers available no - * changes will be made. Updates the coordinates if the finger id it's already set. If the touch - * ends delays the output by one frame to set the end_touch flag before finally freeing the - * finger id - */ - size_t UpdateTouchInputEvent(const std::tuple<float, float, bool>& touch_input, - size_t finger_id); - // Returns the average distance, angle and middle point of the active fingers GestureProperties GetGestureProperties(); - SharedMemory shared_memory{}; - std::unique_ptr<Input::TouchDevice> touch_mouse_device; - std::unique_ptr<Input::TouchDevice> touch_udp_device; - std::unique_ptr<Input::TouchDevice> touch_btn_device; - std::array<size_t, MAX_FINGERS> mouse_finger_id{}; - std::array<size_t, MAX_FINGERS> keyboard_finger_id{}; - std::array<size_t, MAX_FINGERS> udp_finger_id{}; - std::array<Finger, MAX_POINTS> fingers{}; + // This is nn::hid::detail::GestureLifo + Lifo<GestureState, hid_entry_count> gesture_lifo{}; + static_assert(sizeof(gesture_lifo) == 0x708, "gesture_lifo is an invalid size"); + GestureState next_state{}; + + Core::HID::EmulatedConsole* console; + + std::array<Core::HID::TouchFinger, MAX_POINTS> fingers{}; GestureProperties last_gesture{}; - s64_le last_update_timestamp{}; - s64_le last_tap_timestamp{}; + s64 last_update_timestamp{}; + s64 last_tap_timestamp{}; f32 last_pan_time_difference{}; bool force_update{false}; bool enable_press_and_tap{false}; diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp index c6c620008..9588a6910 100644 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp @@ -6,13 +6,18 @@ #include "common/common_types.h" #include "common/settings.h" #include "core/core_timing.h" +#include "core/hid/emulated_devices.h" +#include "core/hid/hid_core.h" #include "core/hle/service/hid/controllers/keyboard.h" namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; -constexpr u8 KEYS_PER_BYTE = 8; -Controller_Keyboard::Controller_Keyboard(Core::System& system_) : ControllerBase{system_} {} +Controller_Keyboard::Controller_Keyboard(Core::HID::HIDCore& hid_core_) + : ControllerBase{hid_core_} { + emulated_devices = hid_core.GetEmulatedDevices(); +} + Controller_Keyboard::~Controller_Keyboard() = default; void Controller_Keyboard::OnInit() {} @@ -21,51 +26,27 @@ void Controller_Keyboard::OnRelease() {} void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { - shared_memory.header.timestamp = core_timing.GetCPUTicks(); - shared_memory.header.total_entry_count = 17; - if (!IsControllerActivated()) { - shared_memory.header.entry_count = 0; - shared_memory.header.last_entry_index = 0; + keyboard_lifo.buffer_count = 0; + keyboard_lifo.buffer_tail = 0; + std::memcpy(data + SHARED_MEMORY_OFFSET, &keyboard_lifo, sizeof(keyboard_lifo)); return; } - shared_memory.header.entry_count = 16; - - const auto& last_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; - shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; - auto& cur_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; - cur_entry.sampling_number = last_entry.sampling_number + 1; - cur_entry.sampling_number2 = cur_entry.sampling_number; + const auto& last_entry = keyboard_lifo.ReadCurrentEntry().state; + next_state.sampling_number = last_entry.sampling_number + 1; - cur_entry.key.fill(0); if (Settings::values.keyboard_enabled) { - for (std::size_t i = 0; i < keyboard_keys.size(); ++i) { - auto& entry = cur_entry.key[i / KEYS_PER_BYTE]; - entry = static_cast<u8>(entry | (keyboard_keys[i]->GetStatus() << (i % KEYS_PER_BYTE))); - } + const auto& keyboard_state = emulated_devices->GetKeyboard(); + const auto& keyboard_modifier_state = emulated_devices->GetKeyboardModifier(); - using namespace Settings::NativeKeyboard; - - // TODO: Assign the correct key to all modifiers - cur_entry.modifier.control.Assign(keyboard_mods[LeftControl]->GetStatus()); - cur_entry.modifier.shift.Assign(keyboard_mods[LeftShift]->GetStatus()); - cur_entry.modifier.left_alt.Assign(keyboard_mods[LeftAlt]->GetStatus()); - cur_entry.modifier.right_alt.Assign(keyboard_mods[RightAlt]->GetStatus()); - cur_entry.modifier.gui.Assign(0); - cur_entry.modifier.caps_lock.Assign(keyboard_mods[CapsLock]->GetStatus()); - cur_entry.modifier.scroll_lock.Assign(keyboard_mods[ScrollLock]->GetStatus()); - cur_entry.modifier.num_lock.Assign(keyboard_mods[NumLock]->GetStatus()); - cur_entry.modifier.katakana.Assign(0); - cur_entry.modifier.hiragana.Assign(0); + next_state.key = keyboard_state; + next_state.modifier = keyboard_modifier_state; + next_state.attribute.is_connected.Assign(1); } - std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); -} -void Controller_Keyboard::OnLoadInputDevices() { - std::transform(Settings::values.keyboard_keys.begin(), Settings::values.keyboard_keys.end(), - keyboard_keys.begin(), Input::CreateDevice<Input::ButtonDevice>); - std::transform(Settings::values.keyboard_mods.begin(), Settings::values.keyboard_mods.end(), - keyboard_mods.begin(), Input::CreateDevice<Input::ButtonDevice>); + keyboard_lifo.WriteNextEntry(next_state); + std::memcpy(data + SHARED_MEMORY_OFFSET, &keyboard_lifo, sizeof(keyboard_lifo)); } + } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h index 172a80e9c..cf62d3896 100644 --- a/src/core/hle/service/hid/controllers/keyboard.h +++ b/src/core/hle/service/hid/controllers/keyboard.h @@ -8,15 +8,20 @@ #include "common/bit_field.h" #include "common/common_funcs.h" #include "common/common_types.h" -#include "common/settings.h" #include "common/swap.h" -#include "core/frontend/input.h" #include "core/hle/service/hid/controllers/controller_base.h" +#include "core/hle/service/hid/ring_lifo.h" + +namespace Core::HID { +class EmulatedDevices; +struct KeyboardModifier; +struct KeyboardKey; +} // namespace Core::HID namespace Service::HID { class Controller_Keyboard final : public ControllerBase { public: - explicit Controller_Keyboard(Core::System& system_); + explicit Controller_Keyboard(Core::HID::HIDCore& hid_core_); ~Controller_Keyboard() override; // Called when the controller is initialized @@ -28,47 +33,21 @@ public: // When the controller is requesting an update for the shared memory void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; - // Called when input devices should be loaded - void OnLoadInputDevices() override; - private: - struct Modifiers { - union { - u32_le raw{}; - BitField<0, 1, u32> control; - BitField<1, 1, u32> shift; - BitField<2, 1, u32> left_alt; - BitField<3, 1, u32> right_alt; - BitField<4, 1, u32> gui; - BitField<8, 1, u32> caps_lock; - BitField<9, 1, u32> scroll_lock; - BitField<10, 1, u32> num_lock; - BitField<11, 1, u32> katakana; - BitField<12, 1, u32> hiragana; - }; - }; - static_assert(sizeof(Modifiers) == 0x4, "Modifiers is an invalid size"); - + // This is nn::hid::detail::KeyboardState struct KeyboardState { - s64_le sampling_number; - s64_le sampling_number2; - - Modifiers modifier; - std::array<u8, 32> key; + s64 sampling_number; + Core::HID::KeyboardModifier modifier; + Core::HID::KeyboardAttribute attribute; + Core::HID::KeyboardKey key; }; - static_assert(sizeof(KeyboardState) == 0x38, "KeyboardState is an invalid size"); + static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size"); - struct SharedMemory { - CommonHeader header; - std::array<KeyboardState, 17> pad_states; - INSERT_PADDING_BYTES(0x28); - }; - static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size"); - SharedMemory shared_memory{}; + // This is nn::hid::detail::KeyboardLifo + Lifo<KeyboardState, hid_entry_count> keyboard_lifo{}; + static_assert(sizeof(keyboard_lifo) == 0x3D8, "keyboard_lifo is an invalid size"); + KeyboardState next_state{}; - std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeKeyboard::NumKeyboardKeys> - keyboard_keys; - std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeKeyboard::NumKeyboardMods> - keyboard_mods; + Core::HID::EmulatedDevices* emulated_devices; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp index 544a71948..ba79888ae 100644 --- a/src/core/hle/service/hid/controllers/mouse.cpp +++ b/src/core/hle/service/hid/controllers/mouse.cpp @@ -6,12 +6,17 @@ #include "common/common_types.h" #include "core/core_timing.h" #include "core/frontend/emu_window.h" +#include "core/hid/emulated_devices.h" +#include "core/hid/hid_core.h" #include "core/hle/service/hid/controllers/mouse.h" namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400; -Controller_Mouse::Controller_Mouse(Core::System& system_) : ControllerBase{system_} {} +Controller_Mouse::Controller_Mouse(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} { + emulated_devices = hid_core.GetEmulatedDevices(); +} + Controller_Mouse::~Controller_Mouse() = default; void Controller_Mouse::OnInit() {} @@ -19,50 +24,35 @@ void Controller_Mouse::OnRelease() {} void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { - shared_memory.header.timestamp = core_timing.GetCPUTicks(); - shared_memory.header.total_entry_count = 17; - if (!IsControllerActivated()) { - shared_memory.header.entry_count = 0; - shared_memory.header.last_entry_index = 0; + mouse_lifo.buffer_count = 0; + mouse_lifo.buffer_tail = 0; + std::memcpy(data + SHARED_MEMORY_OFFSET, &mouse_lifo, sizeof(mouse_lifo)); return; } - shared_memory.header.entry_count = 16; - auto& last_entry = shared_memory.mouse_states[shared_memory.header.last_entry_index]; - shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; - auto& cur_entry = shared_memory.mouse_states[shared_memory.header.last_entry_index]; + const auto& last_entry = mouse_lifo.ReadCurrentEntry().state; + next_state.sampling_number = last_entry.sampling_number + 1; - cur_entry.sampling_number = last_entry.sampling_number + 1; - cur_entry.sampling_number2 = cur_entry.sampling_number; - - cur_entry.attribute.raw = 0; + next_state.attribute.raw = 0; if (Settings::values.mouse_enabled) { - const auto [px, py, sx, sy] = mouse_device->GetStatus(); - const auto x = static_cast<s32>(px * Layout::ScreenUndocked::Width); - const auto y = static_cast<s32>(py * Layout::ScreenUndocked::Height); - cur_entry.x = x; - cur_entry.y = y; - cur_entry.delta_x = x - last_entry.x; - cur_entry.delta_y = y - last_entry.y; - cur_entry.mouse_wheel_x = sx; - cur_entry.mouse_wheel_y = sy; - cur_entry.attribute.is_connected.Assign(1); - - using namespace Settings::NativeMouseButton; - cur_entry.button.left.Assign(mouse_button_devices[Left]->GetStatus()); - cur_entry.button.right.Assign(mouse_button_devices[Right]->GetStatus()); - cur_entry.button.middle.Assign(mouse_button_devices[Middle]->GetStatus()); - cur_entry.button.forward.Assign(mouse_button_devices[Forward]->GetStatus()); - cur_entry.button.back.Assign(mouse_button_devices[Back]->GetStatus()); + const auto& mouse_button_state = emulated_devices->GetMouseButtons(); + const auto& mouse_position_state = emulated_devices->GetMousePosition(); + const auto& mouse_wheel_state = emulated_devices->GetMouseWheel(); + next_state.attribute.is_connected.Assign(1); + next_state.x = static_cast<s32>(mouse_position_state.x * Layout::ScreenUndocked::Width); + next_state.y = static_cast<s32>(mouse_position_state.y * Layout::ScreenUndocked::Height); + next_state.delta_x = next_state.x - last_entry.x; + next_state.delta_y = next_state.y - last_entry.y; + next_state.delta_wheel_x = mouse_wheel_state.x - last_mouse_wheel_state.x; + next_state.delta_wheel_y = mouse_wheel_state.y - last_mouse_wheel_state.y; + + last_mouse_wheel_state = mouse_wheel_state; + next_state.button = mouse_button_state; } - std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); + mouse_lifo.WriteNextEntry(next_state); + std::memcpy(data + SHARED_MEMORY_OFFSET, &mouse_lifo, sizeof(mouse_lifo)); } -void Controller_Mouse::OnLoadInputDevices() { - mouse_device = Input::CreateDevice<Input::MouseDevice>(Settings::values.mouse_device); - std::transform(Settings::values.mouse_buttons.begin(), Settings::values.mouse_buttons.end(), - mouse_button_devices.begin(), Input::CreateDevice<Input::ButtonDevice>); -} } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h index 3d391a798..7559fc78d 100644 --- a/src/core/hle/service/hid/controllers/mouse.h +++ b/src/core/hle/service/hid/controllers/mouse.h @@ -7,15 +7,20 @@ #include <array> #include "common/bit_field.h" #include "common/common_types.h" -#include "common/settings.h" #include "common/swap.h" -#include "core/frontend/input.h" #include "core/hle/service/hid/controllers/controller_base.h" +#include "core/hle/service/hid/ring_lifo.h" + +namespace Core::HID { +class EmulatedDevices; +struct MouseState; +struct AnalogStickState; +} // namespace Core::HID namespace Service::HID { class Controller_Mouse final : public ControllerBase { public: - explicit Controller_Mouse(Core::System& system_); + explicit Controller_Mouse(Core::HID::HIDCore& hid_core_); ~Controller_Mouse() override; // Called when the controller is initialized @@ -27,53 +32,13 @@ public: // When the controller is requesting an update for the shared memory void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; - // Called when input devices should be loaded - void OnLoadInputDevices() override; - private: - struct Buttons { - union { - u32_le raw{}; - BitField<0, 1, u32> left; - BitField<1, 1, u32> right; - BitField<2, 1, u32> middle; - BitField<3, 1, u32> forward; - BitField<4, 1, u32> back; - }; - }; - static_assert(sizeof(Buttons) == 0x4, "Buttons is an invalid size"); - - struct Attributes { - union { - u32_le raw{}; - BitField<0, 1, u32> transferable; - BitField<1, 1, u32> is_connected; - }; - }; - static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size"); - - struct MouseState { - s64_le sampling_number; - s64_le sampling_number2; - s32_le x; - s32_le y; - s32_le delta_x; - s32_le delta_y; - s32_le mouse_wheel_x; - s32_le mouse_wheel_y; - Buttons button; - Attributes attribute; - }; - static_assert(sizeof(MouseState) == 0x30, "MouseState is an invalid size"); - - struct SharedMemory { - CommonHeader header; - std::array<MouseState, 17> mouse_states; - }; - SharedMemory shared_memory{}; + // This is nn::hid::detail::MouseLifo + Lifo<Core::HID::MouseState, hid_entry_count> mouse_lifo{}; + static_assert(sizeof(mouse_lifo) == 0x350, "mouse_lifo is an invalid size"); + Core::HID::MouseState next_state{}; - std::unique_ptr<Input::MouseDevice> mouse_device; - std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeMouseButton::NumMouseButtons> - mouse_button_devices; + Core::HID::AnalogStickState last_mouse_wheel_state; + Core::HID::EmulatedDevices* emulated_devices; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 196876810..2705e9dcb 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -10,9 +10,9 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "common/settings.h" -#include "core/core.h" #include "core/core_timing.h" -#include "core/frontend/input.h" +#include "core/hid/emulated_controller.h" +#include "core/hid/hid_core.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,120 +20,26 @@ #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, +constexpr std::array<Core::HID::NpadIdType, 10> npad_id_list{ + Core::HID::NpadIdType::Player1, Core::HID::NpadIdType::Player2, Core::HID::NpadIdType::Player3, + Core::HID::NpadIdType::Player4, Core::HID::NpadIdType::Player5, Core::HID::NpadIdType::Player6, + Core::HID::NpadIdType::Player7, Core::HID::NpadIdType::Player8, Core::HID::NpadIdType::Other, + Core::HID::NpadIdType::Handheld, }; -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) { +bool Controller_NPad::IsNpadIdValid(Core::HID::NpadIdType npad_id) { switch (npad_id) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - return npad_id; - case HANDHELD_INDEX: - case NPAD_HANDHELD: - return HANDHELD_INDEX; - case 9: - case NPAD_UNKNOWN: - return 9; - default: - UNIMPLEMENTED_MSG("Unknown npad id {}", npad_id); - return 0; - } -} - -u32 Controller_NPad::IndexToNPad(std::size_t index) { - switch (index) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - return static_cast<u32>(index); - case HANDHELD_INDEX: - return NPAD_HANDHELD; - case 9: - return NPAD_UNKNOWN; - default: - UNIMPLEMENTED_MSG("Unknown npad index {}", index); - return 0; - } -} - -bool Controller_NPad::IsNpadIdValid(u32 npad_id) { - switch (npad_id) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case NPAD_UNKNOWN: - case NPAD_HANDHELD: + case Core::HID::NpadIdType::Player1: + case Core::HID::NpadIdType::Player2: + case Core::HID::NpadIdType::Player3: + case Core::HID::NpadIdType::Player4: + case Core::HID::NpadIdType::Player5: + case Core::HID::NpadIdType::Player6: + case Core::HID::NpadIdType::Player7: + case Core::HID::NpadIdType::Player8: + case Core::HID::NpadIdType::Other: + case Core::HID::NpadIdType::Handheld: return true; default: LOG_ERROR(Service_HID, "Invalid npad id {}", npad_id); @@ -141,305 +47,337 @@ 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.device_index < DeviceIndex::MaxDeviceIndex; +bool Controller_NPad::IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle) { + return IsNpadIdValid(static_cast<Core::HID::NpadIdType>(device_handle.npad_id)) && + device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType && + device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex; } -Controller_NPad::Controller_NPad(Core::System& system_, +bool Controller_NPad::IsDeviceHandleValid(const Core::HID::SixAxisSensorHandle& device_handle) { + return IsNpadIdValid(static_cast<Core::HID::NpadIdType>(device_handle.npad_id)) && + device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType && + device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex; +} + +Controller_NPad::Controller_NPad(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_) - : ControllerBase{system_}, service_context{service_context_} { - latest_vibration_values.fill({DEFAULT_VIBRATION_VALUE, DEFAULT_VIBRATION_VALUE}); + : ControllerBase{hid_core_}, service_context{service_context_} { + for (std::size_t i = 0; i < controller_data.size(); ++i) { + auto& controller = controller_data[i]; + controller.device = hid_core.GetEmulatedControllerByIndex(i); + controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value = + DEFAULT_VIBRATION_VALUE; + controller.vibration[Core::HID::EmulatedDeviceIndex::RightIndex].latest_vibration_value = + DEFAULT_VIBRATION_VALUE; + Core::HID::ControllerUpdateCallback engine_callback{ + .on_change = [this, + i](Core::HID::ControllerTriggerType type) { ControllerUpdate(type, i); }, + .is_npad_service = true, + }; + 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::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(); +void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, + std::size_t controller_idx) { + if (type == Core::HID::ControllerTriggerType::All) { + ControllerUpdate(Core::HID::ControllerTriggerType::Connected, controller_idx); + ControllerUpdate(Core::HID::ControllerTriggerType::Battery, controller_idx); + return; + } + if (controller_idx >= controller_data.size()) { + return; + } + + auto& controller = controller_data[controller_idx]; + const auto is_connected = controller.device->IsConnected(); + const auto npad_type = controller.device->GetNpadStyleIndex(); + const auto npad_id = controller.device->GetNpadIdType(); + switch (type) { + case Core::HID::ControllerTriggerType::Connected: + case Core::HID::ControllerTriggerType::Disconnected: + if (is_connected == controller.is_connected) { + return; + } + UpdateControllerAt(npad_type, npad_id, is_connected); + break; + case Core::HID::ControllerTriggerType::Battery: { + if (!controller.device->IsConnected()) { + return; + } + auto& shared_memory = controller.shared_memory_entry; + 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; + break; + } + default: + break; + } +} + +void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { + auto& controller = GetControllerFromNpadIdType(npad_id); + if (!IsControllerSupported(controller.device->GetNpadStyleIndex())) { return; } - controller.style_set.raw = 0; // Zero out - controller.device_type.raw = 0; - controller.system_properties.raw = 0; + LOG_DEBUG(Service_HID, "Npad connected {}", npad_id); + const auto controller_type = controller.device->GetNpadStyleIndex(); + auto& shared_memory = controller.shared_memory_entry; + if (controller_type == Core::HID::NpadStyleIndex::None) { + controller.styleset_changed_event->GetWritableEvent().Signal(); + return; + } + shared_memory.style_tag.raw = Core::HID::NpadStyleSet::None; + shared_memory.device_type.raw = 0; + shared_memory.system_properties.raw = 0; switch (controller_type) { - case NPadControllerType::None: + case Core::HID::NpadStyleIndex::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::NpadStyleIndex::ProController: + shared_memory.style_tag.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.applet_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::NpadStyleIndex::Handheld: + shared_memory.style_tag.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.system_properties.use_directional_buttons.Assign(1); + shared_memory.assignment_mode = NpadJoyAssignmentMode::Dual; + shared_memory.applet_footer.type = AppletFooterUiType::HandheldJoyConLeftJoyConRight; + break; + case Core::HID::NpadStyleIndex::JoyconDual: + shared_memory.style_tag.joycon_dual.Assign(1); + if (controller.is_dual_left_connected) { + shared_memory.device_type.joycon_left.Assign(1); + shared_memory.system_properties.use_minus.Assign(1); + } + if (controller.is_dual_right_connected) { + shared_memory.device_type.joycon_right.Assign(1); + shared_memory.system_properties.use_plus.Assign(1); + } + shared_memory.system_properties.use_directional_buttons.Assign(1); + shared_memory.system_properties.is_vertical.Assign(1); + shared_memory.assignment_mode = NpadJoyAssignmentMode::Dual; + if (controller.is_dual_left_connected && controller.is_dual_right_connected) { + shared_memory.applet_footer.type = AppletFooterUiType::JoyDual; + } else if (controller.is_dual_left_connected) { + shared_memory.applet_footer.type = AppletFooterUiType::JoyDualLeftOnly; + } else { + shared_memory.applet_footer.type = AppletFooterUiType::JoyDualRightOnly; + } 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::NpadStyleIndex::JoyconLeft: + shared_memory.style_tag.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.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal; 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::NpadStyleIndex::JoyconRight: + shared_memory.style_tag.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.applet_footer.type = AppletFooterUiType::JoyRightHorizontal; 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::NpadStyleIndex::GameCube: + shared_memory.style_tag.gamecube.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::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); + case Core::HID::NpadStyleIndex::Pokeball: + shared_memory.style_tag.palma.Assign(1); + shared_memory.device_type.palma.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::NpadStyleIndex::NES: + shared_memory.style_tag.lark.Assign(1); + shared_memory.device_type.fullkey.Assign(1); + break; + case Core::HID::NpadStyleIndex::SNES: + shared_memory.style_tag.lucia.Assign(1); + shared_memory.device_type.fullkey.Assign(1); + shared_memory.applet_footer.type = AppletFooterUiType::Lucia; + break; + case Core::HID::NpadStyleIndex::N64: + shared_memory.style_tag.lagoon.Assign(1); + shared_memory.device_type.fullkey.Assign(1); + shared_memory.applet_footer.type = AppletFooterUiType::Lagon; + break; + case Core::HID::NpadStyleIndex::SegaGenesis: + shared_memory.style_tag.lager.Assign(1); + shared_memory.device_type.fullkey.Assign(1); + 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; - // 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; + shared_memory.joycon_color.attribute = ColorAttribute::Ok; + shared_memory.joycon_color.left = body_colors.left; + shared_memory.joycon_color.right = body_colors.right; - SignalStyleSetChangedEvent(IndexToNPad(controller_idx)); + // TODO: Investigate when we should report all batery types + 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; + + controller.is_connected = true; + controller.device->Connect(); + SignalStyleSetChangedEvent(npad_id); + WriteEmptyEntry(controller.shared_memory_entry); } void Controller_NPad::OnInit() { - for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) { - styleset_changed_events[i] = - service_context.CreateEvent(fmt::format("npad:NpadStyleSetChanged_{}", i)); - } - if (!IsControllerActivated()) { return; } - OnLoadInputDevices(); - - if (style.raw == 0) { - // We want to support all controllers - style.handheld.Assign(1); - style.joycon_left.Assign(1); - style.joycon_right.Assign(1); - style.joycon_dual.Assign(1); - 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}; - } + 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)); } - // Account for handheld - if (connected_controllers[HANDHELD_INDEX].is_connected) { - connected_controllers[HANDHELD_INDEX].type = NPadControllerType::Handheld; + if (hid_core.GetSupportedStyleTag().raw == Core::HID::NpadStyleSet::None) { + // We want to support all controllers + hid_core.SetSupportedStyleTag({Core::HID::NpadStyleSet::All}); } 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)); + npad_id_list.size() * sizeof(Core::HID::NpadIdType)); + + // Prefill controller buffers + for (auto& controller : controller_data) { + auto& npad = controller.shared_memory_entry; + npad.fullkey_color = { + .attribute = ColorAttribute::NoController, + .fullkey = {}, + }; + npad.joycon_color = { + .attribute = ColorAttribute::NoController, + .left = {}, + .right = {}, + }; + // HW seems to initialize the first 19 entries + for (std::size_t i = 0; i < 19; ++i) { + WriteEmptyEntry(npad); + } + } - 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); + // Connect controllers + for (auto& controller : controller_data) { + const auto& device = controller.device; + if (device->IsConnected()) { + AddNewControllerAt(device->GetNpadStyleIndex(), device->GetNpadIdType()); } } } -void Controller_NPad::OnLoadInputDevices() { - const auto& players = Settings::values.players.GetValue(); +void Controller_NPad::WriteEmptyEntry(NpadInternalState& npad) { + NPadGenericState dummy_pad_state{}; + NpadGcTriggerState dummy_gc_state{}; + dummy_pad_state.sampling_number = npad.fullkey_lifo.ReadCurrentEntry().sampling_number + 1; + npad.fullkey_lifo.WriteNextEntry(dummy_pad_state); + dummy_pad_state.sampling_number = npad.handheld_lifo.ReadCurrentEntry().sampling_number + 1; + npad.handheld_lifo.WriteNextEntry(dummy_pad_state); + dummy_pad_state.sampling_number = npad.joy_dual_lifo.ReadCurrentEntry().sampling_number + 1; + npad.joy_dual_lifo.WriteNextEntry(dummy_pad_state); + dummy_pad_state.sampling_number = npad.joy_left_lifo.ReadCurrentEntry().sampling_number + 1; + npad.joy_left_lifo.WriteNextEntry(dummy_pad_state); + dummy_pad_state.sampling_number = npad.joy_right_lifo.ReadCurrentEntry().sampling_number + 1; + npad.joy_right_lifo.WriteNextEntry(dummy_pad_state); + dummy_pad_state.sampling_number = npad.palma_lifo.ReadCurrentEntry().sampling_number + 1; + npad.palma_lifo.WriteNextEntry(dummy_pad_state); + dummy_pad_state.sampling_number = npad.system_ext_lifo.ReadCurrentEntry().sampling_number + 1; + npad.system_ext_lifo.WriteNextEntry(dummy_pad_state); + dummy_gc_state.sampling_number = npad.gc_trigger_lifo.ReadCurrentEntry().sampling_number + 1; + npad.gc_trigger_lifo.WriteNextEntry(dummy_gc_state); +} - 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); +void Controller_NPad::OnRelease() { + 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(controller.device->GetNpadIdType(), device_idx, {}); } } } -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, {}); - } +void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) { + std::lock_guard lock{mutex}; + auto& controller = GetControllerFromNpadIdType(npad_id); + const auto controller_type = controller.device->GetNpadStyleIndex(); + if (!controller.device->IsConnected()) { + return; } - for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) { - service_context.CloseEvent(styleset_changed_events[i]); + 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::NpadStyleIndex::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; } -} -void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { - std::lock_guard lock{mutex}; + if (controller_type != Core::HID::NpadStyleIndex::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; + } - const auto controller_idx = NPadIdToIndex(npad_id); - const auto controller_type = connected_controllers[controller_idx].type; - if (!connected_controllers[controller_idx].is_connected) { - return; + if (controller_type == Core::HID::NpadStyleIndex::JoyconLeft) { + pad_entry.npad_buttons.left_sl.Assign(button_state.left_sl); + pad_entry.npad_buttons.left_sr.Assign(button_state.left_sr); } - 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); - } - - 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 == 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 == 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 == 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::NpadStyleIndex::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 == Core::HID::NpadStyleIndex::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 +386,136 @@ 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 (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; - } + for (std::size_t i = 0; i < controller_data.size(); ++i) { + auto& controller = controller_data[i]; + auto& npad = controller.shared_memory_entry; - const auto& controller_type = connected_controllers[i].type; + const auto& controller_type = controller.device->GetNpadStyleIndex(); - if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) { + if (controller_type == Core::HID::NpadStyleIndex::None || + !controller.device->IsConnected()) { + // Refresh shared memory + std::memcpy(data + NPAD_OFFSET + (i * sizeof(NpadInternalState)), + &controller.shared_memory_entry, sizeof(NpadInternalState)); 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); + RequestPadStateUpdate(controller.device->GetNpadIdType()); + 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::NpadStyleIndex::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::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::NES: + case Core::HID::NpadStyleIndex::SNES: + case Core::HID::NpadStyleIndex::N64: + case Core::HID::NpadStyleIndex::SegaGenesis: + 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::NpadStyleIndex::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::NpadStyleIndex::JoyconDual: + pad_state.connection_status.raw = 0; + pad_state.connection_status.is_connected.Assign(1); + if (controller.is_dual_left_connected) { + pad_state.connection_status.is_left_connected.Assign(1); + libnx_state.connection_status.is_left_connected.Assign(1); + } + if (controller.is_dual_right_connected) { + pad_state.connection_status.is_right_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::NpadStyleIndex::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::NpadStyleIndex::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::NpadStyleIndex::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::NpadStyleIndex::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<u64>(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 +523,138 @@ 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; - } - - 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, - }; - - 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; + for (std::size_t i = 0; i < controller_data.size(); ++i) { + auto& controller = controller_data[i]; - auto& cur_entry = sixaxis_sensor->sixaxis[sixaxis_sensor->common.last_entry_index]; + const auto& controller_type = controller.device->GetNpadStyleIndex(); - cur_entry.timestamp = last_entry.timestamp + 1; - cur_entry.timestamp2 = cur_entry.timestamp; + if (controller_type == Core::HID::NpadStyleIndex::None || + !controller.device->IsConnected()) { + continue; } - // Try to read sixaxis sensor states - std::array<MotionDevice, 2> motion_devices; - - 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; - } + 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 (controller.sixaxis_sensor_enabled && Settings::values.motion_enabled.GetValue()) { + controller.sixaxis_at_rest = true; + for (std::size_t e = 0; e < motion_state.size(); ++e) { + controller.sixaxis_at_rest = + controller.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::NpadStyleIndex::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::NpadStyleIndex::ProController: + sixaxis_fullkey_state.attribute.raw = 0; + if (controller.sixaxis_sensor_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::NpadStyleIndex::Handheld: + sixaxis_handheld_state.attribute.raw = 0; + if (controller.sixaxis_sensor_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::NpadStyleIndex::JoyconDual: + sixaxis_dual_left_state.attribute.raw = 0; + sixaxis_dual_right_state.attribute.raw = 0; + if (controller.sixaxis_sensor_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 (controller.sixaxis_sensor_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::NpadStyleIndex::JoyconLeft: + sixaxis_left_lifo_state.attribute.raw = 0; + if (controller.sixaxis_sensor_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::NpadStyleIndex::JoyconRight: + sixaxis_right_lifo_state.attribute.raw = 0; + if (controller.sixaxis_sensor_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_handheld_lifo.ReadCurrentEntry().state.sampling_number + 1; + sixaxis_dual_left_state.sampling_number = + npad.sixaxis_dual_left_lifo.ReadCurrentEntry().state.sampling_number + 1; + sixaxis_dual_right_state.sampling_number = + npad.sixaxis_dual_right_lifo.ReadCurrentEntry().state.sampling_number + 1; + sixaxis_left_lifo_state.sampling_number = + npad.sixaxis_left_lifo.ReadCurrentEntry().state.sampling_number + 1; + sixaxis_right_lifo_state.sampling_number = + npad.sixaxis_right_lifo.ReadCurrentEntry().state.sampling_number + 1; + + if (Core::HID::IndexToNpadIdType(i) == Core::HID::NpadIdType::Handheld) { + // This buffer only is updated on handheld on HW + npad.sixaxis_handheld_lifo.WriteNextEntry(sixaxis_handheld_state); + } else { + // Handheld doesn't update this buffer on HW + npad.sixaxis_fullkey_lifo.WriteNextEntry(sixaxis_fullkey_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) { + hid_core.SetSupportedStyleTag(style_set); } -Controller_NPad::NpadStyleSet Controller_NPad::GetSupportedStyleSet() const { - return style; +Core::HID::NpadStyleTag Controller_NPad::GetSupportedStyleSet() const { + return hid_core.GetSupportedStyleTag(); } void Controller_NPad::SetSupportedNpadIdTypes(u8* data, std::size_t length) { @@ -779,11 +673,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 +697,91 @@ Controller_NPad::NpadCommunicationMode Controller_NPad::GetNpadCommunicationMode return communication_mode; } -void Controller_NPad::SetNpadMode(u32 npad_id, NpadAssignments 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; +void Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceType npad_device_type, + NpadJoyAssignmentMode assignment_mode) { + if (!IsNpadIdValid(npad_id)) { + LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); + return; + } + + auto& controller = GetControllerFromNpadIdType(npad_id); + if (controller.shared_memory_entry.assignment_mode != assignment_mode) { + controller.shared_memory_entry.assignment_mode = assignment_mode; + } + + if (!controller.device->IsConnected()) { + return; + } + + if (assignment_mode == NpadJoyAssignmentMode::Dual) { + if (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft) { + DisconnectNpad(npad_id); + controller.is_dual_left_connected = true; + controller.is_dual_right_connected = false; + UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true); + return; + } + if (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight) { + DisconnectNpad(npad_id); + controller.is_dual_left_connected = false; + controller.is_dual_right_connected = true; + UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true); + return; + } + return; + } + + // This is for NpadJoyAssignmentMode::Single + + // Only JoyconDual get affected by this function + if (controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::JoyconDual) { + return; + } + + if (controller.is_dual_left_connected && !controller.is_dual_right_connected) { + DisconnectNpad(npad_id); + UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true); + return; + } + if (!controller.is_dual_left_connected && controller.is_dual_right_connected) { + DisconnectNpad(npad_id); + UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconRight, npad_id, true); + return; + } + + // We have two controllers connected to the same npad_id we need to split them + const auto npad_id_2 = hid_core.GetFirstDisconnectedNpadId(); + auto& controller_2 = GetControllerFromNpadIdType(npad_id_2); + DisconnectNpad(npad_id); + if (npad_device_type == NpadJoyDeviceType::Left) { + UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true); + controller_2.is_dual_left_connected = false; + controller_2.is_dual_right_connected = true; + UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_2, true); + } else { + UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconRight, npad_id, true); + controller_2.is_dual_left_connected = true; + controller_2.is_dual_right_connected = false; + UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_2, true); } } -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]) { +bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, + std::size_t device_index, + const Core::HID::VibrationValue& vibration_value) { + auto& controller = GetControllerFromNpadIdType(npad_id); + 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.low_amplitude != 0.0f || + controller.vibration[device_index].latest_vibration_value.high_amplitude != 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; @@ -839,27 +795,25 @@ bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index, std::size const auto now = steady_clock::now(); // 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]) < + if ((vibration_value.low_amplitude != 0.0f || vibration_value.high_amplitude != 0.0f) && + 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.low_amplitude, vibration_value.low_frequency, + vibration_value.high_amplitude, vibration_value.high_frequency}; + return controller.device->SetVibration(device_index, vibration); } -void Controller_NPad::VibrateController(const DeviceHandle& vibration_device_handle, - const VibrationValue& vibration_value) { +void Controller_NPad::VibrateController( + const Core::HID::VibrationDeviceHandle& vibration_device_handle, + const Core::HID::VibrationValue& vibration_value) { if (!IsDeviceHandleValid(vibration_device_handle)) { return; } @@ -868,42 +822,45 @@ void Controller_NPad::VibrateController(const DeviceHandle& vibration_device_han return; } - const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); + auto& controller = GetControllerFromHandle(vibration_device_handle); 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; } - if (vibration_device_handle.device_index == DeviceIndex::None) { + if (vibration_device_handle.device_index == Core::HID::DeviceIndex::None) { UNREACHABLE_MSG("DeviceIndex should never be None!"); return; } // 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 || - vibration_device_handle.device_index == DeviceIndex::Right)) || - (connected_controllers[npad_index].type == NPadControllerType::JoyRight && - (vibration_device_handle.npad_type == NpadType::JoyconLeft || - vibration_device_handle.device_index == DeviceIndex::Left))) { + if ((controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft && + (vibration_device_handle.npad_type == Core::HID::NpadStyleIndex::JoyconRight || + vibration_device_handle.device_index == Core::HID::DeviceIndex::Right)) || + (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight && + (vibration_device_handle.npad_type == Core::HID::NpadStyleIndex::JoyconLeft || + vibration_device_handle.device_index == Core::HID::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.low_amplitude == + controller.vibration[device_index].latest_vibration_value.low_amplitude && + vibration_value.high_amplitude == + controller.vibration[device_index].latest_vibration_value.high_amplitude) { return; } - if (VibrateControllerAtIndex(npad_index, device_index, vibration_value)) { - latest_vibration_values[npad_index][device_index] = vibration_value; + if (VibrateControllerAtIndex(controller.device->GetNpadIdType(), device_index, + vibration_value)) { + controller.vibration[device_index].latest_vibration_value = vibration_value; } } -void Controller_NPad::VibrateControllers(const std::vector<DeviceHandle>& vibration_device_handles, - const std::vector<VibrationValue>& vibration_values) { +void Controller_NPad::VibrateControllers( + const std::vector<Core::HID::VibrationDeviceHandle>& vibration_device_handles, + const std::vector<Core::HID::VibrationValue>& vibration_values) { if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) { return; } @@ -918,168 +875,285 @@ void Controller_NPad::VibrateControllers(const std::vector<DeviceHandle>& vibrat } } -Controller_NPad::VibrationValue Controller_NPad::GetLastVibration( - const DeviceHandle& vibration_device_handle) const { +Core::HID::VibrationValue Controller_NPad::GetLastVibration( + const Core::HID::VibrationDeviceHandle& vibration_device_handle) const { if (!IsDeviceHandleValid(vibration_device_handle)) { return {}; } - const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); + const auto& controller = GetControllerFromHandle(vibration_device_handle); 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) { +void Controller_NPad::InitializeVibrationDevice( + const Core::HID::VibrationDeviceHandle& vibration_device_handle) { if (!IsDeviceHandleValid(vibration_device_handle)) { return; } - const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); + const auto npad_index = static_cast<Core::HID::NpadIdType>(vibration_device_handle.npad_id); const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); InitializeVibrationDeviceAtIndex(npad_index, device_index); } -void Controller_NPad::InitializeVibrationDeviceAtIndex(std::size_t npad_index, +void Controller_NPad::InitializeVibrationDeviceAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index) { + auto& controller = GetControllerFromNpadIdType(npad_id); 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); } void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) { permit_vibration_session_enabled = permit_vibration_session; } -bool Controller_NPad::IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const { +bool Controller_NPad::IsVibrationDeviceMounted( + const Core::HID::VibrationDeviceHandle& vibration_device_handle) const { if (!IsDeviceHandleValid(vibration_device_handle)) { return false; } - const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); + const auto& controller = GetControllerFromHandle(vibration_device_handle); 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(); +Kernel::KReadableEvent& Controller_NPad::GetStyleSetChangedEvent(Core::HID::NpadIdType npad_id) { + if (!IsNpadIdValid(npad_id)) { + LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); + // Fallback to player 1 + const auto& controller = GetControllerFromNpadIdType(Core::HID::NpadIdType::Player1); + return controller.styleset_changed_event->GetReadableEvent(); + } + + const auto& controller = GetControllerFromNpadIdType(npad_id); + return controller.styleset_changed_event->GetReadableEvent(); } -void Controller_NPad::SignalStyleSetChangedEvent(u32 npad_id) const { - styleset_changed_events[NPadIdToIndex(npad_id)]->GetWritableEvent().Signal(); +void Controller_NPad::SignalStyleSetChangedEvent(Core::HID::NpadIdType npad_id) const { + const auto& controller = GetControllerFromNpadIdType(npad_id); + controller.styleset_changed_event->GetWritableEvent().Signal(); } -void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::size_t npad_index) { - UpdateControllerAt(controller, npad_index, true); +void Controller_NPad::AddNewControllerAt(Core::HID::NpadStyleIndex controller, + Core::HID::NpadIdType npad_id) { + UpdateControllerAt(controller, npad_id, true); } -void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, - bool connected) { +void Controller_NPad::UpdateControllerAt(Core::HID::NpadStyleIndex type, + Core::HID::NpadIdType npad_id, bool connected) { + auto& controller = GetControllerFromNpadIdType(npad_id); 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); + DisconnectNpad(npad_id); 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}; - InitNewlyAddedController(npad_index); + controller.device->SetNpadStyleIndex(type); + InitNewlyAddedController(npad_id); } -void Controller_NPad::DisconnectNpad(u32 npad_id) { - DisconnectNpadAtIndex(NPadIdToIndex(npad_id)); -} +void Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) { + if (!IsNpadIdValid(npad_id)) { + LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); + return; + } -void Controller_NPad::DisconnectNpadAtIndex(std::size_t npad_index) { - for (std::size_t device_idx = 0; device_idx < vibrations[npad_index].size(); ++device_idx) { + LOG_DEBUG(Service_HID, "Npad disconnected {}", npad_id); + auto& controller = GetControllerFromNpadIdType(npad_id); + 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; + VibrateControllerAtIndex(npad_id, device_idx, {}); + 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; + auto& shared_memory_entry = controller.shared_memory_entry; + // Don't reset shared_memory_entry.assignment_mode this value is persistent + shared_memory_entry.style_tag.raw = Core::HID::NpadStyleSet::None; // 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 = { + .attribute = ColorAttribute::NoController, + .fullkey = {}, + }; + shared_memory_entry.joycon_color = { + .attribute = ColorAttribute::NoController, + .left = {}, + .right = {}, + }; + shared_memory_entry.applet_footer.type = AppletFooterUiType::None; + + controller.is_dual_left_connected = true; + controller.is_dual_right_connected = true; + controller.is_connected = false; + controller.device->Disconnect(); + SignalStyleSetChangedEvent(npad_id); + WriteEmptyEntry(controller.shared_memory_entry); +} - SignalStyleSetChangedEvent(IndexToNPad(npad_index)); +void Controller_NPad::SetGyroscopeZeroDriftMode(Core::HID::SixAxisSensorHandle sixaxis_handle, + GyroscopeZeroDriftMode drift_mode) { + if (!IsDeviceHandleValid(sixaxis_handle)) { + LOG_ERROR(Service_HID, "Invalid handle"); + return; + } + auto& controller = GetControllerFromHandle(sixaxis_handle); + controller.gyroscope_zero_drift_mode = drift_mode; } -void Controller_NPad::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode) { - gyroscope_zero_drift_mode = drift_mode; +Controller_NPad::GyroscopeZeroDriftMode Controller_NPad::GetGyroscopeZeroDriftMode( + Core::HID::SixAxisSensorHandle sixaxis_handle) const { + if (!IsDeviceHandleValid(sixaxis_handle)) { + LOG_ERROR(Service_HID, "Invalid handle"); + // Return the default value + return GyroscopeZeroDriftMode::Standard; + } + const auto& controller = GetControllerFromHandle(sixaxis_handle); + return controller.gyroscope_zero_drift_mode; } -Controller_NPad::GyroscopeZeroDriftMode Controller_NPad::GetGyroscopeZeroDriftMode() const { - return gyroscope_zero_drift_mode; +bool Controller_NPad::IsSixAxisSensorAtRest(Core::HID::SixAxisSensorHandle sixaxis_handle) const { + if (!IsDeviceHandleValid(sixaxis_handle)) { + LOG_ERROR(Service_HID, "Invalid handle"); + // Return the default value + return true; + } + const auto& controller = GetControllerFromHandle(sixaxis_handle); + return controller.sixaxis_at_rest; } -bool Controller_NPad::IsSixAxisSensorAtRest() const { - return sixaxis_at_rest; +void Controller_NPad::SetSixAxisEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle, + bool sixaxis_status) { + if (!IsDeviceHandleValid(sixaxis_handle)) { + LOG_ERROR(Service_HID, "Invalid handle"); + return; + } + auto& controller = GetControllerFromHandle(sixaxis_handle); + controller.sixaxis_sensor_enabled = sixaxis_status; } -void Controller_NPad::SetSixAxisEnabled(bool six_axis_status) { - sixaxis_sensors_enabled = six_axis_status; +void Controller_NPad::SetSixAxisFusionEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle, + bool sixaxis_fusion_status) { + if (!IsDeviceHandleValid(sixaxis_handle)) { + LOG_ERROR(Service_HID, "Invalid handle"); + return; + } + auto& controller = GetControllerFromHandle(sixaxis_handle); + controller.sixaxis_fusion_enabled = sixaxis_fusion_status; } -void Controller_NPad::SetSixAxisFusionParameters(f32 parameter1, f32 parameter2) { - sixaxis_fusion_parameter1 = parameter1; - sixaxis_fusion_parameter2 = parameter2; +void Controller_NPad::SetSixAxisFusionParameters( + Core::HID::SixAxisSensorHandle sixaxis_handle, + Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters) { + if (!IsDeviceHandleValid(sixaxis_handle)) { + LOG_ERROR(Service_HID, "Invalid handle"); + return; + } + auto& controller = GetControllerFromHandle(sixaxis_handle); + controller.sixaxis_fusion = sixaxis_fusion_parameters; } -std::pair<f32, f32> Controller_NPad::GetSixAxisFusionParameters() { - return { - sixaxis_fusion_parameter1, - sixaxis_fusion_parameter2, - }; +Core::HID::SixAxisSensorFusionParameters Controller_NPad::GetSixAxisFusionParameters( + Core::HID::SixAxisSensorHandle sixaxis_handle) { + if (!IsDeviceHandleValid(sixaxis_handle)) { + LOG_ERROR(Service_HID, "Invalid handle"); + // Since these parameters are unknow just return zeros + return {}; + } + auto& controller = GetControllerFromHandle(sixaxis_handle); + return controller.sixaxis_fusion; } -void Controller_NPad::ResetSixAxisFusionParameters() { - sixaxis_fusion_parameter1 = 0.0f; - sixaxis_fusion_parameter2 = 0.0f; +void Controller_NPad::ResetSixAxisFusionParameters(Core::HID::SixAxisSensorHandle sixaxis_handle) { + if (!IsDeviceHandleValid(sixaxis_handle)) { + LOG_ERROR(Service_HID, "Invalid handle"); + return; + } + auto& controller = GetControllerFromHandle(sixaxis_handle); + // Since these parameters are unknow just fill with zeros + controller.sixaxis_fusion = {}; } -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); +void Controller_NPad::MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, + Core::HID::NpadIdType npad_id_2) { + if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) { + LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1, + npad_id_2); + return; + } + auto& controller_1 = GetControllerFromNpadIdType(npad_id_1); + auto& controller_2 = GetControllerFromNpadIdType(npad_id_2); + const auto controller_style_1 = controller_1.device->GetNpadStyleIndex(); + const auto controller_style_2 = controller_2.device->GetNpadStyleIndex(); + bool merge_controllers = false; // 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_style_1 == Core::HID::NpadStyleIndex::JoyconLeft && + controller_style_2 == Core::HID::NpadStyleIndex::JoyconRight) { + merge_controllers = true; + } + if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconLeft && + controller_style_1 == Core::HID::NpadStyleIndex::JoyconRight) { + merge_controllers = true; + } + if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual && + controller_style_2 == Core::HID::NpadStyleIndex::JoyconRight && + controller_1.is_dual_left_connected && !controller_1.is_dual_right_connected) { + merge_controllers = true; + } + if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual && + controller_style_2 == Core::HID::NpadStyleIndex::JoyconLeft && + !controller_1.is_dual_left_connected && controller_1.is_dual_right_connected) { + merge_controllers = true; + } + if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual && + controller_style_1 == Core::HID::NpadStyleIndex::JoyconRight && + controller_2.is_dual_left_connected && !controller_2.is_dual_right_connected) { + merge_controllers = true; + } + if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual && + controller_style_1 == Core::HID::NpadStyleIndex::JoyconLeft && + !controller_2.is_dual_left_connected && controller_2.is_dual_right_connected) { + merge_controllers = true; + } + if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual && + controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual && + controller_1.is_dual_left_connected && !controller_1.is_dual_right_connected && + !controller_2.is_dual_left_connected && controller_2.is_dual_right_connected) { + merge_controllers = true; + } + if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual && + controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual && + !controller_1.is_dual_left_connected && controller_1.is_dual_right_connected && + controller_2.is_dual_left_connected && !controller_2.is_dual_right_connected) { + merge_controllers = true; + } + + if (merge_controllers) { // 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); + controller_1.is_dual_left_connected = true; + controller_1.is_dual_right_connected = true; + AddNewControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_1); + return; } + LOG_WARNING(Service_HID, + "Controllers can't be merged npad_id_1:{}, npad_id_2:{}, type_1:{}, type_2:{}, " + "dual_1(left/right):{}/{}, dual_2(left/right):{}/{}", + npad_id_1, npad_id_2, controller_1.device->GetNpadStyleIndex(), + controller_2.device->GetNpadStyleIndex(), controller_1.is_dual_left_connected, + controller_1.is_dual_right_connected, controller_2.is_dual_left_connected, + controller_2.is_dual_right_connected); } void Controller_NPad::StartLRAssignmentMode() { @@ -1092,61 +1166,66 @@ void Controller_NPad::StopLRAssignmentMode() { is_in_lr_assignment_mode = false; } -bool Controller_NPad::SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2) { - if (npad_id_1 == NPAD_HANDHELD || npad_id_2 == NPAD_HANDHELD || npad_id_1 == NPAD_UNKNOWN || - npad_id_2 == NPAD_UNKNOWN) { +bool Controller_NPad::SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, + Core::HID::NpadIdType npad_id_2) { + if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) { + LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1, + npad_id_2); + return false; + } + if (npad_id_1 == Core::HID::NpadIdType::Handheld || + npad_id_2 == Core::HID::NpadIdType::Handheld || npad_id_1 == Core::HID::NpadIdType::Other || + npad_id_2 == Core::HID::NpadIdType::Other) { return true; } - const auto npad_index_1 = NPadIdToIndex(npad_id_1); - const auto npad_index_2 = NPadIdToIndex(npad_id_2); - - if (!IsControllerSupported(connected_controllers[npad_index_1].type) || - !IsControllerSupported(connected_controllers[npad_index_2].type)) { + const auto& controller_1 = GetControllerFromNpadIdType(npad_id_1).device; + const auto& controller_2 = GetControllerFromNpadIdType(npad_id_2).device; + const auto type_index_1 = controller_1->GetNpadStyleIndex(); + const auto type_index_2 = controller_2->GetNpadStyleIndex(); + const auto is_connected_1 = controller_1->IsConnected(); + const auto is_connected_2 = controller_2->IsConnected(); + + if (!IsControllerSupported(type_index_1) && is_connected_1) { + return false; + } + if (!IsControllerSupported(type_index_2) && is_connected_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); + UpdateControllerAt(type_index_2, npad_id_1, is_connected_2); + UpdateControllerAt(type_index_1, npad_id_2, is_connected_1); return true; } -Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) { - if (npad_id == npad_id_list.back() || npad_id == npad_id_list[npad_id_list.size() - 2]) { - // These are controllers without led patterns - return LedPattern{0, 0, 0, 0}; - } - switch (npad_id) { - case 0: - return LedPattern{1, 0, 0, 0}; - case 1: - return LedPattern{1, 1, 0, 0}; - case 2: - return LedPattern{1, 1, 1, 0}; - case 3: - return LedPattern{1, 1, 1, 1}; - case 4: - return LedPattern{1, 0, 0, 1}; - case 5: - return LedPattern{1, 0, 1, 0}; - case 6: - return LedPattern{1, 0, 1, 1}; - case 7: - return LedPattern{0, 1, 1, 0}; - default: - return LedPattern{0, 0, 0, 0}; +Core::HID::LedPattern Controller_NPad::GetLedPattern(Core::HID::NpadIdType npad_id) { + if (!IsNpadIdValid(npad_id)) { + LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); + return Core::HID::LedPattern{0, 0, 0, 0}; } + const auto& controller = GetControllerFromNpadIdType(npad_id).device; + return controller->GetLedPattern(); } -bool Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const { - return unintended_home_button_input_protection[NPadIdToIndex(npad_id)]; +bool Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled( + Core::HID::NpadIdType npad_id) const { + if (!IsNpadIdValid(npad_id)) { + LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); + // Return the default value + return false; + } + const auto& controller = GetControllerFromNpadIdType(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; + Core::HID::NpadIdType npad_id) { + if (!IsNpadIdValid(npad_id)) { + LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); + return; + } + auto& controller = GetControllerFromNpadIdType(npad_id); + controller.unintended_home_button_input_protection = is_protection_enabled; } void Controller_NPad::SetAnalogStickUseCenterClamp(bool use_center_clamp) { @@ -1154,49 +1233,51 @@ 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->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::None) { + controller.device->Disconnect(); + controller.device->SetNpadStyleIndex(Core::HID::NpadStyleIndex::None); } } } 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->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::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->Disconnect(); + controller.device->SetNpadStyleIndex(Core::HID::NpadStyleIndex::None); } } -u32 Controller_NPad::GetAndResetPressState() { - return press_state.exchange(0); +Core::HID::NpadButton Controller_NPad::GetAndResetPressState() { + return static_cast<Core::HID::NpadButton>(press_state.exchange(0)); } -bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const { - if (controller == NPadControllerType::Handheld) { +bool Controller_NPad::IsControllerSupported(Core::HID::NpadStyleIndex controller) const { + if (controller == Core::HID::NpadStyleIndex::Handheld) { const bool support_handheld = std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), - NPAD_HANDHELD) != supported_npad_id_types.end(); + Core::HID::NpadIdType::Handheld) != supported_npad_id_types.end(); // Handheld is not even a supported type, lets stop here 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; } @@ -1205,20 +1286,31 @@ 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::NpadIdType npad_id) { + return npad_id <= Core::HID::NpadIdType::Player8; + })) { + Core::HID::NpadStyleTag style = GetSupportedStyleSet(); switch (controller) { - case NPadControllerType::ProController: + case Core::HID::NpadStyleIndex::ProController: return style.fullkey; - case NPadControllerType::JoyDual: + case Core::HID::NpadStyleIndex::JoyconDual: return style.joycon_dual; - case NPadControllerType::JoyLeft: + case Core::HID::NpadStyleIndex::JoyconLeft: return style.joycon_left; - case NPadControllerType::JoyRight: + case Core::HID::NpadStyleIndex::JoyconRight: return style.joycon_right; - case NPadControllerType::GameCube: + case Core::HID::NpadStyleIndex::GameCube: return style.gamecube; - case NPadControllerType::Pokeball: + case Core::HID::NpadStyleIndex::Pokeball: return style.palma; + case Core::HID::NpadStyleIndex::NES: + return style.lark; + case Core::HID::NpadStyleIndex::SNES: + return style.lucia; + case Core::HID::NpadStyleIndex::N64: + return style.lagoon; + case Core::HID::NpadStyleIndex::SegaGenesis: + return style.lager; default: return false; } @@ -1227,4 +1319,48 @@ bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const return false; } +Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromHandle( + const Core::HID::SixAxisSensorHandle& device_handle) { + const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); + return GetControllerFromNpadIdType(npad_id); +} + +const Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromHandle( + const Core::HID::SixAxisSensorHandle& device_handle) const { + const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); + return GetControllerFromNpadIdType(npad_id); +} + +Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromHandle( + const Core::HID::VibrationDeviceHandle& device_handle) { + const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); + return GetControllerFromNpadIdType(npad_id); +} + +const Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromHandle( + const Core::HID::VibrationDeviceHandle& device_handle) const { + const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); + return GetControllerFromNpadIdType(npad_id); +} + +Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromNpadIdType( + Core::HID::NpadIdType npad_id) { + if (!IsNpadIdValid(npad_id)) { + LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); + npad_id = Core::HID::NpadIdType::Player1; + } + const auto npad_index = Core::HID::NpadIdTypeToIndex(npad_id); + return controller_data[npad_index]; +} + +const Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromNpadIdType( + Core::HID::NpadIdType npad_id) const { + if (!IsNpadIdValid(npad_id)) { + LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); + npad_id = Core::HID::NpadIdType::Player1; + } + const auto npad_index = Core::HID::NpadIdTypeToIndex(npad_id); + return controller_data[npad_index]; +} + } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 9ee146caf..63281cb35 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -11,9 +11,14 @@ #include "common/bit_field.h" #include "common/common_types.h" #include "common/quaternion.h" -#include "common/settings.h" -#include "core/frontend/input.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 Core::HID { +class EmulatedController; +enum class ControllerTriggerType; +} // namespace Core::HID namespace Kernel { class KEvent; @@ -26,12 +31,9 @@ class ServiceContext; namespace Service::HID { -constexpr u32 NPAD_HANDHELD = 32; -constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this? - class Controller_NPad final : public ControllerBase { public: - explicit Controller_NPad(Core::System& system_, + explicit Controller_NPad(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_); ~Controller_NPad() override; @@ -48,60 +50,39 @@ 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, - None = 2, - 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::NpadJoyDeviceType + enum class NpadJoyDeviceType : s64 { + Left = 0, + Right = 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, @@ -109,74 +90,22 @@ public: Default = 3, }; - struct DeviceHandle { - NpadType npad_type; - u8 npad_id; - DeviceIndex device_index; - INSERT_PADDING_BYTES_NOINIT(1); + static constexpr Core::HID::VibrationValue DEFAULT_VIBRATION_VALUE{ + .low_amplitude = 0.0f, + .low_frequency = 160.0f, + .high_amplitude = 0.0f, + .high_frequency = 320.0f, }; - 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"); - - struct VibrationValue { - f32 amp_low; - f32 freq_low; - f32 amp_high; - f32 freq_high; - }; - static_assert(sizeof(VibrationValue) == 0x10, "Vibration is an invalid size"); - - static constexpr VibrationValue DEFAULT_VIBRATION_VALUE{ - .amp_low = 0.0f, - .freq_low = 160.0f, - .amp_high = 0.0f, - .freq_high = 320.0f, - }; - - struct LedPattern { - explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) { - position1.Assign(light1); - position2.Assign(light2); - position3.Assign(light3); - position4.Assign(light4); - } - union { - u64 raw{}; - BitField<0, 1, u64> position1; - BitField<1, 1, u64> position2; - BitField<2, 1, u64> position3; - BitField<3, 1, u64> position4; - }; - }; - - 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,162 +113,107 @@ public: void SetNpadCommunicationMode(NpadCommunicationMode communication_mode_); NpadCommunicationMode GetNpadCommunicationMode() const; - void SetNpadMode(u32 npad_id, NpadAssignments assignment_mode); + void SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceType npad_device_type, + NpadJoyAssignmentMode assignment_mode); - bool VibrateControllerAtIndex(std::size_t npad_index, std::size_t device_index, - const VibrationValue& vibration_value); + bool VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index, + const Core::HID::VibrationValue& vibration_value); - void VibrateController(const DeviceHandle& vibration_device_handle, - const VibrationValue& vibration_value); + void VibrateController(const Core::HID::VibrationDeviceHandle& vibration_device_handle, + const Core::HID::VibrationValue& vibration_value); - void VibrateControllers(const std::vector<DeviceHandle>& vibration_device_handles, - const std::vector<VibrationValue>& vibration_values); + void VibrateControllers( + const std::vector<Core::HID::VibrationDeviceHandle>& vibration_device_handles, + const std::vector<Core::HID::VibrationValue>& vibration_values); - VibrationValue GetLastVibration(const DeviceHandle& vibration_device_handle) const; + Core::HID::VibrationValue GetLastVibration( + const Core::HID::VibrationDeviceHandle& vibration_device_handle) const; - void InitializeVibrationDevice(const DeviceHandle& vibration_device_handle); + void InitializeVibrationDevice(const Core::HID::VibrationDeviceHandle& vibration_device_handle); - void InitializeVibrationDeviceAtIndex(std::size_t npad_index, std::size_t device_index); + void InitializeVibrationDeviceAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index); void SetPermitVibrationSession(bool permit_vibration_session); - bool IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const; + bool IsVibrationDeviceMounted( + const Core::HID::VibrationDeviceHandle& vibration_device_handle) const; - Kernel::KReadableEvent& GetStyleSetChangedEvent(u32 npad_id); - void SignalStyleSetChangedEvent(u32 npad_id) const; + Kernel::KReadableEvent& GetStyleSetChangedEvent(Core::HID::NpadIdType npad_id); + void SignalStyleSetChangedEvent(Core::HID::NpadIdType npad_id) const; // Adds a new controller at an index. - void AddNewControllerAt(NPadControllerType controller, std::size_t npad_index); + void AddNewControllerAt(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id); // Adds a new controller at an index with connection status. - void UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, bool connected); - - void DisconnectNpad(u32 npad_id); - void DisconnectNpadAtIndex(std::size_t index); - - void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode); - GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const; - bool IsSixAxisSensorAtRest() const; - void SetSixAxisEnabled(bool six_axis_status); - void SetSixAxisFusionParameters(f32 parameter1, f32 parameter2); - std::pair<f32, f32> GetSixAxisFusionParameters(); - void ResetSixAxisFusionParameters(); - LedPattern GetLedPattern(u32 npad_id); - bool IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const; - void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, u32 npad_id); + void UpdateControllerAt(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id, + bool connected); + + void DisconnectNpad(Core::HID::NpadIdType npad_id); + + void SetGyroscopeZeroDriftMode(Core::HID::SixAxisSensorHandle sixaxis_handle, + GyroscopeZeroDriftMode drift_mode); + GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode( + Core::HID::SixAxisSensorHandle sixaxis_handle) const; + bool IsSixAxisSensorAtRest(Core::HID::SixAxisSensorHandle sixaxis_handle) const; + void SetSixAxisEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle, bool sixaxis_status); + void SetSixAxisFusionEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle, + bool sixaxis_fusion_status); + void SetSixAxisFusionParameters( + Core::HID::SixAxisSensorHandle sixaxis_handle, + Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters); + Core::HID::SixAxisSensorFusionParameters GetSixAxisFusionParameters( + Core::HID::SixAxisSensorHandle sixaxis_handle); + void ResetSixAxisFusionParameters(Core::HID::SixAxisSensorHandle sixaxis_handle); + Core::HID::LedPattern GetLedPattern(Core::HID::NpadIdType npad_id); + bool IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id) const; + void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, + Core::HID::NpadIdType npad_id); void SetAnalogStickUseCenterClamp(bool use_center_clamp); void ClearAllConnectedControllers(); void DisconnectAllConnectedControllers(); void ConnectAllDisconnectedControllers(); void ClearAllControllers(); - void MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2); + void MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2); void StartLRAssignmentMode(); void StopLRAssignmentMode(); - bool SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2); + bool SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2); // Logical OR for all buttons presses on all controllers // Specifically for cheat engine and other features. - u32 GetAndResetPressState(); + Core::HID::NpadButton 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); + static bool IsNpadIdValid(Core::HID::NpadIdType npad_id); + static bool IsDeviceHandleValid(const Core::HID::SixAxisSensorHandle& device_handle); + static bool IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& 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 { Ok = 0, ReadError = 1, NoController = 2, }; - static_assert(sizeof(ColorAttributes) == 4, "ColorAttributes is an invalid size"); + static_assert(sizeof(ColorAttribute) == 4, "ColorAttribute is an invalid size"); - struct ControllerColor { - u32_le body; - u32_le button; + // This is nn::hid::detail::NpadFullKeyColorState + struct NpadFullKeyColorState { + ColorAttribute attribute; + Core::HID::NpadControllerColor fullkey; }; - static_assert(sizeof(ControllerColor) == 8, "ControllerColor is an invalid size"); + static_assert(sizeof(NpadFullKeyColorState) == 0xC, "NpadFullKeyColorState is an invalid size"); - struct FullKeyColor { - ColorAttributes attribute; - ControllerColor fullkey; + // This is nn::hid::detail::NpadJoyColorState + struct NpadJoyColorState { + ColorAttribute attribute; + Core::HID::NpadControllerColor left; + Core::HID::NpadControllerColor right; }; - static_assert(sizeof(FullKeyColor) == 0xC, "FullKeyColor is an invalid size"); + static_assert(sizeof(NpadJoyColorState) == 0x14, "NpadJoyColorState is an invalid size"); - struct JoyconColor { - ColorAttributes attribute; - ControllerColor left; - ControllerColor right; - }; - static_assert(sizeof(JoyconColor) == 0x14, "JoyconColor 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; - }; - }; - static_assert(sizeof(ControllerPadState) == 8, "ControllerPadState is an invalid size"); - - struct AnalogPosition { - s32_le x; - s32_le y; - }; - static_assert(sizeof(AnalogPosition) == 8, "AnalogPosition is an invalid size"); - - struct ConnectionState { + // This is nn::hid::NpadAttribute + struct NpadAttribute { union { - u32_le raw{}; + u32 raw{}; BitField<0, 1, u32> is_connected; BitField<1, 1, u32> is_wired; BitField<2, 1, u32> is_left_connected; @@ -348,79 +222,60 @@ 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{}; + u32 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 delta_time{}; + s64 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{}; - s32_le l_analog{}; - s32_le r_analog{}; + // This is nn::hid::server::NpadGcTriggerState + struct NpadGcTriggerState { + s64 sampling_number{}; + s32 l_analog{}; + s32 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{}; + s64 raw{}; BitField<0, 1, s64> is_charging_joy_dual; BitField<1, 1, s64> is_charging_joy_left; BitField<2, 1, s64> is_charging_joy_right; @@ -438,17 +293,20 @@ private: }; static_assert(sizeof(NPadSystemProperties) == 0x8, "NPadSystemProperties is an invalid size"); - struct NPadButtonProperties { + // This is nn::hid::NpadSystemButtonProperties + struct NpadSystemButtonProperties { union { - s32_le raw{}; + s32 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{}; + u32 raw{}; BitField<0, 1, s32> fullkey; BitField<1, 1, s32> debug_pad; BitField<2, 1, s32> handheld_left; @@ -465,26 +323,29 @@ private: BitField<13, 1, s32> handheld_lark_nes_left; BitField<14, 1, s32> handheld_lark_nes_right; BitField<15, 1, s32> lucia; + BitField<16, 1, s32> lagon; + BitField<17, 1, s32> lager; BitField<31, 1, s32> system; }; }; - 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); + // This is nn::hid::detail::NfcXcdDeviceHandleStateImpl + struct NfcXcdDeviceHandleStateImpl { + u64 handle; + bool is_available; + bool is_activated; + INSERT_PADDING_BYTES(0x6); // Reserved + u64 sampling_number; }; + static_assert(sizeof(NfcXcdDeviceHandleStateImpl) == 0x18, + "NfcXcdDeviceHandleStateImpl is an invalid size"); + // This is nn::hid::system::AppletFooterUiAttributesSet struct AppletFooterUiAttributes { INSERT_PADDING_BYTES(0x4); }; + // This is nn::hid::system::AppletFooterUiType enum class AppletFooterUiType : u8 { None = 0, HandheldNone = 1, @@ -510,95 +371,153 @@ 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 + struct AppletFooterUi { + AppletFooterUiAttributes attributes; + AppletFooterUiType type; + INSERT_PADDING_BYTES(0x5B); // Reserved + }; + static_assert(sizeof(AppletFooterUi) == 0x60, "AppletFooterUi is an invalid size"); + + // This is nn::hid::NpadLarkType + enum class NpadLarkType : u32 { + Invalid, + H1, + H2, + NL, + NR, + }; + + // This is nn::hid::NpadLuciaType + enum class NpadLuciaType : u32 { + Invalid, + J, + E, + U, + }; + + // This is nn::hid::NpadLagonType + enum class NpadLagonType : u32 { + Invalid, + }; + + // This is nn::hid::NpadLagerType + enum class NpadLagerType : u32 { + Invalid, + J, + E, + U, + }; + + // This is nn::hid::detail::NpadInternalState + struct NpadInternalState { + Core::HID::NpadStyleTag style_tag; + NpadJoyAssignmentMode assignment_mode; + NpadFullKeyColorState fullkey_color; + NpadJoyColorState joycon_color; + Lifo<NPadGenericState, hid_entry_count> fullkey_lifo; + Lifo<NPadGenericState, hid_entry_count> handheld_lifo; + Lifo<NPadGenericState, hid_entry_count> joy_dual_lifo; + Lifo<NPadGenericState, hid_entry_count> joy_left_lifo; + Lifo<NPadGenericState, hid_entry_count> joy_right_lifo; + Lifo<NPadGenericState, hid_entry_count> palma_lifo; + Lifo<NPadGenericState, hid_entry_count> system_ext_lifo; + Lifo<SixAxisSensorState, hid_entry_count> sixaxis_fullkey_lifo; + Lifo<SixAxisSensorState, hid_entry_count> sixaxis_handheld_lifo; + Lifo<SixAxisSensorState, hid_entry_count> sixaxis_dual_left_lifo; + Lifo<SixAxisSensorState, hid_entry_count> sixaxis_dual_right_lifo; + Lifo<SixAxisSensorState, hid_entry_count> sixaxis_left_lifo; + Lifo<SixAxisSensorState, hid_entry_count> 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; - AppletFooterUiAttributes footer_attributes; - AppletFooterUiType footer_type; - // nfc_states needs to be checked switchbrew does not match with HW - NfcXcdHandle nfc_states; - INSERT_PADDING_BYTES(0x8); // Mutex - TriggerGeneric gc_trigger_states; - INSERT_PADDING_BYTES(0xc1f); - }; - static_assert(sizeof(NPadEntry) == 0x5000, "NPadEntry is an invalid size"); - - struct ControllerHolder { - NPadControllerType type; - bool is_connected; - }; - - void InitNewlyAddedController(std::size_t controller_idx); - bool IsControllerSupported(NPadControllerType 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::NUM_STICKS_HID>, - 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>; - + NpadSystemButtonProperties button_properties; + Core::HID::NpadBatteryLevel battery_level_dual; + Core::HID::NpadBatteryLevel battery_level_left; + Core::HID::NpadBatteryLevel battery_level_right; + union { + Lifo<NfcXcdDeviceHandleStateImpl, 0x2> nfc_xcd_device_lifo{}; + AppletFooterUi applet_footer; + }; + INSERT_PADDING_BYTES(0x20); // Unknown + Lifo<NpadGcTriggerState, hid_entry_count> gc_trigger_lifo; + NpadLarkType lark_type_l_and_main; + NpadLarkType lark_type_r; + NpadLuciaType lucia_type; + NpadLagonType lagon_type; + NpadLagerType lager_type; + // FW 13.x Investigate there is some sort of bitflag related to joycons + INSERT_PADDING_BYTES(0x4); + INSERT_PADDING_BYTES(0xc08); // Unknown + }; + static_assert(sizeof(NpadInternalState) == 0x5000, "NpadInternalState is an invalid size"); + + struct VibrationData { + bool device_mounted{}; + Core::HID::VibrationValue latest_vibration_value{}; + std::chrono::steady_clock::time_point last_vibration_timepoint{}; + }; + + struct NpadControllerData { + Core::HID::EmulatedController* device; + Kernel::KEvent* styleset_changed_event{}; + NpadInternalState shared_memory_entry{}; + + std::array<VibrationData, 2> vibration{}; + bool unintended_home_button_input_protection{}; + bool is_connected{}; + + // Dual joycons can have only one side connected + bool is_dual_left_connected{true}; + bool is_dual_right_connected{true}; + + // Motion parameters + bool sixaxis_at_rest{true}; + bool sixaxis_sensor_enabled{true}; + bool sixaxis_fusion_enabled{false}; + Core::HID::SixAxisSensorFusionParameters sixaxis_fusion{}; + GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard}; + + // 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(Core::HID::NpadIdType npad_id); + bool IsControllerSupported(Core::HID::NpadStyleIndex controller) const; + void RequestPadStateUpdate(Core::HID::NpadIdType npad_id); + void WriteEmptyEntry(NpadInternalState& npad); + + NpadControllerData& GetControllerFromHandle( + const Core::HID::SixAxisSensorHandle& device_handle); + const NpadControllerData& GetControllerFromHandle( + const Core::HID::SixAxisSensorHandle& device_handle) const; + NpadControllerData& GetControllerFromHandle( + const Core::HID::VibrationDeviceHandle& device_handle); + const NpadControllerData& GetControllerFromHandle( + const Core::HID::VibrationDeviceHandle& device_handle) const; + NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id); + const NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) const; + + std::atomic<u64> press_state{}; + + std::array<NpadControllerData, 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}; + std::vector<Core::HID::NpadIdType> supported_npad_id_types{}; + 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 diff --git a/src/core/hle/service/hid/controllers/stubbed.cpp b/src/core/hle/service/hid/controllers/stubbed.cpp index 772c20453..b7d7a5756 100644 --- a/src/core/hle/service/hid/controllers/stubbed.cpp +++ b/src/core/hle/service/hid/controllers/stubbed.cpp @@ -5,11 +5,12 @@ #include <cstring> #include "common/common_types.h" #include "core/core_timing.h" +#include "core/hid/hid_core.h" #include "core/hle/service/hid/controllers/stubbed.h" namespace Service::HID { -Controller_Stubbed::Controller_Stubbed(Core::System& system_) : ControllerBase{system_} {} +Controller_Stubbed::Controller_Stubbed(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {} Controller_Stubbed::~Controller_Stubbed() = default; void Controller_Stubbed::OnInit() {} @@ -31,10 +32,9 @@ void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing, u std::memcpy(data + common_offset, &header, sizeof(CommonHeader)); } -void Controller_Stubbed::OnLoadInputDevices() {} - void Controller_Stubbed::SetCommonHeaderOffset(std::size_t off) { common_offset = off; smart_update = true; } + } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/stubbed.h b/src/core/hle/service/hid/controllers/stubbed.h index 21092af0d..0044a4efa 100644 --- a/src/core/hle/service/hid/controllers/stubbed.h +++ b/src/core/hle/service/hid/controllers/stubbed.h @@ -10,7 +10,7 @@ namespace Service::HID { class Controller_Stubbed final : public ControllerBase { public: - explicit Controller_Stubbed(Core::System& system_); + explicit Controller_Stubbed(Core::HID::HIDCore& hid_core_); ~Controller_Stubbed() override; // Called when the controller is initialized @@ -22,12 +22,17 @@ public: // When the controller is requesting an update for the shared memory void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; - // Called when input devices should be loaded - void OnLoadInputDevices() override; - void SetCommonHeaderOffset(std::size_t off); private: + struct CommonHeader { + s64 timestamp; + s64 total_entry_count; + s64 last_entry_index; + s64 entry_count; + }; + static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); + bool smart_update{}; std::size_t common_offset{}; }; diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp index 6ef17acc5..48978e5c6 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.cpp +++ b/src/core/hle/service/hid/controllers/touchscreen.cpp @@ -7,72 +7,82 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "common/settings.h" +#include "core/core.h" #include "core/core_timing.h" #include "core/frontend/emu_window.h" -#include "core/frontend/input.h" +#include "core/hid/emulated_console.h" +#include "core/hid/hid_core.h" #include "core/hle/service/hid/controllers/touchscreen.h" namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; -Controller_Touchscreen::Controller_Touchscreen(Core::System& system_) : ControllerBase{system_} {} +Controller_Touchscreen::Controller_Touchscreen(Core::HID::HIDCore& hid_core_) + : ControllerBase{hid_core_} { + console = hid_core.GetEmulatedConsole(); +} + Controller_Touchscreen::~Controller_Touchscreen() = default; -void Controller_Touchscreen::OnInit() { - for (std::size_t id = 0; id < MAX_FINGERS; ++id) { - mouse_finger_id[id] = MAX_FINGERS; - keyboard_finger_id[id] = MAX_FINGERS; - udp_finger_id[id] = MAX_FINGERS; - } -} +void Controller_Touchscreen::OnInit() {} void Controller_Touchscreen::OnRelease() {} void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { - shared_memory.header.timestamp = core_timing.GetCPUTicks(); - shared_memory.header.total_entry_count = 17; + touch_screen_lifo.timestamp = core_timing.GetCPUTicks(); if (!IsControllerActivated()) { - shared_memory.header.entry_count = 0; - shared_memory.header.last_entry_index = 0; + touch_screen_lifo.buffer_count = 0; + touch_screen_lifo.buffer_tail = 0; + std::memcpy(data, &touch_screen_lifo, sizeof(touch_screen_lifo)); return; } - shared_memory.header.entry_count = 16; - const auto& last_entry = - shared_memory.shared_memory_entries[shared_memory.header.last_entry_index]; - shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; - auto& cur_entry = shared_memory.shared_memory_entries[shared_memory.header.last_entry_index]; + const auto touch_status = console->GetTouch(); + for (std::size_t id = 0; id < MAX_FINGERS; id++) { + const auto& current_touch = touch_status[id]; + auto& finger = fingers[id]; + finger.position = current_touch.position; + finger.id = current_touch.id; - cur_entry.sampling_number = last_entry.sampling_number + 1; - cur_entry.sampling_number2 = cur_entry.sampling_number; + if (finger.attribute.start_touch) { + finger.attribute.raw = 0; + continue; + } - const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus(); - const Input::TouchStatus& udp_status = touch_udp_device->GetStatus(); - for (std::size_t id = 0; id < mouse_status.size(); ++id) { - mouse_finger_id[id] = UpdateTouchInputEvent(mouse_status[id], mouse_finger_id[id]); - udp_finger_id[id] = UpdateTouchInputEvent(udp_status[id], udp_finger_id[id]); - } + if (finger.attribute.end_touch) { + finger.attribute.raw = 0; + finger.pressed = false; + continue; + } + + if (!finger.pressed && current_touch.pressed) { + finger.attribute.start_touch.Assign(1); + finger.pressed = true; + continue; + } - if (Settings::values.use_touch_from_button) { - const Input::TouchStatus& keyboard_status = touch_btn_device->GetStatus(); - for (std::size_t id = 0; id < mouse_status.size(); ++id) { - keyboard_finger_id[id] = - UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]); + if (finger.pressed && !current_touch.pressed) { + finger.attribute.raw = 0; + finger.attribute.end_touch.Assign(1); } } - std::array<Finger, 16> active_fingers; + std::array<Core::HID::TouchFinger, MAX_FINGERS> active_fingers; const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), [](const auto& finger) { return finger.pressed; }); const auto active_fingers_count = static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter)); const u64 tick = core_timing.GetCPUTicks(); - cur_entry.entry_count = static_cast<s32_le>(active_fingers_count); + const auto& last_entry = touch_screen_lifo.ReadCurrentEntry().state; + + next_state.sampling_number = last_entry.sampling_number + 1; + next_state.entry_count = static_cast<s32>(active_fingers_count); + for (std::size_t id = 0; id < MAX_FINGERS; ++id) { - auto& touch_entry = cur_entry.states[id]; + auto& touch_entry = next_state.states[id]; if (id < active_fingers_count) { const auto& [active_x, active_y] = active_fingers[id].position; touch_entry.position = { @@ -97,66 +107,9 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin touch_entry.finger = 0; } } - std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(TouchScreenSharedMemory)); -} - -void Controller_Touchscreen::OnLoadInputDevices() { - touch_mouse_device = Input::CreateDevice<Input::TouchDevice>("engine:emu_window"); - touch_udp_device = Input::CreateDevice<Input::TouchDevice>("engine:cemuhookudp"); - touch_btn_device = Input::CreateDevice<Input::TouchDevice>("engine:touch_from_button"); -} - -std::optional<std::size_t> Controller_Touchscreen::GetUnusedFingerID() const { - // Dont assign any touch input to a finger if disabled - if (!Settings::values.touchscreen.enabled) { - return std::nullopt; - } - std::size_t first_free_id = 0; - while (first_free_id < MAX_FINGERS) { - if (!fingers[first_free_id].pressed) { - return first_free_id; - } else { - first_free_id++; - } - } - return std::nullopt; -} - -std::size_t Controller_Touchscreen::UpdateTouchInputEvent( - const std::tuple<float, float, bool>& touch_input, std::size_t finger_id) { - const auto& [x, y, pressed] = touch_input; - if (finger_id > MAX_FINGERS) { - LOG_ERROR(Service_HID, "Invalid finger id {}", finger_id); - return MAX_FINGERS; - } - if (pressed) { - Attributes attribute{}; - if (finger_id == MAX_FINGERS) { - const auto first_free_id = GetUnusedFingerID(); - if (!first_free_id) { - // Invalid finger id do nothing - return MAX_FINGERS; - } - finger_id = first_free_id.value(); - fingers[finger_id].pressed = true; - fingers[finger_id].id = static_cast<u32_le>(finger_id); - attribute.start_touch.Assign(1); - } - fingers[finger_id].position = {x, y}; - fingers[finger_id].attribute = attribute; - return finger_id; - } - - if (finger_id != MAX_FINGERS) { - if (!fingers[finger_id].attribute.end_touch) { - fingers[finger_id].attribute.end_touch.Assign(1); - fingers[finger_id].attribute.start_touch.Assign(0); - return finger_id; - } - fingers[finger_id].pressed = false; - } - return MAX_FINGERS; + touch_screen_lifo.WriteNextEntry(next_state); + std::memcpy(data + SHARED_MEMORY_OFFSET, &touch_screen_lifo, sizeof(touch_screen_lifo)); } } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h index 8e9b40c0a..708dde4f0 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.h +++ b/src/core/hle/service/hid/controllers/touchscreen.h @@ -9,18 +9,25 @@ #include "common/common_types.h" #include "common/point.h" #include "common/swap.h" -#include "core/frontend/input.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 Core::HID { +class EmulatedConsole; +} // namespace Core::HID namespace Service::HID { class Controller_Touchscreen final : public ControllerBase { public: + // This is nn::hid::TouchScreenModeForNx enum class TouchScreenModeForNx : u8 { UseSystemSetting, Finger, Heat2, }; + // This is nn::hid::TouchScreenConfigurationForNx struct TouchScreenConfigurationForNx { TouchScreenModeForNx mode; INSERT_PADDING_BYTES_NOINIT(0x7); @@ -29,7 +36,7 @@ public: static_assert(sizeof(TouchScreenConfigurationForNx) == 0x17, "TouchScreenConfigurationForNx is an invalid size"); - explicit Controller_Touchscreen(Core::System& system_); + explicit Controller_Touchscreen(Core::HID::HIDCore& hid_core_); ~Controller_Touchscreen() override; // Called when the controller is initialized @@ -41,73 +48,24 @@ public: // When the controller is requesting an update for the shared memory void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; - // Called when input devices should be loaded - void OnLoadInputDevices() override; - private: static constexpr std::size_t MAX_FINGERS = 16; - // Returns an unused finger id, if there is no fingers available std::nullopt will be returned - std::optional<std::size_t> GetUnusedFingerID() const; - - // If the touch is new it tries to assing a new finger id, if there is no fingers avaliable no - // changes will be made. Updates the coordinates if the finger id it's already set. If the touch - // ends delays the output by one frame to set the end_touch flag before finally freeing the - // finger id - std::size_t UpdateTouchInputEvent(const std::tuple<float, float, bool>& touch_input, - std::size_t finger_id); - - struct Attributes { - union { - u32 raw{}; - BitField<0, 1, u32> start_touch; - BitField<1, 1, u32> end_touch; - }; - }; - static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size"); - - struct TouchState { - u64_le delta_time; - Attributes attribute; - u32_le finger; - Common::Point<u32_le> position; - u32_le diameter_x; - u32_le diameter_y; - u32_le rotation_angle; + // This is nn::hid::TouchScreenState + struct TouchScreenState { + s64 sampling_number; + s32 entry_count; + INSERT_PADDING_BYTES(4); // Reserved + std::array<Core::HID::TouchState, MAX_FINGERS> states; }; - static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size"); + static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size"); - struct TouchScreenEntry { - s64_le sampling_number; - s64_le sampling_number2; - s32_le entry_count; - std::array<TouchState, MAX_FINGERS> states; - }; - static_assert(sizeof(TouchScreenEntry) == 0x298, "TouchScreenEntry is an invalid size"); - - struct TouchScreenSharedMemory { - CommonHeader header; - std::array<TouchScreenEntry, 17> shared_memory_entries{}; - INSERT_PADDING_BYTES(0x3c8); - }; - static_assert(sizeof(TouchScreenSharedMemory) == 0x3000, - "TouchScreenSharedMemory is an invalid size"); - - struct Finger { - u64_le last_touch{}; - Common::Point<float> position; - u32_le id{}; - bool pressed{}; - Attributes attribute; - }; + // This is nn::hid::detail::TouchScreenLifo + Lifo<TouchScreenState, hid_entry_count> touch_screen_lifo{}; + static_assert(sizeof(touch_screen_lifo) == 0x2C38, "touch_screen_lifo is an invalid size"); + TouchScreenState next_state{}; - TouchScreenSharedMemory shared_memory{}; - std::unique_ptr<Input::TouchDevice> touch_mouse_device; - std::unique_ptr<Input::TouchDevice> touch_udp_device; - std::unique_ptr<Input::TouchDevice> touch_btn_device; - std::array<std::size_t, MAX_FINGERS> mouse_finger_id; - std::array<std::size_t, MAX_FINGERS> keyboard_finger_id; - std::array<std::size_t, MAX_FINGERS> udp_finger_id; - std::array<Finger, MAX_FINGERS> fingers; + std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers; + Core::HID::EmulatedConsole* console; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/xpad.cpp b/src/core/hle/service/hid/controllers/xpad.cpp index 41dc22cf9..e4da16466 100644 --- a/src/core/hle/service/hid/controllers/xpad.cpp +++ b/src/core/hle/service/hid/controllers/xpad.cpp @@ -5,12 +5,13 @@ #include <cstring> #include "common/common_types.h" #include "core/core_timing.h" +#include "core/hid/hid_core.h" #include "core/hle/service/hid/controllers/xpad.h" namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00; -Controller_XPad::Controller_XPad(Core::System& system_) : ControllerBase{system_} {} +Controller_XPad::Controller_XPad(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {} Controller_XPad::~Controller_XPad() = default; void Controller_XPad::OnInit() {} @@ -19,28 +20,19 @@ void Controller_XPad::OnRelease() {} void Controller_XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { - for (auto& xpad_entry : shared_memory.shared_memory_entries) { - xpad_entry.header.timestamp = core_timing.GetCPUTicks(); - xpad_entry.header.total_entry_count = 17; - - if (!IsControllerActivated()) { - xpad_entry.header.entry_count = 0; - xpad_entry.header.last_entry_index = 0; - return; - } - xpad_entry.header.entry_count = 16; - - const auto& last_entry = xpad_entry.pad_states[xpad_entry.header.last_entry_index]; - xpad_entry.header.last_entry_index = (xpad_entry.header.last_entry_index + 1) % 17; - auto& cur_entry = xpad_entry.pad_states[xpad_entry.header.last_entry_index]; - - cur_entry.sampling_number = last_entry.sampling_number + 1; - cur_entry.sampling_number2 = cur_entry.sampling_number; + if (!IsControllerActivated()) { + basic_xpad_lifo.buffer_count = 0; + basic_xpad_lifo.buffer_tail = 0; + std::memcpy(data + SHARED_MEMORY_OFFSET, &basic_xpad_lifo, sizeof(basic_xpad_lifo)); + return; } + + const auto& last_entry = basic_xpad_lifo.ReadCurrentEntry().state; + next_state.sampling_number = last_entry.sampling_number + 1; // TODO(ogniK): Update xpad states - std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); + basic_xpad_lifo.WriteNextEntry(next_state); + std::memcpy(data + SHARED_MEMORY_OFFSET, &basic_xpad_lifo, sizeof(basic_xpad_lifo)); } -void Controller_XPad::OnLoadInputDevices() {} } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/xpad.h b/src/core/hle/service/hid/controllers/xpad.h index f9ab5facf..ba8db8d9d 100644 --- a/src/core/hle/service/hid/controllers/xpad.h +++ b/src/core/hle/service/hid/controllers/xpad.h @@ -8,12 +8,14 @@ #include "common/common_funcs.h" #include "common/common_types.h" #include "common/swap.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 Service::HID { class Controller_XPad final : public ControllerBase { public: - explicit Controller_XPad(Core::System& system_); + explicit Controller_XPad(Core::HID::HIDCore& hid_core_); ~Controller_XPad() override; // Called when the controller is initialized @@ -25,13 +27,11 @@ public: // When the controller is requesting an update for the shared memory void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; - // Called when input devices should be loaded - void OnLoadInputDevices() override; - private: - struct Attributes { + // This is nn::hid::BasicXpadAttributeSet + struct BasicXpadAttributeSet { union { - u32_le raw{}; + u32 raw{}; BitField<0, 1, u32> is_connected; BitField<1, 1, u32> is_wired; BitField<2, 1, u32> is_left_connected; @@ -40,11 +40,12 @@ private: BitField<5, 1, u32> is_right_wired; }; }; - static_assert(sizeof(Attributes) == 4, "Attributes is an invalid size"); + static_assert(sizeof(BasicXpadAttributeSet) == 4, "BasicXpadAttributeSet is an invalid size"); - struct Buttons { + // This is nn::hid::BasicXpadButtonSet + struct BasicXpadButtonSet { union { - u32_le raw{}; + u32 raw{}; // Button states BitField<0, 1, u32> a; BitField<1, 1, u32> b; @@ -88,35 +89,21 @@ private: BitField<30, 1, u32> handheld_left_b; }; }; - static_assert(sizeof(Buttons) == 4, "Buttons is an invalid size"); - - struct AnalogStick { - s32_le x; - s32_le y; - }; - static_assert(sizeof(AnalogStick) == 0x8, "AnalogStick is an invalid size"); - - struct XPadState { - s64_le sampling_number; - s64_le sampling_number2; - Attributes attributes; - Buttons pad_states; - AnalogStick l_stick; - AnalogStick r_stick; + static_assert(sizeof(BasicXpadButtonSet) == 4, "BasicXpadButtonSet is an invalid size"); + + // This is nn::hid::detail::BasicXpadState + struct BasicXpadState { + s64 sampling_number; + BasicXpadAttributeSet attributes; + BasicXpadButtonSet pad_states; + Core::HID::AnalogStickState l_stick; + Core::HID::AnalogStickState r_stick; }; - static_assert(sizeof(XPadState) == 0x28, "XPadState is an invalid size"); + static_assert(sizeof(BasicXpadState) == 0x20, "BasicXpadState is an invalid size"); - struct XPadEntry { - CommonHeader header; - std::array<XPadState, 17> pad_states{}; - INSERT_PADDING_BYTES(0x138); - }; - static_assert(sizeof(XPadEntry) == 0x400, "XPadEntry is an invalid size"); - - struct SharedMemory { - std::array<XPadEntry, 4> shared_memory_entries{}; - }; - static_assert(sizeof(SharedMemory) == 0x1000, "SharedMemory is an invalid size"); - SharedMemory shared_memory{}; + // This is nn::hid::detail::BasicXpadLifo + Lifo<BasicXpadState, hid_entry_count> basic_xpad_lifo{}; + static_assert(sizeof(basic_xpad_lifo) == 0x2C8, "basic_xpad_lifo is an invalid size"); + BasicXpadState next_state{}; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 10c64d41a..7163e1a4e 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -8,7 +8,7 @@ #include "common/settings.h" #include "core/core.h" #include "core/core_timing.h" -#include "core/frontend/input.h" +#include "core/hid/hid_core.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_shared_memory.h" @@ -34,10 +34,10 @@ namespace Service::HID { // Updating period for each HID device. -// HID is polled every 15ms, this value was derived from -// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering#joy-con-status-data-packet -constexpr auto pad_update_ns = std::chrono::nanoseconds{1000 * 1000}; // (1ms, 1000Hz) -constexpr auto motion_update_ns = std::chrono::nanoseconds{15 * 1000 * 1000}; // (15ms, 66.666Hz) +// Period time is obtained by measuring the number of samples in a second on HW using a homebrew +constexpr auto pad_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 250Hz) +constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz) +constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz) constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; IAppletResource::IAppletResource(Core::System& system_, @@ -79,17 +79,24 @@ IAppletResource::IAppletResource(Core::System& system_, const auto guard = LockService(); UpdateControllers(user_data, ns_late); }); + mouse_keyboard_update_event = Core::Timing::CreateEvent( + "HID::UpdateMouseKeyboardCallback", + [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { + const auto guard = LockService(); + UpdateMouseKeyboard(user_data, ns_late); + }); motion_update_event = Core::Timing::CreateEvent( - "HID::MotionPadCallback", + "HID::UpdateMotionCallback", [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { const auto guard = LockService(); UpdateMotion(user_data, ns_late); }); system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event); + system.CoreTiming().ScheduleEvent(mouse_keyboard_update_ns, mouse_keyboard_update_event); system.CoreTiming().ScheduleEvent(motion_update_ns, motion_update_event); - ReloadInputDevices(); + system.HIDCore().ReloadInputDevices(); } void IAppletResource::ActivateController(HidController controller) { @@ -102,6 +109,7 @@ void IAppletResource::DeactivateController(HidController controller) { IAppletResource::~IAppletResource() { system.CoreTiming().UnscheduleEvent(pad_update_event, 0); + system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0); system.CoreTiming().UnscheduleEvent(motion_update_event, 0); } @@ -117,23 +125,44 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { auto& core_timing = system.CoreTiming(); - const bool should_reload = Settings::values.is_device_reload_pending.exchange(false); for (const auto& controller : controllers) { - if (should_reload) { - controller->OnLoadInputDevices(); + // Keyboard has it's own update event + if (controller == controllers[static_cast<size_t>(HidController::Keyboard)]) { + continue; + } + // Mouse has it's own update event + if (controller == controllers[static_cast<size_t>(HidController::Mouse)]) { + continue; } controller->OnUpdate(core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE); } // If ns_late is higher than the update rate ignore the delay - if (ns_late > motion_update_ns) { + if (ns_late > pad_update_ns) { ns_late = {}; } core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event); } +void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data, + std::chrono::nanoseconds ns_late) { + auto& core_timing = system.CoreTiming(); + + controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate( + core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE); + controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate( + core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE); + + // If ns_late is higher than the update rate ignore the delay + if (ns_late > mouse_keyboard_update_ns) { + ns_late = {}; + } + + core_timing.ScheduleEvent(mouse_keyboard_update_ns - ns_late, mouse_keyboard_update_event); +} + void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { auto& core_timing = system.CoreTiming(); @@ -166,7 +195,7 @@ public: private: void InitializeVibrationDevice(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto vibration_device_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()}; + const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()}; if (applet_resource != nullptr) { applet_resource->GetController<Controller_NPad>(HidController::NPad) @@ -264,8 +293,8 @@ Hid::Hid(Core::System& system_) {132, &Hid::EnableUnintendedHomeButtonInputProtection, "EnableUnintendedHomeButtonInputProtection"}, {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"}, {134, &Hid::SetNpadAnalogStickUseCenterClamp, "SetNpadAnalogStickUseCenterClamp"}, - {135, nullptr, "SetNpadCaptureButtonAssignment"}, - {136, nullptr, "ClearNpadCaptureButtonAssignment"}, + {135, &Hid::SetNpadCaptureButtonAssignment, "SetNpadCaptureButtonAssignment"}, + {136, &Hid::ClearNpadCaptureButtonAssignment, "ClearNpadCaptureButtonAssignment"}, {200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"}, {201, &Hid::SendVibrationValue, "SendVibrationValue"}, {202, &Hid::GetActualVibrationValue, "GetActualVibrationValue"}, @@ -422,6 +451,7 @@ void Hid::ActivateXpad(Kernel::HLERequestContext& ctx) { INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw<Parameters>()}; @@ -448,19 +478,18 @@ void Hid::GetXpadIDs(Kernel::HLERequestContext& ctx) { void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle sixaxis_handle; + u32 basic_xpad_id; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw<Parameters>()}; - applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(true); + // This function does nothing on 10.0.0+ - LOG_DEBUG(Service_HID, - "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", - parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, - parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); + LOG_WARNING(Service_HID, "(STUBBED) called, basic_xpad_id={}, applet_resource_user_id={}", + parameters.basic_xpad_id, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -469,19 +498,18 @@ void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) { void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle sixaxis_handle; + u32 basic_xpad_id; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw<Parameters>()}; - applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(false); + // This function does nothing on 10.0.0+ - LOG_DEBUG(Service_HID, - "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", - parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, - parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); + LOG_WARNING(Service_HID, "(STUBBED) called, basic_xpad_id={}, applet_resource_user_id={}", + parameters.basic_xpad_id, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -490,14 +518,16 @@ void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) { void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle sixaxis_handle; + Core::HID::SixAxisSensorHandle sixaxis_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw<Parameters>()}; - applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(true); + applet_resource->GetController<Controller_NPad>(HidController::NPad) + .SetSixAxisEnabled(parameters.sixaxis_handle, true); LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", @@ -511,14 +541,16 @@ void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) { void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle sixaxis_handle; + Core::HID::SixAxisSensorHandle sixaxis_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw<Parameters>()}; - applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(false); + applet_resource->GetController<Controller_NPad>(HidController::NPad) + .SetSixAxisEnabled(parameters.sixaxis_handle, false); LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", @@ -534,19 +566,23 @@ void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) { struct Parameters { bool enable_sixaxis_sensor_fusion; INSERT_PADDING_BYTES_NOINIT(3); - Controller_NPad::DeviceHandle sixaxis_handle; + Core::HID::SixAxisSensorHandle sixaxis_handle; u64 applet_resource_user_id; }; static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw<Parameters>()}; - LOG_WARNING(Service_HID, - "(STUBBED) called, enable_sixaxis_sensor_fusion={}, npad_type={}, npad_id={}, " - "device_index={}, applet_resource_user_id={}", - parameters.enable_sixaxis_sensor_fusion, parameters.sixaxis_handle.npad_type, - parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index, - parameters.applet_resource_user_id); + applet_resource->GetController<Controller_NPad>(HidController::NPad) + .SetSixAxisFusionEnabled(parameters.sixaxis_handle, + parameters.enable_sixaxis_sensor_fusion); + + LOG_DEBUG(Service_HID, + "called, enable_sixaxis_sensor_fusion={}, npad_type={}, npad_id={}, " + "device_index={}, applet_resource_user_id={}", + parameters.enable_sixaxis_sensor_fusion, parameters.sixaxis_handle.npad_type, + parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index, + parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -555,9 +591,9 @@ void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) { void Hid::SetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle sixaxis_handle; - f32 parameter1; - f32 parameter2; + Core::HID::SixAxisSensorHandle sixaxis_handle; + Core::HID::SixAxisSensorFusionParameters sixaxis_fusion; + INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); @@ -565,14 +601,14 @@ void Hid::SetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; applet_resource->GetController<Controller_NPad>(HidController::NPad) - .SetSixAxisFusionParameters(parameters.parameter1, parameters.parameter2); + .SetSixAxisFusionParameters(parameters.sixaxis_handle, parameters.sixaxis_fusion); - LOG_WARNING(Service_HID, - "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, parameter1={}, " - "parameter2={}, applet_resource_user_id={}", - parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, - parameters.sixaxis_handle.device_index, parameters.parameter1, - parameters.parameter2, parameters.applet_resource_user_id); + LOG_DEBUG(Service_HID, + "called, npad_type={}, npad_id={}, device_index={}, parameter1={}, " + "parameter2={}, applet_resource_user_id={}", + parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, + parameters.sixaxis_handle.device_index, parameters.sixaxis_fusion.parameter1, + parameters.sixaxis_fusion.parameter2, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -581,35 +617,33 @@ void Hid::SetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { void Hid::GetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle sixaxis_handle; + Core::HID::SixAxisSensorHandle sixaxis_handle; + INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); - f32 parameter1 = 0; - f32 parameter2 = 0; const auto parameters{rp.PopRaw<Parameters>()}; - std::tie(parameter1, parameter2) = + const auto sixaxis_fusion_parameters = applet_resource->GetController<Controller_NPad>(HidController::NPad) - .GetSixAxisFusionParameters(); + .GetSixAxisFusionParameters(parameters.sixaxis_handle); - LOG_WARNING( - Service_HID, - "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", - parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, - parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); + LOG_DEBUG(Service_HID, + "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", + parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, + parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); - rb.Push(parameter1); - rb.Push(parameter2); + rb.PushRaw(sixaxis_fusion_parameters); } void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle sixaxis_handle; + Core::HID::SixAxisSensorHandle sixaxis_handle; + INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); @@ -617,13 +651,12 @@ void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; applet_resource->GetController<Controller_NPad>(HidController::NPad) - .ResetSixAxisFusionParameters(); + .ResetSixAxisFusionParameters(parameters.sixaxis_handle); - LOG_WARNING( - Service_HID, - "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", - parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, - parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); + LOG_DEBUG(Service_HID, + "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", + parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, + parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -631,12 +664,12 @@ void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto sixaxis_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()}; + const auto sixaxis_handle{rp.PopRaw<Core::HID::SixAxisSensorHandle>()}; const auto drift_mode{rp.PopEnum<Controller_NPad::GyroscopeZeroDriftMode>()}; const auto applet_resource_user_id{rp.Pop<u64>()}; applet_resource->GetController<Controller_NPad>(HidController::NPad) - .SetGyroscopeZeroDriftMode(drift_mode); + .SetGyroscopeZeroDriftMode(sixaxis_handle, drift_mode); LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}, drift_mode={}, " @@ -651,10 +684,11 @@ void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle sixaxis_handle; + Core::HID::SixAxisSensorHandle sixaxis_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw<Parameters>()}; @@ -666,21 +700,23 @@ void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad) - .GetGyroscopeZeroDriftMode()); + .GetGyroscopeZeroDriftMode(parameters.sixaxis_handle)); } void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle sixaxis_handle; + Core::HID::SixAxisSensorHandle sixaxis_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw<Parameters>()}; + const auto drift_mode{Controller_NPad::GyroscopeZeroDriftMode::Standard}; applet_resource->GetController<Controller_NPad>(HidController::NPad) - .SetGyroscopeZeroDriftMode(Controller_NPad::GyroscopeZeroDriftMode::Standard); + .SetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode); LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", @@ -694,10 +730,11 @@ void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle sixaxis_handle; + Core::HID::SixAxisSensorHandle sixaxis_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw<Parameters>()}; @@ -709,16 +746,17 @@ void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad) - .IsSixAxisSensorAtRest()); + .IsSixAxisSensorAtRest(parameters.sixaxis_handle)); } void Hid::IsFirmwareUpdateAvailableForSixAxisSensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle sixaxis_handle; + Core::HID::SixAxisSensorHandle sixaxis_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw<Parameters>()}; @@ -740,13 +778,14 @@ void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) { INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw<Parameters>()}; applet_resource->ActivateController(HidController::Gesture); - LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", parameters.unknown, - parameters.applet_resource_user_id); + LOG_WARNING(Service_HID, "(STUBBED) called, unknown={}, applet_resource_user_id={}", + parameters.unknown, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -754,12 +793,20 @@ void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) { void Hid::SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto supported_styleset{rp.Pop<u32>()}; + struct Parameters { + Core::HID::NpadStyleSet supported_styleset; + INSERT_PADDING_WORDS_NOINIT(1); + u64 applet_resource_user_id; + }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); + + const auto parameters{rp.PopRaw<Parameters>()}; applet_resource->GetController<Controller_NPad>(HidController::NPad) - .SetSupportedStyleSet({supported_styleset}); + .SetSupportedStyleSet({parameters.supported_styleset}); - LOG_DEBUG(Service_HID, "called, supported_styleset={}", supported_styleset); + LOG_DEBUG(Service_HID, "called, supported_styleset={}, applet_resource_user_id={}", + parameters.supported_styleset, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -773,9 +820,9 @@ void Hid::GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad) - .GetSupportedStyleSet() - .raw); + rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad) + .GetSupportedStyleSet() + .raw); } void Hid::SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { @@ -818,11 +865,12 @@ void Hid::DeactivateNpad(Kernel::HLERequestContext& ctx) { void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - u32 npad_id; + Core::HID::NpadIdType npad_id; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; u64 unknown; }; + static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); const auto parameters{rp.PopRaw<Parameters>()}; @@ -838,10 +886,11 @@ void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - u32 npad_id; + Core::HID::NpadIdType npad_id; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw<Parameters>()}; @@ -857,7 +906,7 @@ void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) { void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto npad_id{rp.Pop<u32>()}; + const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()}; LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id); @@ -872,16 +921,17 @@ void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { // Should have no effect with how our npad sets up the data IPC::RequestParser rp{ctx}; struct Parameters { - u32 unknown; + s32 revision; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw<Parameters>()}; applet_resource->ActivateController(HidController::NPad); - LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", parameters.unknown, + LOG_DEBUG(Service_HID, "called, revision={}, applet_resource_user_id={}", parameters.revision, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; @@ -891,7 +941,7 @@ void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { void Hid::SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop<u64>()}; - const auto hold_type{rp.PopEnum<Controller_NPad::NpadHoldType>()}; + const auto hold_type{rp.PopEnum<Controller_NPad::NpadJoyHoldType>()}; applet_resource->GetController<Controller_NPad>(HidController::NPad).SetHoldType(hold_type); @@ -916,42 +966,44 @@ void Hid::GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - u32 npad_id; + Core::HID::NpadIdType npad_id; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw<Parameters>()}; applet_resource->GetController<Controller_NPad>(HidController::NPad) - .SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Single); + .SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyDeviceType::Left, + Controller_NPad::NpadJoyAssignmentMode::Single); - LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", - parameters.npad_id, parameters.applet_resource_user_id); + LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, + parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) { - // TODO: Check the differences between this and SetNpadJoyAssignmentModeSingleByDefault IPC::RequestParser rp{ctx}; struct Parameters { - u32 npad_id; + Core::HID::NpadIdType npad_id; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; - u64 npad_joy_device_type; + Controller_NPad::NpadJoyDeviceType npad_joy_device_type; }; + static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); const auto parameters{rp.PopRaw<Parameters>()}; applet_resource->GetController<Controller_NPad>(HidController::NPad) - .SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Single); + .SetNpadMode(parameters.npad_id, parameters.npad_joy_device_type, + Controller_NPad::NpadJoyAssignmentMode::Single); - LOG_WARNING(Service_HID, - "(STUBBED) called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", - parameters.npad_id, parameters.applet_resource_user_id, - parameters.npad_joy_device_type); + LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", + parameters.npad_id, parameters.applet_resource_user_id, + parameters.npad_joy_device_type); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -960,18 +1012,19 @@ void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) { void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - u32 npad_id; + Core::HID::NpadIdType npad_id; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw<Parameters>()}; applet_resource->GetController<Controller_NPad>(HidController::NPad) - .SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Dual); + .SetNpadMode(parameters.npad_id, {}, Controller_NPad::NpadJoyAssignmentMode::Dual); - LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", - parameters.npad_id, parameters.applet_resource_user_id); + LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, + parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -979,8 +1032,8 @@ void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto npad_id_1{rp.Pop<u32>()}; - const auto npad_id_2{rp.Pop<u32>()}; + const auto npad_id_1{rp.PopEnum<Core::HID::NpadIdType>()}; + const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()}; const auto applet_resource_user_id{rp.Pop<u64>()}; applet_resource->GetController<Controller_NPad>(HidController::NPad) @@ -1046,8 +1099,8 @@ void Hid::GetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto npad_id_1{rp.Pop<u32>()}; - const auto npad_id_2{rp.Pop<u32>()}; + const auto npad_id_1{rp.PopEnum<Core::HID::NpadIdType>()}; + const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()}; const auto applet_resource_user_id{rp.Pop<u64>()}; const bool res = applet_resource->GetController<Controller_NPad>(HidController::NPad) @@ -1068,10 +1121,11 @@ void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) { void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - u32 npad_id; + Core::HID::NpadIdType npad_id; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw<Parameters>()}; @@ -1089,9 +1143,10 @@ void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& c struct Parameters { bool unintended_home_button_input_protection; INSERT_PADDING_BYTES_NOINIT(3); - u32 npad_id; + Core::HID::NpadIdType npad_id; u64 applet_resource_user_id; }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw<Parameters>()}; @@ -1113,6 +1168,7 @@ void Hid::SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { bool analog_stick_use_center_clamp; + INSERT_PADDING_BYTES_NOINIT(7); u64 applet_resource_user_id; }; static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); @@ -1130,40 +1186,71 @@ void Hid::SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx) { rb.Push(ResultSuccess); } +void Hid::SetNpadCaptureButtonAssignment(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + struct Parameters { + Core::HID::NpadStyleSet npad_styleset; + INSERT_PADDING_WORDS_NOINIT(1); + u64 applet_resource_user_id; + Core::HID::NpadButton button; + }; + static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); + + const auto parameters{rp.PopRaw<Parameters>()}; + + LOG_WARNING(Service_HID, + "(STUBBED) called, npad_styleset={}, applet_resource_user_id={}, button={}", + parameters.npad_styleset, parameters.applet_resource_user_id, parameters.button); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void Hid::ClearNpadCaptureButtonAssignment(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", + applet_resource_user_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto vibration_device_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()}; + const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()}; - VibrationDeviceInfo vibration_device_info; + Core::HID::VibrationDeviceInfo vibration_device_info; switch (vibration_device_handle.npad_type) { - case Controller_NPad::NpadType::ProController: - case Controller_NPad::NpadType::Handheld: - case Controller_NPad::NpadType::JoyconDual: - case Controller_NPad::NpadType::JoyconLeft: - case Controller_NPad::NpadType::JoyconRight: + case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::Handheld: + case Core::HID::NpadStyleIndex::JoyconDual: + case Core::HID::NpadStyleIndex::JoyconLeft: + case Core::HID::NpadStyleIndex::JoyconRight: default: - vibration_device_info.type = VibrationDeviceType::LinearResonantActuator; + vibration_device_info.type = Core::HID::VibrationDeviceType::LinearResonantActuator; break; - case Controller_NPad::NpadType::GameCube: - vibration_device_info.type = VibrationDeviceType::GcErm; + case Core::HID::NpadStyleIndex::GameCube: + vibration_device_info.type = Core::HID::VibrationDeviceType::GcErm; break; - case Controller_NPad::NpadType::Pokeball: - vibration_device_info.type = VibrationDeviceType::Unknown; + case Core::HID::NpadStyleIndex::Pokeball: + vibration_device_info.type = Core::HID::VibrationDeviceType::Unknown; break; } switch (vibration_device_handle.device_index) { - case Controller_NPad::DeviceIndex::Left: - vibration_device_info.position = VibrationDevicePosition::Left; + case Core::HID::DeviceIndex::Left: + vibration_device_info.position = Core::HID::VibrationDevicePosition::Left; break; - case Controller_NPad::DeviceIndex::Right: - vibration_device_info.position = VibrationDevicePosition::Right; + case Core::HID::DeviceIndex::Right: + vibration_device_info.position = Core::HID::VibrationDevicePosition::Right; break; - case Controller_NPad::DeviceIndex::None: + case Core::HID::DeviceIndex::None: default: UNREACHABLE_MSG("DeviceIndex should never be None!"); - vibration_device_info.position = VibrationDevicePosition::None; + vibration_device_info.position = Core::HID::VibrationDevicePosition::None; break; } @@ -1178,11 +1265,12 @@ void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle vibration_device_handle; - Controller_NPad::VibrationValue vibration_value; + Core::HID::VibrationDeviceHandle vibration_device_handle; + Core::HID::VibrationValue vibration_value; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; + static_assert(sizeof(Parameters) == 0x20, "Parameters has incorrect size."); const auto parameters{rp.PopRaw<Parameters>()}; @@ -1202,10 +1290,11 @@ void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) { void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle vibration_device_handle; + Core::HID::VibrationDeviceHandle vibration_device_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw<Parameters>()}; @@ -1256,10 +1345,10 @@ void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) { const auto handles = ctx.ReadBuffer(0); const auto vibrations = ctx.ReadBuffer(1); - std::vector<Controller_NPad::DeviceHandle> vibration_device_handles( - handles.size() / sizeof(Controller_NPad::DeviceHandle)); - std::vector<Controller_NPad::VibrationValue> vibration_values( - vibrations.size() / sizeof(Controller_NPad::VibrationValue)); + std::vector<Core::HID::VibrationDeviceHandle> vibration_device_handles( + handles.size() / sizeof(Core::HID::VibrationDeviceHandle)); + std::vector<Core::HID::VibrationValue> vibration_values(vibrations.size() / + sizeof(Core::HID::VibrationValue)); std::memcpy(vibration_device_handles.data(), handles.data(), handles.size()); std::memcpy(vibration_values.data(), vibrations.data(), vibrations.size()); @@ -1276,9 +1365,10 @@ void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) { void Hid::SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle vibration_device_handle; + Core::HID::VibrationDeviceHandle vibration_device_handle; + INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; - VibrationGcErmCommand gc_erm_command; + Core::HID::VibrationGcErmCommand gc_erm_command; }; static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); @@ -1292,26 +1382,26 @@ void Hid::SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { */ const auto vibration_value = [parameters] { switch (parameters.gc_erm_command) { - case VibrationGcErmCommand::Stop: - return Controller_NPad::VibrationValue{ - .amp_low = 0.0f, - .freq_low = 160.0f, - .amp_high = 0.0f, - .freq_high = 320.0f, + case Core::HID::VibrationGcErmCommand::Stop: + return Core::HID::VibrationValue{ + .low_amplitude = 0.0f, + .low_frequency = 160.0f, + .high_amplitude = 0.0f, + .high_frequency = 320.0f, }; - case VibrationGcErmCommand::Start: - return Controller_NPad::VibrationValue{ - .amp_low = 1.0f, - .freq_low = 160.0f, - .amp_high = 1.0f, - .freq_high = 320.0f, + case Core::HID::VibrationGcErmCommand::Start: + return Core::HID::VibrationValue{ + .low_amplitude = 1.0f, + .low_frequency = 160.0f, + .high_amplitude = 1.0f, + .high_frequency = 320.0f, }; - case VibrationGcErmCommand::StopHard: - return Controller_NPad::VibrationValue{ - .amp_low = 0.0f, - .freq_low = 0.0f, - .amp_high = 0.0f, - .freq_high = 0.0f, + case Core::HID::VibrationGcErmCommand::StopHard: + return Core::HID::VibrationValue{ + .low_amplitude = 0.0f, + .low_frequency = 0.0f, + .high_amplitude = 0.0f, + .high_frequency = 0.0f, }; default: return Controller_NPad::DEFAULT_VIBRATION_VALUE; @@ -1336,7 +1426,7 @@ void Hid::SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { void Hid::GetActualVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle vibration_device_handle; + Core::HID::VibrationDeviceHandle vibration_device_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; @@ -1347,8 +1437,8 @@ void Hid::GetActualVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { .GetLastVibration(parameters.vibration_device_handle); const auto gc_erm_command = [last_vibration] { - if (last_vibration.amp_low != 0.0f || last_vibration.amp_high != 0.0f) { - return VibrationGcErmCommand::Start; + if (last_vibration.low_amplitude != 0.0f || last_vibration.high_amplitude != 0.0f) { + return Core::HID::VibrationGcErmCommand::Start; } /** @@ -1357,11 +1447,11 @@ void Hid::GetActualVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { * SendVibrationGcErmCommand, in order to differentiate between Stop and StopHard commands. * This is done to reuse the controller vibration functions made for regular controllers. */ - if (last_vibration.freq_low == 0.0f && last_vibration.freq_high == 0.0f) { - return VibrationGcErmCommand::StopHard; + if (last_vibration.low_frequency == 0.0f && last_vibration.high_frequency == 0.0f) { + return Core::HID::VibrationGcErmCommand::StopHard; } - return VibrationGcErmCommand::Stop; + return Core::HID::VibrationGcErmCommand::Stop; }(); LOG_DEBUG(Service_HID, @@ -1401,10 +1491,11 @@ void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) { void Hid::IsVibrationDeviceMounted(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle vibration_device_handle; + Core::HID::VibrationDeviceHandle vibration_device_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw<Parameters>()}; @@ -1435,18 +1526,18 @@ void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle sixaxis_handle; + Core::HID::ConsoleSixAxisSensorHandle console_sixaxis_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw<Parameters>()}; - LOG_WARNING( - Service_HID, - "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", - parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, - parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); + LOG_WARNING(Service_HID, + "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}", + parameters.console_sixaxis_handle.unknown_1, + parameters.console_sixaxis_handle.unknown_2, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -1455,18 +1546,18 @@ void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { void Hid::StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::DeviceHandle sixaxis_handle; + Core::HID::ConsoleSixAxisSensorHandle console_sixaxis_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw<Parameters>()}; - LOG_WARNING( - Service_HID, - "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", - parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, - parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); + LOG_WARNING(Service_HID, + "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}", + parameters.console_sixaxis_handle.unknown_1, + parameters.console_sixaxis_handle.unknown_2, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -1620,10 +1711,8 @@ void Hid::SetNpadCommunicationMode(Kernel::HLERequestContext& ctx) { void Hid::GetNpadCommunicationMode(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto applet_resource_user_id{rp.Pop<u64>()}; - LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", - applet_resource_user_id); + LOG_WARNING(Service_HID, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); @@ -1825,7 +1914,7 @@ public: {317, nullptr, "GetNpadLeftRightInterfaceType"}, {318, nullptr, "HasBattery"}, {319, nullptr, "HasLeftRightBattery"}, - {321, nullptr, "GetUniquePadsFromNpad"}, + {321, &HidSys::GetUniquePadsFromNpad, "GetUniquePadsFromNpad"}, {322, nullptr, "GetIrSensorState"}, {323, nullptr, "GetXcdHandleForNpadWithIrSensor"}, {324, nullptr, "GetUniquePadButtonSet"}, @@ -1996,6 +2085,18 @@ private: IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } + + void GetUniquePadsFromNpad(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()}; + + const s64 total_entries = 0; + LOG_WARNING(Service_HID, "(STUBBED) called, npad_id_type={}", npad_id_type); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(total_entries); + } }; class HidTmp final : public ServiceFramework<HidTmp> { @@ -2037,10 +2138,6 @@ public: } }; -void ReloadInputDevices() { - Settings::values.is_device_reload_pending.store(true); -} - void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { std::make_shared<Hid>(system)->InstallAsService(service_manager); std::make_shared<HidBus>(system)->InstallAsService(service_manager); diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index b1fe75e94..d290df161 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -60,21 +60,23 @@ public: private: template <typename T> void MakeController(HidController controller) { - controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(system); + controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(system.HIDCore()); } template <typename T> void MakeControllerWithServiceContext(HidController controller) { controllers[static_cast<std::size_t>(controller)] = - std::make_unique<T>(system, service_context); + std::make_unique<T>(system.HIDCore(), service_context); } void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); + void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); KernelHelpers::ServiceContext& service_context; std::shared_ptr<Core::Timing::EventType> pad_update_event; + std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event; std::shared_ptr<Core::Timing::EventType> motion_update_event; std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)> @@ -134,6 +136,8 @@ private: void IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx); void EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx); void SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx); + void SetNpadCaptureButtonAssignment(Kernel::HLERequestContext& ctx); + void ClearNpadCaptureButtonAssignment(Kernel::HLERequestContext& ctx); void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx); void SendVibrationValue(Kernel::HLERequestContext& ctx); void GetActualVibrationValue(Kernel::HLERequestContext& ctx); @@ -161,38 +165,11 @@ private: void GetNpadCommunicationMode(Kernel::HLERequestContext& ctx); void SetTouchScreenConfiguration(Kernel::HLERequestContext& ctx); - enum class VibrationDeviceType : u32 { - Unknown = 0, - LinearResonantActuator = 1, - GcErm = 2, - }; - - enum class VibrationDevicePosition : u32 { - None = 0, - Left = 1, - Right = 2, - }; - - enum class VibrationGcErmCommand : u64 { - Stop = 0, - Start = 1, - StopHard = 2, - }; - - struct VibrationDeviceInfo { - VibrationDeviceType type{}; - VibrationDevicePosition position{}; - }; - static_assert(sizeof(VibrationDeviceInfo) == 0x8, "VibrationDeviceInfo has incorrect size."); - std::shared_ptr<IAppletResource> applet_resource; KernelHelpers::ServiceContext service_context; }; -/// Reload input devices. Used when input configuration changed -void ReloadInputDevices(); - /// Registers all HID services with the specified service manager. void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); diff --git a/src/core/hle/service/hid/ring_lifo.h b/src/core/hle/service/hid/ring_lifo.h new file mode 100644 index 000000000..44c20d967 --- /dev/null +++ b/src/core/hle/service/hid/ring_lifo.h @@ -0,0 +1,54 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#pragma once + +#include <array> + +#include "common/common_types.h" + +namespace Service::HID { + +template <typename State> +struct AtomicStorage { + s64 sampling_number; + State state; +}; + +template <typename State, std::size_t max_buffer_size> +struct Lifo { + s64 timestamp{}; + s64 total_buffer_count = static_cast<s64>(max_buffer_size); + s64 buffer_tail{}; + s64 buffer_count{}; + std::array<AtomicStorage<State>, max_buffer_size> entries{}; + + const AtomicStorage<State>& ReadCurrentEntry() const { + return entries[buffer_tail]; + } + + const AtomicStorage<State>& ReadPreviousEntry() const { + return entries[GetPreviousEntryIndex()]; + } + + std::size_t GetPreviousEntryIndex() const { + return static_cast<size_t>((buffer_tail + total_buffer_count - 1) % total_buffer_count); + } + + std::size_t GetNextEntryIndex() const { + return static_cast<size_t>((buffer_tail + 1) % total_buffer_count); + } + + void WriteNextEntry(const State& new_state) { + if (buffer_count < total_buffer_count - 1) { + buffer_count++; + } + buffer_tail = GetNextEntryIndex(); + const auto& previous_entry = ReadPreviousEntry(); + entries[buffer_tail].sampling_number = previous_entry.sampling_number + 1; + entries[buffer_tail].state = new_state; + } +}; + +} // namespace Service::HID |