Merge pull request #8229 from german77/reinterpret2
service: hid: Access shared memory directly
This commit is contained in:
		| @@ -9,9 +9,14 @@ | ||||
| namespace Service::HID { | ||||
| constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200; | ||||
|  | ||||
| Controller_ConsoleSixAxis::Controller_ConsoleSixAxis(Core::HID::HIDCore& hid_core_) | ||||
| Controller_ConsoleSixAxis::Controller_ConsoleSixAxis(Core::HID::HIDCore& hid_core_, | ||||
|                                                      u8* raw_shared_memory_) | ||||
|     : ControllerBase{hid_core_} { | ||||
|     console = hid_core.GetEmulatedConsole(); | ||||
|     static_assert(SHARED_MEMORY_OFFSET + sizeof(ConsoleSharedMemory) < shared_memory_size, | ||||
|                   "ConsoleSharedMemory is bigger than the shared memory"); | ||||
|     shared_memory = std::construct_at( | ||||
|         reinterpret_cast<ConsoleSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET)); | ||||
| } | ||||
|  | ||||
| Controller_ConsoleSixAxis::~Controller_ConsoleSixAxis() = default; | ||||
| @@ -20,8 +25,7 @@ void Controller_ConsoleSixAxis::OnInit() {} | ||||
|  | ||||
| void Controller_ConsoleSixAxis::OnRelease() {} | ||||
|  | ||||
| void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | ||||
|                                          std::size_t size) { | ||||
| void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | ||||
|     if (!IsControllerActivated() || !is_transfer_memory_set) { | ||||
|         seven_sixaxis_lifo.buffer_count = 0; | ||||
|         seven_sixaxis_lifo.buffer_tail = 0; | ||||
| @@ -48,13 +52,11 @@ void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_ti | ||||
|         -motion_status.quaternion.xyz.z, | ||||
|     }; | ||||
|  | ||||
|     console_six_axis.sampling_number++; | ||||
|     console_six_axis.is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest; | ||||
|     console_six_axis.verticalization_error = motion_status.verticalization_error; | ||||
|     console_six_axis.gyro_bias = motion_status.gyro_bias; | ||||
|     shared_memory->sampling_number++; | ||||
|     shared_memory->is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest; | ||||
|     shared_memory->verticalization_error = motion_status.verticalization_error; | ||||
|     shared_memory->gyro_bias = motion_status.gyro_bias; | ||||
|  | ||||
|     // 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 | ||||
|     seven_sixaxis_lifo.WriteNextEntry(next_seven_sixaxis_state); | ||||
|     std::memcpy(transfer_memory, &seven_sixaxis_lifo, sizeof(seven_sixaxis_lifo)); | ||||
|   | ||||
| @@ -17,7 +17,7 @@ class EmulatedConsole; | ||||
| namespace Service::HID { | ||||
| class Controller_ConsoleSixAxis final : public ControllerBase { | ||||
| public: | ||||
|     explicit Controller_ConsoleSixAxis(Core::HID::HIDCore& hid_core_); | ||||
|     explicit Controller_ConsoleSixAxis(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); | ||||
|     ~Controller_ConsoleSixAxis() override; | ||||
|  | ||||
|     // Called when the controller is initialized | ||||
| @@ -27,7 +27,7 @@ public: | ||||
|     void OnRelease() override; | ||||
|  | ||||
|     // 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; | ||||
|     void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; | ||||
|  | ||||
|     // Called on InitializeSevenSixAxisSensor | ||||
|     void SetTransferMemoryPointer(u8* t_mem); | ||||
| @@ -61,12 +61,13 @@ private: | ||||
|     Lifo<SevenSixAxisState, 0x21> seven_sixaxis_lifo{}; | ||||
|     static_assert(sizeof(seven_sixaxis_lifo) == 0xA70, "SevenSixAxisState is an invalid size"); | ||||
|  | ||||
|     Core::HID::EmulatedConsole* console; | ||||
|     SevenSixAxisState next_seven_sixaxis_state{}; | ||||
|     u8* transfer_memory = nullptr; | ||||
|     ConsoleSharedMemory* shared_memory = nullptr; | ||||
|     Core::HID::EmulatedConsole* console = nullptr; | ||||
|  | ||||
|     bool is_transfer_memory_set = false; | ||||
|     u64 last_saved_timestamp{}; | ||||
|     u64 last_global_timestamp{}; | ||||
|     ConsoleSharedMemory console_six_axis{}; | ||||
|     SevenSixAxisState next_seven_sixaxis_state{}; | ||||
| }; | ||||
| } // namespace Service::HID | ||||
|   | ||||
| @@ -26,12 +26,10 @@ public: | ||||
|     virtual void OnRelease() = 0; | ||||
|  | ||||
|     // When the controller is requesting an update for the shared memory | ||||
|     virtual void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | ||||
|                           std::size_t size) = 0; | ||||
|     virtual void OnUpdate(const Core::Timing::CoreTiming& core_timing) = 0; | ||||
|  | ||||
|     // When the controller is requesting a motion update for the shared memory | ||||
|     virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | ||||
|                                 std::size_t size) {} | ||||
|     virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) {} | ||||
|  | ||||
|     void ActivateController(); | ||||
|  | ||||
| @@ -40,6 +38,7 @@ public: | ||||
|     bool IsControllerActivated() const; | ||||
|  | ||||
|     static const std::size_t hid_entry_count = 17; | ||||
|     static const std::size_t shared_memory_size = 0x40000; | ||||
|  | ||||
| protected: | ||||
|     bool is_activated{false}; | ||||
|   | ||||
| @@ -13,8 +13,12 @@ | ||||
| namespace Service::HID { | ||||
| constexpr std::size_t SHARED_MEMORY_OFFSET = 0x00000; | ||||
|  | ||||
| Controller_DebugPad::Controller_DebugPad(Core::HID::HIDCore& hid_core_) | ||||
| Controller_DebugPad::Controller_DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) | ||||
|     : ControllerBase{hid_core_} { | ||||
|     static_assert(SHARED_MEMORY_OFFSET + sizeof(DebugPadSharedMemory) < shared_memory_size, | ||||
|                   "DebugPadSharedMemory is bigger than the shared memory"); | ||||
|     shared_memory = std::construct_at( | ||||
|         reinterpret_cast<DebugPadSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET)); | ||||
|     controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other); | ||||
| } | ||||
|  | ||||
| @@ -24,16 +28,14 @@ void Controller_DebugPad::OnInit() {} | ||||
|  | ||||
| void Controller_DebugPad::OnRelease() {} | ||||
|  | ||||
| void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | ||||
|                                    std::size_t size) { | ||||
| void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | ||||
|     if (!IsControllerActivated()) { | ||||
|         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)); | ||||
|         shared_memory->debug_pad_lifo.buffer_count = 0; | ||||
|         shared_memory->debug_pad_lifo.buffer_tail = 0; | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const auto& last_entry = debug_pad_lifo.ReadCurrentEntry().state; | ||||
|     const auto& last_entry = shared_memory->debug_pad_lifo.ReadCurrentEntry().state; | ||||
|     next_state.sampling_number = last_entry.sampling_number + 1; | ||||
|  | ||||
|     if (Settings::values.debug_pad_enabled) { | ||||
| @@ -47,8 +49,7 @@ void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, | ||||
|         next_state.r_stick = stick_state.right; | ||||
|     } | ||||
|  | ||||
|     debug_pad_lifo.WriteNextEntry(next_state); | ||||
|     std::memcpy(data + SHARED_MEMORY_OFFSET, &debug_pad_lifo, sizeof(debug_pad_lifo)); | ||||
|     shared_memory->debug_pad_lifo.WriteNextEntry(next_state); | ||||
| } | ||||
|  | ||||
| } // namespace Service::HID | ||||
|   | ||||
| @@ -17,7 +17,7 @@ struct AnalogStickState; | ||||
| namespace Service::HID { | ||||
| class Controller_DebugPad final : public ControllerBase { | ||||
| public: | ||||
|     explicit Controller_DebugPad(Core::HID::HIDCore& hid_core_); | ||||
|     explicit Controller_DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); | ||||
|     ~Controller_DebugPad() override; | ||||
|  | ||||
|     // Called when the controller is initialized | ||||
| @@ -27,7 +27,7 @@ public: | ||||
|     void OnRelease() override; | ||||
|  | ||||
|     // 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; | ||||
|     void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; | ||||
|  | ||||
| private: | ||||
|     // This is nn::hid::DebugPadAttribute | ||||
| @@ -41,19 +41,24 @@ private: | ||||
|  | ||||
|     // 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; | ||||
|         s64 sampling_number{}; | ||||
|         DebugPadAttribute attribute{}; | ||||
|         Core::HID::DebugPadButton pad_state{}; | ||||
|         Core::HID::AnalogStickState r_stick{}; | ||||
|         Core::HID::AnalogStickState l_stick{}; | ||||
|     }; | ||||
|     static_assert(sizeof(DebugPadState) == 0x20, "DebugPadState is an invalid state"); | ||||
|  | ||||
|     // 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{}; | ||||
|     struct DebugPadSharedMemory { | ||||
|         // 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"); | ||||
|         INSERT_PADDING_WORDS(0x4E); | ||||
|     }; | ||||
|     static_assert(sizeof(DebugPadSharedMemory) == 0x400, "DebugPadSharedMemory is an invalid size"); | ||||
|  | ||||
|     Core::HID::EmulatedController* controller; | ||||
|     DebugPadState next_state{}; | ||||
|     DebugPadSharedMemory* shared_memory = nullptr; | ||||
|     Core::HID::EmulatedController* controller = nullptr; | ||||
| }; | ||||
| } // namespace Service::HID | ||||
|   | ||||
| @@ -23,25 +23,28 @@ constexpr f32 Square(s32 num) { | ||||
|     return static_cast<f32>(num * num); | ||||
| } | ||||
|  | ||||
| Controller_Gesture::Controller_Gesture(Core::HID::HIDCore& hid_core_) : ControllerBase(hid_core_) { | ||||
| Controller_Gesture::Controller_Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) | ||||
|     : ControllerBase(hid_core_) { | ||||
|     static_assert(SHARED_MEMORY_OFFSET + sizeof(GestureSharedMemory) < shared_memory_size, | ||||
|                   "GestureSharedMemory is bigger than the shared memory"); | ||||
|     shared_memory = std::construct_at( | ||||
|         reinterpret_cast<GestureSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET)); | ||||
|     console = hid_core.GetEmulatedConsole(); | ||||
| } | ||||
| Controller_Gesture::~Controller_Gesture() = default; | ||||
|  | ||||
| void Controller_Gesture::OnInit() { | ||||
|     gesture_lifo.buffer_count = 0; | ||||
|     gesture_lifo.buffer_tail = 0; | ||||
|     shared_memory->gesture_lifo.buffer_count = 0; | ||||
|     shared_memory->gesture_lifo.buffer_tail = 0; | ||||
|     force_update = true; | ||||
| } | ||||
|  | ||||
| void Controller_Gesture::OnRelease() {} | ||||
|  | ||||
| void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | ||||
|                                   std::size_t size) { | ||||
| void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | ||||
|     if (!IsControllerActivated()) { | ||||
|         gesture_lifo.buffer_count = 0; | ||||
|         gesture_lifo.buffer_tail = 0; | ||||
|         std::memcpy(data + SHARED_MEMORY_OFFSET, &gesture_lifo, sizeof(gesture_lifo)); | ||||
|         shared_memory->gesture_lifo.buffer_count = 0; | ||||
|         shared_memory->gesture_lifo.buffer_tail = 0; | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| @@ -49,15 +52,15 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u | ||||
|  | ||||
|     GestureProperties gesture = GetGestureProperties(); | ||||
|     f32 time_difference = | ||||
|         static_cast<f32>(gesture_lifo.timestamp - last_update_timestamp) / (1000 * 1000 * 1000); | ||||
|         static_cast<f32>(shared_memory->gesture_lifo.timestamp - last_update_timestamp) / | ||||
|         (1000 * 1000 * 1000); | ||||
|  | ||||
|     // Only update if necesary | ||||
|     if (!ShouldUpdateGesture(gesture, time_difference)) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     last_update_timestamp = gesture_lifo.timestamp; | ||||
|     UpdateGestureSharedMemory(data, size, gesture, time_difference); | ||||
|     last_update_timestamp = shared_memory->gesture_lifo.timestamp; | ||||
| } | ||||
|  | ||||
| void Controller_Gesture::ReadTouchInput() { | ||||
| @@ -97,7 +100,7 @@ void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, | ||||
|     GestureType type = GestureType::Idle; | ||||
|     GestureAttribute attributes{}; | ||||
|  | ||||
|     const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; | ||||
|     const auto& last_entry = shared_memory->gesture_lifo.ReadCurrentEntry().state; | ||||
|  | ||||
|     // Reset next state to default | ||||
|     next_state.sampling_number = last_entry.sampling_number + 1; | ||||
| @@ -127,8 +130,7 @@ void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, | ||||
|     next_state.points = gesture.points; | ||||
|     last_gesture = gesture; | ||||
|  | ||||
|     gesture_lifo.WriteNextEntry(next_state); | ||||
|     std::memcpy(data + SHARED_MEMORY_OFFSET, &gesture_lifo, sizeof(gesture_lifo)); | ||||
|     shared_memory->gesture_lifo.WriteNextEntry(next_state); | ||||
| } | ||||
|  | ||||
| void Controller_Gesture::NewGesture(GestureProperties& gesture, GestureType& type, | ||||
| @@ -305,7 +307,7 @@ void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture, | ||||
| } | ||||
|  | ||||
| const Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() const { | ||||
|     return gesture_lifo.ReadCurrentEntry().state; | ||||
|     return shared_memory->gesture_lifo.ReadCurrentEntry().state; | ||||
| } | ||||
|  | ||||
| Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() { | ||||
|   | ||||
| @@ -14,7 +14,7 @@ | ||||
| namespace Service::HID { | ||||
| class Controller_Gesture final : public ControllerBase { | ||||
| public: | ||||
|     explicit Controller_Gesture(Core::HID::HIDCore& hid_core_); | ||||
|     explicit Controller_Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); | ||||
|     ~Controller_Gesture() override; | ||||
|  | ||||
|     // Called when the controller is initialized | ||||
| @@ -24,7 +24,7 @@ public: | ||||
|     void OnRelease() override; | ||||
|  | ||||
|     // 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; | ||||
|     void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; | ||||
|  | ||||
| private: | ||||
|     static constexpr size_t MAX_FINGERS = 16; | ||||
| @@ -66,19 +66,19 @@ private: | ||||
|  | ||||
|     // This is nn::hid::GestureState | ||||
|     struct GestureState { | ||||
|         s64 sampling_number; | ||||
|         s64 detection_count; | ||||
|         GestureType type; | ||||
|         GestureDirection direction; | ||||
|         Common::Point<s32> pos; | ||||
|         Common::Point<s32> delta; | ||||
|         f32 vel_x; | ||||
|         f32 vel_y; | ||||
|         GestureAttribute attributes; | ||||
|         f32 scale; | ||||
|         f32 rotation_angle; | ||||
|         s32 point_count; | ||||
|         std::array<Common::Point<s32>, 4> points; | ||||
|         s64 sampling_number{}; | ||||
|         s64 detection_count{}; | ||||
|         GestureType type{GestureType::Idle}; | ||||
|         GestureDirection direction{GestureDirection::None}; | ||||
|         Common::Point<s32> pos{}; | ||||
|         Common::Point<s32> delta{}; | ||||
|         f32 vel_x{}; | ||||
|         f32 vel_y{}; | ||||
|         GestureAttribute attributes{}; | ||||
|         f32 scale{}; | ||||
|         f32 rotation_angle{}; | ||||
|         s32 point_count{}; | ||||
|         std::array<Common::Point<s32>, 4> points{}; | ||||
|     }; | ||||
|     static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size"); | ||||
|  | ||||
| @@ -92,6 +92,14 @@ private: | ||||
|         f32 angle{}; | ||||
|     }; | ||||
|  | ||||
|     struct GestureSharedMemory { | ||||
|         // 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"); | ||||
|         INSERT_PADDING_WORDS(0x3E); | ||||
|     }; | ||||
|     static_assert(sizeof(GestureSharedMemory) == 0x800, "GestureSharedMemory is an invalid size"); | ||||
|  | ||||
|     // Reads input from all available input engines | ||||
|     void ReadTouchInput(); | ||||
|  | ||||
| @@ -134,12 +142,9 @@ private: | ||||
|     // Returns the average distance, angle and middle point of the active fingers | ||||
|     GestureProperties GetGestureProperties(); | ||||
|  | ||||
|     // 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; | ||||
|     GestureSharedMemory* shared_memory = nullptr; | ||||
|     Core::HID::EmulatedConsole* console = nullptr; | ||||
|  | ||||
|     std::array<Core::HID::TouchFinger, MAX_POINTS> fingers{}; | ||||
|     GestureProperties last_gesture{}; | ||||
|   | ||||
| @@ -12,8 +12,12 @@ | ||||
| namespace Service::HID { | ||||
| constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; | ||||
|  | ||||
| Controller_Keyboard::Controller_Keyboard(Core::HID::HIDCore& hid_core_) | ||||
| Controller_Keyboard::Controller_Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) | ||||
|     : ControllerBase{hid_core_} { | ||||
|     static_assert(SHARED_MEMORY_OFFSET + sizeof(KeyboardSharedMemory) < shared_memory_size, | ||||
|                   "KeyboardSharedMemory is bigger than the shared memory"); | ||||
|     shared_memory = std::construct_at( | ||||
|         reinterpret_cast<KeyboardSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET)); | ||||
|     emulated_devices = hid_core.GetEmulatedDevices(); | ||||
| } | ||||
|  | ||||
| @@ -23,16 +27,14 @@ void Controller_Keyboard::OnInit() {} | ||||
|  | ||||
| void Controller_Keyboard::OnRelease() {} | ||||
|  | ||||
| void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | ||||
|                                    std::size_t size) { | ||||
| void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | ||||
|     if (!IsControllerActivated()) { | ||||
|         keyboard_lifo.buffer_count = 0; | ||||
|         keyboard_lifo.buffer_tail = 0; | ||||
|         std::memcpy(data + SHARED_MEMORY_OFFSET, &keyboard_lifo, sizeof(keyboard_lifo)); | ||||
|         shared_memory->keyboard_lifo.buffer_count = 0; | ||||
|         shared_memory->keyboard_lifo.buffer_tail = 0; | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const auto& last_entry = keyboard_lifo.ReadCurrentEntry().state; | ||||
|     const auto& last_entry = shared_memory->keyboard_lifo.ReadCurrentEntry().state; | ||||
|     next_state.sampling_number = last_entry.sampling_number + 1; | ||||
|  | ||||
|     if (Settings::values.keyboard_enabled) { | ||||
| @@ -44,8 +46,7 @@ void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing, | ||||
|         next_state.attribute.is_connected.Assign(1); | ||||
|     } | ||||
|  | ||||
|     keyboard_lifo.WriteNextEntry(next_state); | ||||
|     std::memcpy(data + SHARED_MEMORY_OFFSET, &keyboard_lifo, sizeof(keyboard_lifo)); | ||||
|     shared_memory->keyboard_lifo.WriteNextEntry(next_state); | ||||
| } | ||||
|  | ||||
| } // namespace Service::HID | ||||
|   | ||||
| @@ -16,7 +16,7 @@ struct KeyboardKey; | ||||
| namespace Service::HID { | ||||
| class Controller_Keyboard final : public ControllerBase { | ||||
| public: | ||||
|     explicit Controller_Keyboard(Core::HID::HIDCore& hid_core_); | ||||
|     explicit Controller_Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); | ||||
|     ~Controller_Keyboard() override; | ||||
|  | ||||
|     // Called when the controller is initialized | ||||
| @@ -26,23 +26,28 @@ public: | ||||
|     void OnRelease() override; | ||||
|  | ||||
|     // 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; | ||||
|     void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; | ||||
|  | ||||
| private: | ||||
|     // This is nn::hid::detail::KeyboardState | ||||
|     struct KeyboardState { | ||||
|         s64 sampling_number; | ||||
|         Core::HID::KeyboardModifier modifier; | ||||
|         Core::HID::KeyboardAttribute attribute; | ||||
|         Core::HID::KeyboardKey key; | ||||
|         s64 sampling_number{}; | ||||
|         Core::HID::KeyboardModifier modifier{}; | ||||
|         Core::HID::KeyboardAttribute attribute{}; | ||||
|         Core::HID::KeyboardKey key{}; | ||||
|     }; | ||||
|     static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size"); | ||||
|  | ||||
|     // 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{}; | ||||
|     struct KeyboardSharedMemory { | ||||
|         // 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"); | ||||
|         INSERT_PADDING_WORDS(0xA); | ||||
|     }; | ||||
|     static_assert(sizeof(KeyboardSharedMemory) == 0x400, "KeyboardSharedMemory is an invalid size"); | ||||
|  | ||||
|     Core::HID::EmulatedDevices* emulated_devices; | ||||
|     KeyboardState next_state{}; | ||||
|     KeyboardSharedMemory* shared_memory = nullptr; | ||||
|     Core::HID::EmulatedDevices* emulated_devices = nullptr; | ||||
| }; | ||||
| } // namespace Service::HID | ||||
|   | ||||
| @@ -12,7 +12,12 @@ | ||||
| namespace Service::HID { | ||||
| constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400; | ||||
|  | ||||
| Controller_Mouse::Controller_Mouse(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} { | ||||
| Controller_Mouse::Controller_Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) | ||||
|     : ControllerBase{hid_core_} { | ||||
|     static_assert(SHARED_MEMORY_OFFSET + sizeof(MouseSharedMemory) < shared_memory_size, | ||||
|                   "MouseSharedMemory is bigger than the shared memory"); | ||||
|     shared_memory = std::construct_at( | ||||
|         reinterpret_cast<MouseSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET)); | ||||
|     emulated_devices = hid_core.GetEmulatedDevices(); | ||||
| } | ||||
|  | ||||
| @@ -21,16 +26,14 @@ Controller_Mouse::~Controller_Mouse() = default; | ||||
| void Controller_Mouse::OnInit() {} | ||||
| void Controller_Mouse::OnRelease() {} | ||||
|  | ||||
| void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | ||||
|                                 std::size_t size) { | ||||
| void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | ||||
|     if (!IsControllerActivated()) { | ||||
|         mouse_lifo.buffer_count = 0; | ||||
|         mouse_lifo.buffer_tail = 0; | ||||
|         std::memcpy(data + SHARED_MEMORY_OFFSET, &mouse_lifo, sizeof(mouse_lifo)); | ||||
|         shared_memory->mouse_lifo.buffer_count = 0; | ||||
|         shared_memory->mouse_lifo.buffer_tail = 0; | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const auto& last_entry = mouse_lifo.ReadCurrentEntry().state; | ||||
|     const auto& last_entry = shared_memory->mouse_lifo.ReadCurrentEntry().state; | ||||
|     next_state.sampling_number = last_entry.sampling_number + 1; | ||||
|  | ||||
|     next_state.attribute.raw = 0; | ||||
| @@ -50,8 +53,7 @@ void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* | ||||
|         next_state.button = mouse_button_state; | ||||
|     } | ||||
|  | ||||
|     mouse_lifo.WriteNextEntry(next_state); | ||||
|     std::memcpy(data + SHARED_MEMORY_OFFSET, &mouse_lifo, sizeof(mouse_lifo)); | ||||
|     shared_memory->mouse_lifo.WriteNextEntry(next_state); | ||||
| } | ||||
|  | ||||
| } // namespace Service::HID | ||||
|   | ||||
| @@ -16,7 +16,7 @@ struct AnalogStickState; | ||||
| namespace Service::HID { | ||||
| class Controller_Mouse final : public ControllerBase { | ||||
| public: | ||||
|     explicit Controller_Mouse(Core::HID::HIDCore& hid_core_); | ||||
|     explicit Controller_Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); | ||||
|     ~Controller_Mouse() override; | ||||
|  | ||||
|     // Called when the controller is initialized | ||||
| @@ -26,15 +26,20 @@ public: | ||||
|     void OnRelease() override; | ||||
|  | ||||
|     // 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; | ||||
|     void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; | ||||
|  | ||||
| private: | ||||
|     // 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{}; | ||||
|     struct MouseSharedMemory { | ||||
|         // 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"); | ||||
|         INSERT_PADDING_WORDS(0x2C); | ||||
|     }; | ||||
|     static_assert(sizeof(MouseSharedMemory) == 0x400, "MouseSharedMemory is an invalid size"); | ||||
|  | ||||
|     Core::HID::AnalogStickState last_mouse_wheel_state; | ||||
|     Core::HID::EmulatedDevices* emulated_devices; | ||||
|     Core::HID::MouseState next_state{}; | ||||
|     Core::HID::AnalogStickState last_mouse_wheel_state{}; | ||||
|     MouseSharedMemory* shared_memory = nullptr; | ||||
|     Core::HID::EmulatedDevices* emulated_devices = nullptr; | ||||
| }; | ||||
| } // namespace Service::HID | ||||
|   | ||||
| @@ -61,11 +61,14 @@ bool Controller_NPad::IsDeviceHandleValid(const Core::HID::SixAxisSensorHandle& | ||||
|     return npad_id && npad_type && device_index; | ||||
| } | ||||
|  | ||||
| Controller_NPad::Controller_NPad(Core::HID::HIDCore& hid_core_, | ||||
| Controller_NPad::Controller_NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_, | ||||
|                                  KernelHelpers::ServiceContext& service_context_) | ||||
|     : ControllerBase{hid_core_}, service_context{service_context_} { | ||||
|     static_assert(NPAD_OFFSET + (NPAD_COUNT * sizeof(NpadInternalState)) < shared_memory_size); | ||||
|     for (std::size_t i = 0; i < controller_data.size(); ++i) { | ||||
|         auto& controller = controller_data[i]; | ||||
|         controller.shared_memory = std::construct_at(reinterpret_cast<NpadInternalState*>( | ||||
|             raw_shared_memory_ + NPAD_OFFSET + (i * sizeof(NpadInternalState)))); | ||||
|         controller.device = hid_core.GetEmulatedControllerByIndex(i); | ||||
|         controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value = | ||||
|             Core::HID::DEFAULT_VIBRATION_VALUE; | ||||
| @@ -115,11 +118,11 @@ void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, | ||||
|         if (!controller.device->IsConnected()) { | ||||
|             return; | ||||
|         } | ||||
|         auto& shared_memory = controller.shared_memory_entry; | ||||
|         auto* shared_memory = controller.shared_memory; | ||||
|         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; | ||||
|         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: | ||||
| @@ -134,99 +137,100 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { | ||||
|     } | ||||
|     LOG_DEBUG(Service_HID, "Npad connected {}", npad_id); | ||||
|     const auto controller_type = controller.device->GetNpadStyleIndex(); | ||||
|     auto& shared_memory = controller.shared_memory_entry; | ||||
|     auto* shared_memory = controller.shared_memory; | ||||
|     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; | ||||
|     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 Core::HID::NpadStyleIndex::None: | ||||
|         UNREACHABLE(); | ||||
|         break; | ||||
|     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; | ||||
|         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_nfc_xcd.applet_footer.type = AppletFooterUiType::SwitchProController; | ||||
|         break; | ||||
|     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; | ||||
|         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_nfc_xcd.applet_footer.type = | ||||
|             AppletFooterUiType::HandheldJoyConLeftJoyConRight; | ||||
|         break; | ||||
|     case Core::HID::NpadStyleIndex::JoyconDual: | ||||
|         shared_memory.style_tag.joycon_dual.Assign(1); | ||||
|         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); | ||||
|             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->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; | ||||
|         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; | ||||
|             shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDual; | ||||
|         } else if (controller.is_dual_left_connected) { | ||||
|             shared_memory.applet_footer.type = AppletFooterUiType::JoyDualLeftOnly; | ||||
|             shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualLeftOnly; | ||||
|         } else { | ||||
|             shared_memory.applet_footer.type = AppletFooterUiType::JoyDualRightOnly; | ||||
|             shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualRightOnly; | ||||
|         } | ||||
|         break; | ||||
|     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; | ||||
|         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_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal; | ||||
|         break; | ||||
|     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; | ||||
|         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_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyRightHorizontal; | ||||
|         break; | ||||
|     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); | ||||
|         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 Core::HID::NpadStyleIndex::Pokeball: | ||||
|         shared_memory.style_tag.palma.Assign(1); | ||||
|         shared_memory.device_type.palma.Assign(1); | ||||
|         shared_memory->style_tag.palma.Assign(1); | ||||
|         shared_memory->device_type.palma.Assign(1); | ||||
|         break; | ||||
|     case Core::HID::NpadStyleIndex::NES: | ||||
|         shared_memory.style_tag.lark.Assign(1); | ||||
|         shared_memory.device_type.fullkey.Assign(1); | ||||
|         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; | ||||
|         shared_memory->style_tag.lucia.Assign(1); | ||||
|         shared_memory->device_type.fullkey.Assign(1); | ||||
|         shared_memory->applet_nfc_xcd.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; | ||||
|         shared_memory->style_tag.lagoon.Assign(1); | ||||
|         shared_memory->device_type.fullkey.Assign(1); | ||||
|         shared_memory->applet_nfc_xcd.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); | ||||
|         shared_memory->style_tag.lager.Assign(1); | ||||
|         shared_memory->device_type.fullkey.Assign(1); | ||||
|         break; | ||||
|     default: | ||||
|         break; | ||||
| @@ -234,23 +238,23 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { | ||||
|  | ||||
|     const auto& body_colors = controller.device->GetColors(); | ||||
|  | ||||
|     shared_memory.fullkey_color.attribute = ColorAttribute::Ok; | ||||
|     shared_memory.fullkey_color.fullkey = body_colors.fullkey; | ||||
|     shared_memory->fullkey_color.attribute = ColorAttribute::Ok; | ||||
|     shared_memory->fullkey_color.fullkey = body_colors.fullkey; | ||||
|  | ||||
|     shared_memory.joycon_color.attribute = ColorAttribute::Ok; | ||||
|     shared_memory.joycon_color.left = body_colors.left; | ||||
|     shared_memory.joycon_color.right = body_colors.right; | ||||
|     shared_memory->joycon_color.attribute = ColorAttribute::Ok; | ||||
|     shared_memory->joycon_color.left = body_colors.left; | ||||
|     shared_memory->joycon_color.right = body_colors.right; | ||||
|  | ||||
|     // TODO: Investigate when we should report all batery types | ||||
|     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; | ||||
|     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); | ||||
|     WriteEmptyEntry(controller.shared_memory); | ||||
| } | ||||
|  | ||||
| void Controller_NPad::OnInit() { | ||||
| @@ -270,12 +274,12 @@ void Controller_NPad::OnInit() { | ||||
|  | ||||
|     // Prefill controller buffers | ||||
|     for (auto& controller : controller_data) { | ||||
|         auto& npad = controller.shared_memory_entry; | ||||
|         npad.fullkey_color = { | ||||
|         auto* npad = controller.shared_memory; | ||||
|         npad->fullkey_color = { | ||||
|             .attribute = ColorAttribute::NoController, | ||||
|             .fullkey = {}, | ||||
|         }; | ||||
|         npad.joycon_color = { | ||||
|         npad->joycon_color = { | ||||
|             .attribute = ColorAttribute::NoController, | ||||
|             .left = {}, | ||||
|             .right = {}, | ||||
| @@ -287,25 +291,25 @@ void Controller_NPad::OnInit() { | ||||
|     } | ||||
| } | ||||
|  | ||||
| void Controller_NPad::WriteEmptyEntry(NpadInternalState& npad) { | ||||
| 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); | ||||
|     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); | ||||
| } | ||||
|  | ||||
| void Controller_NPad::OnRelease() { | ||||
| @@ -371,23 +375,19 @@ void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) { | ||||
|     } | ||||
| } | ||||
|  | ||||
| void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | ||||
|                                std::size_t data_len) { | ||||
| void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | ||||
|     if (!IsControllerActivated()) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     for (std::size_t i = 0; i < controller_data.size(); ++i) { | ||||
|         auto& controller = controller_data[i]; | ||||
|         auto& npad = controller.shared_memory_entry; | ||||
|         auto* npad = controller.shared_memory; | ||||
|  | ||||
|         const auto& controller_type = controller.device->GetNpadStyleIndex(); | ||||
|  | ||||
|         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; | ||||
|         } | ||||
|  | ||||
| @@ -415,8 +415,8 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* | ||||
|  | ||||
|             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); | ||||
|                 npad->fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||||
|             npad->fullkey_lifo.WriteNextEntry(pad_state); | ||||
|             break; | ||||
|         case Core::HID::NpadStyleIndex::Handheld: | ||||
|             pad_state.connection_status.raw = 0; | ||||
| @@ -433,8 +433,8 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* | ||||
|             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); | ||||
|                 npad->handheld_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||||
|             npad->handheld_lifo.WriteNextEntry(pad_state); | ||||
|             break; | ||||
|         case Core::HID::NpadStyleIndex::JoyconDual: | ||||
|             pad_state.connection_status.raw = 0; | ||||
| @@ -449,8 +449,8 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* | ||||
|             } | ||||
|  | ||||
|             pad_state.sampling_number = | ||||
|                 npad.joy_dual_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||||
|             npad.joy_dual_lifo.WriteNextEntry(pad_state); | ||||
|                 npad->joy_dual_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||||
|             npad->joy_dual_lifo.WriteNextEntry(pad_state); | ||||
|             break; | ||||
|         case Core::HID::NpadStyleIndex::JoyconLeft: | ||||
|             pad_state.connection_status.raw = 0; | ||||
| @@ -459,8 +459,8 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* | ||||
|  | ||||
|             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); | ||||
|                 npad->joy_left_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||||
|             npad->joy_left_lifo.WriteNextEntry(pad_state); | ||||
|             break; | ||||
|         case Core::HID::NpadStyleIndex::JoyconRight: | ||||
|             pad_state.connection_status.raw = 0; | ||||
| @@ -469,8 +469,8 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* | ||||
|  | ||||
|             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); | ||||
|                 npad->joy_right_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||||
|             npad->joy_right_lifo.WriteNextEntry(pad_state); | ||||
|             break; | ||||
|         case Core::HID::NpadStyleIndex::GameCube: | ||||
|             pad_state.connection_status.raw = 0; | ||||
| @@ -479,18 +479,18 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* | ||||
|  | ||||
|             libnx_state.connection_status.is_wired.Assign(1); | ||||
|             pad_state.sampling_number = | ||||
|                 npad.fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||||
|                 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); | ||||
|                 npad->gc_trigger_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||||
|             npad->fullkey_lifo.WriteNextEntry(pad_state); | ||||
|             npad->gc_trigger_lifo.WriteNextEntry(trigger_state); | ||||
|             break; | ||||
|         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); | ||||
|                 npad->palma_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||||
|             npad->palma_lifo.WriteNextEntry(pad_state); | ||||
|             break; | ||||
|         default: | ||||
|             break; | ||||
| @@ -499,17 +499,13 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* | ||||
|         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); | ||||
|         npad->system_ext_lifo.WriteNextEntry(pad_state); | ||||
|  | ||||
|         press_state |= static_cast<u64>(pad_state.npad_buttons.raw); | ||||
|  | ||||
|         std::memcpy(data + NPAD_OFFSET + (i * sizeof(NpadInternalState)), | ||||
|                     &controller.shared_memory_entry, sizeof(NpadInternalState)); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | ||||
|                                      std::size_t data_len) { | ||||
| void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) { | ||||
|     if (!IsControllerActivated()) { | ||||
|         return; | ||||
|     } | ||||
| @@ -524,7 +520,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         auto& npad = controller.shared_memory_entry; | ||||
|         auto* npad = controller.shared_memory; | ||||
|         const auto& motion_state = controller.device->GetMotions(); | ||||
|         auto& sixaxis_fullkey_state = controller.sixaxis_fullkey_state; | ||||
|         auto& sixaxis_handheld_state = controller.sixaxis_handheld_state; | ||||
| @@ -610,32 +606,30 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing | ||||
|         } | ||||
|  | ||||
|         sixaxis_fullkey_state.sampling_number = | ||||
|             npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||||
|             npad->sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||||
|         sixaxis_handheld_state.sampling_number = | ||||
|             npad.sixaxis_handheld_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||||
|             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; | ||||
|             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; | ||||
|             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; | ||||
|             npad->sixaxis_left_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||||
|         sixaxis_right_lifo_state.sampling_number = | ||||
|             npad.sixaxis_right_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||||
|             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); | ||||
|             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_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)); | ||||
|         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); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -713,8 +707,8 @@ void Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceTy | ||||
|     } | ||||
|  | ||||
|     auto& controller = GetControllerFromNpadIdType(npad_id); | ||||
|     if (controller.shared_memory_entry.assignment_mode != assignment_mode) { | ||||
|         controller.shared_memory_entry.assignment_mode = assignment_mode; | ||||
|     if (controller.shared_memory->assignment_mode != assignment_mode) { | ||||
|         controller.shared_memory->assignment_mode = assignment_mode; | ||||
|     } | ||||
|  | ||||
|     if (!controller.device->IsConnected()) { | ||||
| @@ -981,32 +975,32 @@ void Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) { | ||||
|         controller.vibration[device_idx].device_mounted = false; | ||||
|     } | ||||
|  | ||||
|     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 = { | ||||
|     auto* shared_memory = controller.shared_memory; | ||||
|     // Don't reset shared_memory->assignment_mode this value is persistent | ||||
|     shared_memory->style_tag.raw = Core::HID::NpadStyleSet::None; // Zero out | ||||
|     shared_memory->device_type.raw = 0; | ||||
|     shared_memory->system_properties.raw = 0; | ||||
|     shared_memory->button_properties.raw = 0; | ||||
|     shared_memory->battery_level_dual = 0; | ||||
|     shared_memory->battery_level_left = 0; | ||||
|     shared_memory->battery_level_right = 0; | ||||
|     shared_memory->fullkey_color = { | ||||
|         .attribute = ColorAttribute::NoController, | ||||
|         .fullkey = {}, | ||||
|     }; | ||||
|     shared_memory_entry.joycon_color = { | ||||
|     shared_memory->joycon_color = { | ||||
|         .attribute = ColorAttribute::NoController, | ||||
|         .left = {}, | ||||
|         .right = {}, | ||||
|     }; | ||||
|     shared_memory_entry.applet_footer.type = AppletFooterUiType::None; | ||||
|     shared_memory->applet_nfc_xcd.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); | ||||
|     WriteEmptyEntry(shared_memory); | ||||
| } | ||||
|  | ||||
| ResultCode Controller_NPad::SetGyroscopeZeroDriftMode(Core::HID::SixAxisSensorHandle sixaxis_handle, | ||||
|   | ||||
| @@ -35,7 +35,7 @@ namespace Service::HID { | ||||
|  | ||||
| class Controller_NPad final : public ControllerBase { | ||||
| public: | ||||
|     explicit Controller_NPad(Core::HID::HIDCore& hid_core_, | ||||
|     explicit Controller_NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_, | ||||
|                              KernelHelpers::ServiceContext& service_context_); | ||||
|     ~Controller_NPad() override; | ||||
|  | ||||
| @@ -46,11 +46,10 @@ public: | ||||
|     void OnRelease() override; | ||||
|  | ||||
|     // 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; | ||||
|     void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; | ||||
|  | ||||
|     // When the controller is requesting a motion update for the shared memory | ||||
|     void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | ||||
|                         std::size_t size) override; | ||||
|     void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) override; | ||||
|  | ||||
|     // This is nn::hid::GyroscopeZeroDriftMode | ||||
|     enum class GyroscopeZeroDriftMode : u32 { | ||||
| @@ -188,6 +187,8 @@ public: | ||||
|     static bool IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle); | ||||
|  | ||||
| private: | ||||
|     static constexpr std::size_t NPAD_COUNT = 10; | ||||
|  | ||||
|     // This is nn::hid::detail::ColorAttribute | ||||
|     enum class ColorAttribute : u32 { | ||||
|         Ok = 0, | ||||
| @@ -409,6 +410,13 @@ private: | ||||
|         U, | ||||
|     }; | ||||
|  | ||||
|     struct AppletNfcXcd { | ||||
|         union { | ||||
|             AppletFooterUi applet_footer{}; | ||||
|             Lifo<NfcXcdDeviceHandleStateImpl, 0x2> nfc_xcd_device_lifo; | ||||
|         }; | ||||
|     }; | ||||
|  | ||||
|     // This is nn::hid::detail::NpadInternalState | ||||
|     struct NpadInternalState { | ||||
|         Core::HID::NpadStyleTag style_tag{Core::HID::NpadStyleSet::None}; | ||||
| @@ -435,10 +443,7 @@ private: | ||||
|         Core::HID::NpadBatteryLevel battery_level_dual{}; | ||||
|         Core::HID::NpadBatteryLevel battery_level_left{}; | ||||
|         Core::HID::NpadBatteryLevel battery_level_right{}; | ||||
|         union { | ||||
|             AppletFooterUi applet_footer{}; | ||||
|             Lifo<NfcXcdDeviceHandleStateImpl, 0x2> nfc_xcd_device_lifo; | ||||
|         }; | ||||
|         AppletNfcXcd applet_nfc_xcd{}; | ||||
|         INSERT_PADDING_BYTES(0x20); // Unknown | ||||
|         Lifo<NpadGcTriggerState, hid_entry_count> gc_trigger_lifo{}; | ||||
|         NpadLarkType lark_type_l_and_main{}; | ||||
| @@ -465,9 +470,9 @@ private: | ||||
|     }; | ||||
|  | ||||
|     struct NpadControllerData { | ||||
|         Core::HID::EmulatedController* device; | ||||
|         Kernel::KEvent* styleset_changed_event{}; | ||||
|         NpadInternalState shared_memory_entry{}; | ||||
|         NpadInternalState* shared_memory = nullptr; | ||||
|         Core::HID::EmulatedController* device = nullptr; | ||||
|  | ||||
|         std::array<VibrationData, 2> vibration{}; | ||||
|         bool unintended_home_button_input_protection{}; | ||||
| @@ -497,15 +502,14 @@ private: | ||||
|         SixAxisSensorState sixaxis_dual_right_state{}; | ||||
|         SixAxisSensorState sixaxis_left_lifo_state{}; | ||||
|         SixAxisSensorState sixaxis_right_lifo_state{}; | ||||
|  | ||||
|         int callback_key; | ||||
|         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); | ||||
|     void WriteEmptyEntry(NpadInternalState* npad); | ||||
|  | ||||
|     NpadControllerData& GetControllerFromHandle( | ||||
|         const Core::HID::SixAxisSensorHandle& device_handle); | ||||
| @@ -520,7 +524,7 @@ private: | ||||
|  | ||||
|     std::atomic<u64> press_state{}; | ||||
|  | ||||
|     std::array<NpadControllerData, 10> controller_data{}; | ||||
|     std::array<NpadControllerData, NPAD_COUNT> controller_data{}; | ||||
|     KernelHelpers::ServiceContext& service_context; | ||||
|     std::mutex mutex; | ||||
|     std::vector<Core::HID::NpadIdType> supported_npad_id_types{}; | ||||
|   | ||||
| @@ -9,15 +9,18 @@ | ||||
|  | ||||
| namespace Service::HID { | ||||
|  | ||||
| Controller_Stubbed::Controller_Stubbed(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {} | ||||
| Controller_Stubbed::Controller_Stubbed(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) | ||||
|     : ControllerBase{hid_core_} { | ||||
|     raw_shared_memory = raw_shared_memory_; | ||||
| } | ||||
|  | ||||
| Controller_Stubbed::~Controller_Stubbed() = default; | ||||
|  | ||||
| void Controller_Stubbed::OnInit() {} | ||||
|  | ||||
| void Controller_Stubbed::OnRelease() {} | ||||
|  | ||||
| void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | ||||
|                                   std::size_t size) { | ||||
| void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | ||||
|     if (!smart_update) { | ||||
|         return; | ||||
|     } | ||||
| @@ -28,7 +31,7 @@ void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing, u | ||||
|     header.entry_count = 0; | ||||
|     header.last_entry_index = 0; | ||||
|  | ||||
|     std::memcpy(data + common_offset, &header, sizeof(CommonHeader)); | ||||
|     std::memcpy(raw_shared_memory + common_offset, &header, sizeof(CommonHeader)); | ||||
| } | ||||
|  | ||||
| void Controller_Stubbed::SetCommonHeaderOffset(std::size_t off) { | ||||
|   | ||||
| @@ -9,7 +9,7 @@ | ||||
| namespace Service::HID { | ||||
| class Controller_Stubbed final : public ControllerBase { | ||||
| public: | ||||
|     explicit Controller_Stubbed(Core::HID::HIDCore& hid_core_); | ||||
|     explicit Controller_Stubbed(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); | ||||
|     ~Controller_Stubbed() override; | ||||
|  | ||||
|     // Called when the controller is initialized | ||||
| @@ -19,19 +19,20 @@ public: | ||||
|     void OnRelease() override; | ||||
|  | ||||
|     // 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; | ||||
|     void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; | ||||
|  | ||||
|     void SetCommonHeaderOffset(std::size_t off); | ||||
|  | ||||
| private: | ||||
|     struct CommonHeader { | ||||
|         s64 timestamp; | ||||
|         s64 total_entry_count; | ||||
|         s64 last_entry_index; | ||||
|         s64 entry_count; | ||||
|         s64 timestamp{}; | ||||
|         s64 total_entry_count{}; | ||||
|         s64 last_entry_index{}; | ||||
|         s64 entry_count{}; | ||||
|     }; | ||||
|     static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); | ||||
|  | ||||
|     u8* raw_shared_memory = nullptr; | ||||
|     bool smart_update{}; | ||||
|     std::size_t common_offset{}; | ||||
| }; | ||||
|   | ||||
| @@ -15,8 +15,13 @@ | ||||
| namespace Service::HID { | ||||
| constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; | ||||
|  | ||||
| Controller_Touchscreen::Controller_Touchscreen(Core::HID::HIDCore& hid_core_) | ||||
| Controller_Touchscreen::Controller_Touchscreen(Core::HID::HIDCore& hid_core_, | ||||
|                                                u8* raw_shared_memory_) | ||||
|     : ControllerBase{hid_core_} { | ||||
|     static_assert(SHARED_MEMORY_OFFSET + sizeof(TouchSharedMemory) < shared_memory_size, | ||||
|                   "TouchSharedMemory is bigger than the shared memory"); | ||||
|     shared_memory = std::construct_at( | ||||
|         reinterpret_cast<TouchSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET)); | ||||
|     console = hid_core.GetEmulatedConsole(); | ||||
| } | ||||
|  | ||||
| @@ -26,14 +31,12 @@ void Controller_Touchscreen::OnInit() {} | ||||
|  | ||||
| void Controller_Touchscreen::OnRelease() {} | ||||
|  | ||||
| void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | ||||
|                                       std::size_t size) { | ||||
|     touch_screen_lifo.timestamp = core_timing.GetCPUTicks(); | ||||
| void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | ||||
|     shared_memory->touch_screen_lifo.timestamp = core_timing.GetCPUTicks(); | ||||
|  | ||||
|     if (!IsControllerActivated()) { | ||||
|         touch_screen_lifo.buffer_count = 0; | ||||
|         touch_screen_lifo.buffer_tail = 0; | ||||
|         std::memcpy(data, &touch_screen_lifo, sizeof(touch_screen_lifo)); | ||||
|         shared_memory->touch_screen_lifo.buffer_count = 0; | ||||
|         shared_memory->touch_screen_lifo.buffer_tail = 0; | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| @@ -74,7 +77,7 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin | ||||
|         static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter)); | ||||
|  | ||||
|     const u64 tick = core_timing.GetCPUTicks(); | ||||
|     const auto& last_entry = touch_screen_lifo.ReadCurrentEntry().state; | ||||
|     const auto& last_entry = shared_memory->touch_screen_lifo.ReadCurrentEntry().state; | ||||
|  | ||||
|     next_state.sampling_number = last_entry.sampling_number + 1; | ||||
|     next_state.entry_count = static_cast<s32>(active_fingers_count); | ||||
| @@ -106,8 +109,7 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     touch_screen_lifo.WriteNextEntry(next_state); | ||||
|     std::memcpy(data + SHARED_MEMORY_OFFSET, &touch_screen_lifo, sizeof(touch_screen_lifo)); | ||||
|     shared_memory->touch_screen_lifo.WriteNextEntry(next_state); | ||||
| } | ||||
|  | ||||
| } // namespace Service::HID | ||||
|   | ||||
| @@ -25,14 +25,14 @@ public: | ||||
|  | ||||
|     // This is nn::hid::TouchScreenConfigurationForNx | ||||
|     struct TouchScreenConfigurationForNx { | ||||
|         TouchScreenModeForNx mode; | ||||
|         TouchScreenModeForNx mode{TouchScreenModeForNx::UseSystemSetting}; | ||||
|         INSERT_PADDING_BYTES_NOINIT(0x7); | ||||
|         INSERT_PADDING_BYTES_NOINIT(0xF); // Reserved | ||||
|     }; | ||||
|     static_assert(sizeof(TouchScreenConfigurationForNx) == 0x17, | ||||
|                   "TouchScreenConfigurationForNx is an invalid size"); | ||||
|  | ||||
|     explicit Controller_Touchscreen(Core::HID::HIDCore& hid_core_); | ||||
|     explicit Controller_Touchscreen(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); | ||||
|     ~Controller_Touchscreen() override; | ||||
|  | ||||
|     // Called when the controller is initialized | ||||
| @@ -42,26 +42,32 @@ public: | ||||
|     void OnRelease() override; | ||||
|  | ||||
|     // 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; | ||||
|     void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; | ||||
|  | ||||
| private: | ||||
|     static constexpr std::size_t MAX_FINGERS = 16; | ||||
|  | ||||
|     // This is nn::hid::TouchScreenState | ||||
|     struct TouchScreenState { | ||||
|         s64 sampling_number; | ||||
|         s32 entry_count; | ||||
|         s64 sampling_number{}; | ||||
|         s32 entry_count{}; | ||||
|         INSERT_PADDING_BYTES(4); // Reserved | ||||
|         std::array<Core::HID::TouchState, MAX_FINGERS> states; | ||||
|         std::array<Core::HID::TouchState, MAX_FINGERS> states{}; | ||||
|     }; | ||||
|     static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size"); | ||||
|  | ||||
|     // 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{}; | ||||
|     struct TouchSharedMemory { | ||||
|         // 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"); | ||||
|         INSERT_PADDING_WORDS(0xF2); | ||||
|     }; | ||||
|     static_assert(sizeof(TouchSharedMemory) == 0x3000, "TouchSharedMemory is an invalid size"); | ||||
|  | ||||
|     std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers; | ||||
|     Core::HID::EmulatedConsole* console; | ||||
|     TouchScreenState next_state{}; | ||||
|     TouchSharedMemory* shared_memory = nullptr; | ||||
|     Core::HID::EmulatedConsole* console = nullptr; | ||||
|  | ||||
|     std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers{}; | ||||
| }; | ||||
| } // namespace Service::HID | ||||
|   | ||||
| @@ -10,28 +10,31 @@ | ||||
| namespace Service::HID { | ||||
| constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00; | ||||
|  | ||||
| Controller_XPad::Controller_XPad(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {} | ||||
| Controller_XPad::Controller_XPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) | ||||
|     : ControllerBase{hid_core_} { | ||||
|     static_assert(SHARED_MEMORY_OFFSET + sizeof(XpadSharedMemory) < shared_memory_size, | ||||
|                   "XpadSharedMemory is bigger than the shared memory"); | ||||
|     shared_memory = std::construct_at( | ||||
|         reinterpret_cast<XpadSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET)); | ||||
| } | ||||
| Controller_XPad::~Controller_XPad() = default; | ||||
|  | ||||
| void Controller_XPad::OnInit() {} | ||||
|  | ||||
| void Controller_XPad::OnRelease() {} | ||||
|  | ||||
| void Controller_XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | ||||
|                                std::size_t size) { | ||||
| void Controller_XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | ||||
|     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)); | ||||
|         shared_memory->basic_xpad_lifo.buffer_count = 0; | ||||
|         shared_memory->basic_xpad_lifo.buffer_tail = 0; | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const auto& last_entry = basic_xpad_lifo.ReadCurrentEntry().state; | ||||
|     const auto& last_entry = shared_memory->basic_xpad_lifo.ReadCurrentEntry().state; | ||||
|     next_state.sampling_number = last_entry.sampling_number + 1; | ||||
|     // TODO(ogniK): Update xpad states | ||||
|  | ||||
|     basic_xpad_lifo.WriteNextEntry(next_state); | ||||
|     std::memcpy(data + SHARED_MEMORY_OFFSET, &basic_xpad_lifo, sizeof(basic_xpad_lifo)); | ||||
|     shared_memory->basic_xpad_lifo.WriteNextEntry(next_state); | ||||
| } | ||||
|  | ||||
| } // namespace Service::HID | ||||
|   | ||||
| @@ -12,7 +12,7 @@ | ||||
| namespace Service::HID { | ||||
| class Controller_XPad final : public ControllerBase { | ||||
| public: | ||||
|     explicit Controller_XPad(Core::HID::HIDCore& hid_core_); | ||||
|     explicit Controller_XPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); | ||||
|     ~Controller_XPad() override; | ||||
|  | ||||
|     // Called when the controller is initialized | ||||
| @@ -22,7 +22,7 @@ public: | ||||
|     void OnRelease() override; | ||||
|  | ||||
|     // 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; | ||||
|     void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; | ||||
|  | ||||
| private: | ||||
|     // This is nn::hid::BasicXpadAttributeSet | ||||
| @@ -90,17 +90,23 @@ private: | ||||
|  | ||||
|     // 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; | ||||
|         s64 sampling_number{}; | ||||
|         BasicXpadAttributeSet attributes{}; | ||||
|         BasicXpadButtonSet pad_states{}; | ||||
|         Core::HID::AnalogStickState l_stick{}; | ||||
|         Core::HID::AnalogStickState r_stick{}; | ||||
|     }; | ||||
|     static_assert(sizeof(BasicXpadState) == 0x20, "BasicXpadState is an invalid size"); | ||||
|  | ||||
|     // 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"); | ||||
|     struct XpadSharedMemory { | ||||
|         // 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"); | ||||
|         INSERT_PADDING_WORDS(0x4E); | ||||
|     }; | ||||
|     static_assert(sizeof(XpadSharedMemory) == 0x400, "XpadSharedMemory is an invalid size"); | ||||
|  | ||||
|     BasicXpadState next_state{}; | ||||
|     XpadSharedMemory* shared_memory = nullptr; | ||||
| }; | ||||
| } // namespace Service::HID | ||||
|   | ||||
| @@ -39,7 +39,6 @@ constexpr auto pad_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; | ||||
| constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz) | ||||
| // TODO: Correct update rate for motion is 5ms. Check why some games don't behave at that speed | ||||
| constexpr auto motion_update_ns = std::chrono::nanoseconds{10 * 1000 * 1000}; // (10ms, 100Hz) | ||||
| constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; | ||||
|  | ||||
| IAppletResource::IAppletResource(Core::System& system_, | ||||
|                                  KernelHelpers::ServiceContext& service_context_) | ||||
| @@ -48,20 +47,20 @@ IAppletResource::IAppletResource(Core::System& system_, | ||||
|         {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"}, | ||||
|     }; | ||||
|     RegisterHandlers(functions); | ||||
|  | ||||
|     MakeController<Controller_DebugPad>(HidController::DebugPad); | ||||
|     MakeController<Controller_Touchscreen>(HidController::Touchscreen); | ||||
|     MakeController<Controller_Mouse>(HidController::Mouse); | ||||
|     MakeController<Controller_Keyboard>(HidController::Keyboard); | ||||
|     MakeController<Controller_XPad>(HidController::XPad); | ||||
|     MakeController<Controller_Stubbed>(HidController::HomeButton); | ||||
|     MakeController<Controller_Stubbed>(HidController::SleepButton); | ||||
|     MakeController<Controller_Stubbed>(HidController::CaptureButton); | ||||
|     MakeController<Controller_Stubbed>(HidController::InputDetector); | ||||
|     MakeController<Controller_Stubbed>(HidController::UniquePad); | ||||
|     MakeControllerWithServiceContext<Controller_NPad>(HidController::NPad); | ||||
|     MakeController<Controller_Gesture>(HidController::Gesture); | ||||
|     MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor); | ||||
|     u8* shared_memory = system.Kernel().GetHidSharedMem().GetPointer(); | ||||
|     MakeController<Controller_DebugPad>(HidController::DebugPad, shared_memory); | ||||
|     MakeController<Controller_Touchscreen>(HidController::Touchscreen, shared_memory); | ||||
|     MakeController<Controller_Mouse>(HidController::Mouse, shared_memory); | ||||
|     MakeController<Controller_Keyboard>(HidController::Keyboard, shared_memory); | ||||
|     MakeController<Controller_XPad>(HidController::XPad, shared_memory); | ||||
|     MakeController<Controller_Stubbed>(HidController::HomeButton, shared_memory); | ||||
|     MakeController<Controller_Stubbed>(HidController::SleepButton, shared_memory); | ||||
|     MakeController<Controller_Stubbed>(HidController::CaptureButton, shared_memory); | ||||
|     MakeController<Controller_Stubbed>(HidController::InputDetector, shared_memory); | ||||
|     MakeController<Controller_Stubbed>(HidController::UniquePad, shared_memory); | ||||
|     MakeControllerWithServiceContext<Controller_NPad>(HidController::NPad, shared_memory); | ||||
|     MakeController<Controller_Gesture>(HidController::Gesture, shared_memory); | ||||
|     MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor, shared_memory); | ||||
|  | ||||
|     // Homebrew doesn't try to activate some controllers, so we activate them by default | ||||
|     GetController<Controller_NPad>(HidController::NPad).ActivateController(); | ||||
| @@ -135,8 +134,7 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data, | ||||
|         if (controller == controllers[static_cast<size_t>(HidController::Mouse)]) { | ||||
|             continue; | ||||
|         } | ||||
|         controller->OnUpdate(core_timing, system.Kernel().GetHidSharedMem().GetPointer(), | ||||
|                              SHARED_MEMORY_SIZE); | ||||
|         controller->OnUpdate(core_timing); | ||||
|     } | ||||
|  | ||||
|     // If ns_late is higher than the update rate ignore the delay | ||||
| @@ -151,10 +149,8 @@ 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); | ||||
|     controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate(core_timing); | ||||
|     controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate(core_timing); | ||||
|  | ||||
|     // If ns_late is higher than the update rate ignore the delay | ||||
|     if (ns_late > mouse_keyboard_update_ns) { | ||||
| @@ -167,8 +163,7 @@ void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data, | ||||
| void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | ||||
|     auto& core_timing = system.CoreTiming(); | ||||
|  | ||||
|     controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate( | ||||
|         core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE); | ||||
|     controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate(core_timing); | ||||
|  | ||||
|     // If ns_late is higher than the update rate ignore the delay | ||||
|     if (ns_late > motion_update_ns) { | ||||
|   | ||||
| @@ -58,13 +58,14 @@ public: | ||||
|  | ||||
| private: | ||||
|     template <typename T> | ||||
|     void MakeController(HidController controller) { | ||||
|         controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(system.HIDCore()); | ||||
|     void MakeController(HidController controller, u8* shared_memory) { | ||||
|         controllers[static_cast<std::size_t>(controller)] = | ||||
|             std::make_unique<T>(system.HIDCore(), shared_memory); | ||||
|     } | ||||
|     template <typename T> | ||||
|     void MakeControllerWithServiceContext(HidController controller) { | ||||
|     void MakeControllerWithServiceContext(HidController controller, u8* shared_memory) { | ||||
|         controllers[static_cast<std::size_t>(controller)] = | ||||
|             std::make_unique<T>(system.HIDCore(), service_context); | ||||
|             std::make_unique<T>(system.HIDCore(), shared_memory, service_context); | ||||
|     } | ||||
|  | ||||
|     void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 bunnei
					bunnei