service: hid: Access shared memory directly

This commit is contained in:
Narr the Reg 2022-04-19 15:30:32 -05:00
parent 7f77aafe41
commit 61582efeb9
21 changed files with 347 additions and 305 deletions

View file

@ -9,9 +9,14 @@
namespace Service::HID { namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200; 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_} { : ControllerBase{hid_core_} {
console = hid_core.GetEmulatedConsole(); 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; Controller_ConsoleSixAxis::~Controller_ConsoleSixAxis() = default;
@ -20,8 +25,7 @@ void Controller_ConsoleSixAxis::OnInit() {}
void Controller_ConsoleSixAxis::OnRelease() {} void Controller_ConsoleSixAxis::OnRelease() {}
void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
std::size_t size) {
if (!IsControllerActivated() || !is_transfer_memory_set) { if (!IsControllerActivated() || !is_transfer_memory_set) {
seven_sixaxis_lifo.buffer_count = 0; seven_sixaxis_lifo.buffer_count = 0;
seven_sixaxis_lifo.buffer_tail = 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, -motion_status.quaternion.xyz.z,
}; };
console_six_axis.sampling_number++; shared_memory->sampling_number++;
console_six_axis.is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest; shared_memory->is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest;
console_six_axis.verticalization_error = motion_status.verticalization_error; shared_memory->verticalization_error = motion_status.verticalization_error;
console_six_axis.gyro_bias = motion_status.gyro_bias; 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 // Update seven six axis transfer memory
seven_sixaxis_lifo.WriteNextEntry(next_seven_sixaxis_state); seven_sixaxis_lifo.WriteNextEntry(next_seven_sixaxis_state);
std::memcpy(transfer_memory, &seven_sixaxis_lifo, sizeof(seven_sixaxis_lifo)); std::memcpy(transfer_memory, &seven_sixaxis_lifo, sizeof(seven_sixaxis_lifo));

View file

@ -17,7 +17,7 @@ class EmulatedConsole;
namespace Service::HID { namespace Service::HID {
class Controller_ConsoleSixAxis final : public ControllerBase { class Controller_ConsoleSixAxis final : public ControllerBase {
public: public:
explicit Controller_ConsoleSixAxis(Core::HID::HIDCore& hid_core_); explicit Controller_ConsoleSixAxis(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
~Controller_ConsoleSixAxis() override; ~Controller_ConsoleSixAxis() override;
// Called when the controller is initialized // Called when the controller is initialized
@ -27,7 +27,7 @@ public:
void OnRelease() override; void OnRelease() override;
// When the controller is requesting an update for the shared memory // 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 // Called on InitializeSevenSixAxisSensor
void SetTransferMemoryPointer(u8* t_mem); void SetTransferMemoryPointer(u8* t_mem);
@ -61,12 +61,13 @@ private:
Lifo<SevenSixAxisState, 0x21> seven_sixaxis_lifo{}; Lifo<SevenSixAxisState, 0x21> seven_sixaxis_lifo{};
static_assert(sizeof(seven_sixaxis_lifo) == 0xA70, "SevenSixAxisState is an invalid size"); static_assert(sizeof(seven_sixaxis_lifo) == 0xA70, "SevenSixAxisState is an invalid size");
ConsoleSharedMemory* shared_memory;
Core::HID::EmulatedConsole* console; Core::HID::EmulatedConsole* console;
u8* transfer_memory = nullptr; u8* transfer_memory = nullptr;
bool is_transfer_memory_set = false; bool is_transfer_memory_set = false;
u64 last_saved_timestamp{}; u64 last_saved_timestamp{};
u64 last_global_timestamp{}; u64 last_global_timestamp{};
ConsoleSharedMemory console_six_axis{};
SevenSixAxisState next_seven_sixaxis_state{}; SevenSixAxisState next_seven_sixaxis_state{};
}; };
} // namespace Service::HID } // namespace Service::HID

View file

@ -26,12 +26,10 @@ public:
virtual void OnRelease() = 0; virtual void OnRelease() = 0;
// When the controller is requesting an update for the shared memory // When the controller is requesting an update for the shared memory
virtual void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, virtual void OnUpdate(const Core::Timing::CoreTiming& core_timing) = 0;
std::size_t size) = 0;
// When the controller is requesting a motion update for the shared memory // When the controller is requesting a motion update for the shared memory
virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) {}
std::size_t size) {}
void ActivateController(); void ActivateController();
@ -40,6 +38,7 @@ public:
bool IsControllerActivated() const; bool IsControllerActivated() const;
static const std::size_t hid_entry_count = 17; static const std::size_t hid_entry_count = 17;
static const std::size_t shared_memory_size = 0x40000;
protected: protected:
bool is_activated{false}; bool is_activated{false};

View file

@ -13,8 +13,12 @@
namespace Service::HID { namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x00000; 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_} { : 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); controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other);
} }
@ -24,16 +28,14 @@ void Controller_DebugPad::OnInit() {}
void Controller_DebugPad::OnRelease() {} void Controller_DebugPad::OnRelease() {}
void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
std::size_t size) {
if (!IsControllerActivated()) { if (!IsControllerActivated()) {
debug_pad_lifo.buffer_count = 0; shared_memory->debug_pad_lifo.buffer_count = 0;
debug_pad_lifo.buffer_tail = 0; shared_memory->debug_pad_lifo.buffer_tail = 0;
std::memcpy(data + SHARED_MEMORY_OFFSET, &debug_pad_lifo, sizeof(debug_pad_lifo));
return; 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; next_state.sampling_number = last_entry.sampling_number + 1;
if (Settings::values.debug_pad_enabled) { 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; next_state.r_stick = stick_state.right;
} }
debug_pad_lifo.WriteNextEntry(next_state); shared_memory->debug_pad_lifo.WriteNextEntry(next_state);
std::memcpy(data + SHARED_MEMORY_OFFSET, &debug_pad_lifo, sizeof(debug_pad_lifo));
} }
} // namespace Service::HID } // namespace Service::HID

View file

@ -17,7 +17,7 @@ struct AnalogStickState;
namespace Service::HID { namespace Service::HID {
class Controller_DebugPad final : public ControllerBase { class Controller_DebugPad final : public ControllerBase {
public: public:
explicit Controller_DebugPad(Core::HID::HIDCore& hid_core_); explicit Controller_DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
~Controller_DebugPad() override; ~Controller_DebugPad() override;
// Called when the controller is initialized // Called when the controller is initialized
@ -27,7 +27,7 @@ public:
void OnRelease() override; void OnRelease() override;
// When the controller is requesting an update for the shared memory // 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: private:
// This is nn::hid::DebugPadAttribute // This is nn::hid::DebugPadAttribute
@ -49,11 +49,17 @@ private:
}; };
static_assert(sizeof(DebugPadState) == 0x20, "DebugPadState is an invalid state"); static_assert(sizeof(DebugPadState) == 0x20, "DebugPadState is an invalid state");
struct DebugPadSharedMemory {
// This is nn::hid::detail::DebugPadLifo // This is nn::hid::detail::DebugPadLifo
Lifo<DebugPadState, hid_entry_count> debug_pad_lifo{}; Lifo<DebugPadState, hid_entry_count> debug_pad_lifo{};
static_assert(sizeof(debug_pad_lifo) == 0x2C8, "debug_pad_lifo is an invalid size"); static_assert(sizeof(debug_pad_lifo) == 0x2C8, "debug_pad_lifo is an invalid size");
DebugPadState next_state{}; INSERT_PADDING_WORDS(0x4E);
};
static_assert(sizeof(DebugPadSharedMemory) == 0x400, "DebugPadSharedMemory is an invalid size");
DebugPadSharedMemory* shared_memory;
DebugPadState next_state{};
Core::HID::EmulatedController* controller; Core::HID::EmulatedController* controller;
}; };
} // namespace Service::HID } // namespace Service::HID

View file

@ -23,25 +23,28 @@ constexpr f32 Square(s32 num) {
return static_cast<f32>(num * 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(); console = hid_core.GetEmulatedConsole();
} }
Controller_Gesture::~Controller_Gesture() = default; Controller_Gesture::~Controller_Gesture() = default;
void Controller_Gesture::OnInit() { void Controller_Gesture::OnInit() {
gesture_lifo.buffer_count = 0; shared_memory->gesture_lifo.buffer_count = 0;
gesture_lifo.buffer_tail = 0; shared_memory->gesture_lifo.buffer_tail = 0;
force_update = true; force_update = true;
} }
void Controller_Gesture::OnRelease() {} void Controller_Gesture::OnRelease() {}
void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
std::size_t size) {
if (!IsControllerActivated()) { if (!IsControllerActivated()) {
gesture_lifo.buffer_count = 0; shared_memory->gesture_lifo.buffer_count = 0;
gesture_lifo.buffer_tail = 0; shared_memory->gesture_lifo.buffer_tail = 0;
std::memcpy(data + SHARED_MEMORY_OFFSET, &gesture_lifo, sizeof(gesture_lifo));
return; return;
} }
@ -49,15 +52,15 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u
GestureProperties gesture = GetGestureProperties(); GestureProperties gesture = GetGestureProperties();
f32 time_difference = 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 // Only update if necesary
if (!ShouldUpdateGesture(gesture, time_difference)) { if (!ShouldUpdateGesture(gesture, time_difference)) {
return; return;
} }
last_update_timestamp = gesture_lifo.timestamp; last_update_timestamp = shared_memory->gesture_lifo.timestamp;
UpdateGestureSharedMemory(data, size, gesture, time_difference);
} }
void Controller_Gesture::ReadTouchInput() { void Controller_Gesture::ReadTouchInput() {
@ -97,7 +100,7 @@ void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size,
GestureType type = GestureType::Idle; GestureType type = GestureType::Idle;
GestureAttribute attributes{}; 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 // Reset next state to default
next_state.sampling_number = last_entry.sampling_number + 1; 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; next_state.points = gesture.points;
last_gesture = gesture; last_gesture = gesture;
gesture_lifo.WriteNextEntry(next_state); shared_memory->gesture_lifo.WriteNextEntry(next_state);
std::memcpy(data + SHARED_MEMORY_OFFSET, &gesture_lifo, sizeof(gesture_lifo));
} }
void Controller_Gesture::NewGesture(GestureProperties& gesture, GestureType& type, 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 { 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() { Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() {

View file

@ -14,7 +14,7 @@
namespace Service::HID { namespace Service::HID {
class Controller_Gesture final : public ControllerBase { class Controller_Gesture final : public ControllerBase {
public: public:
explicit Controller_Gesture(Core::HID::HIDCore& hid_core_); explicit Controller_Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
~Controller_Gesture() override; ~Controller_Gesture() override;
// Called when the controller is initialized // Called when the controller is initialized
@ -24,7 +24,7 @@ public:
void OnRelease() override; void OnRelease() override;
// When the controller is requesting an update for the shared memory // 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: private:
static constexpr size_t MAX_FINGERS = 16; static constexpr size_t MAX_FINGERS = 16;
@ -92,6 +92,14 @@ private:
f32 angle{}; 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 // Reads input from all available input engines
void ReadTouchInput(); void ReadTouchInput();
@ -134,11 +142,8 @@ private:
// Returns the average distance, angle and middle point of the active fingers // Returns the average distance, angle and middle point of the active fingers
GestureProperties GetGestureProperties(); GestureProperties GetGestureProperties();
// This is nn::hid::detail::GestureLifo GestureSharedMemory* shared_memory;
Lifo<GestureState, hid_entry_count> gesture_lifo{};
static_assert(sizeof(gesture_lifo) == 0x708, "gesture_lifo is an invalid size");
GestureState next_state{}; GestureState next_state{};
Core::HID::EmulatedConsole* console; Core::HID::EmulatedConsole* console;
std::array<Core::HID::TouchFinger, MAX_POINTS> fingers{}; std::array<Core::HID::TouchFinger, MAX_POINTS> fingers{};

View file

@ -12,8 +12,12 @@
namespace Service::HID { namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; 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_} { : 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(); emulated_devices = hid_core.GetEmulatedDevices();
} }
@ -23,16 +27,14 @@ void Controller_Keyboard::OnInit() {}
void Controller_Keyboard::OnRelease() {} void Controller_Keyboard::OnRelease() {}
void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
std::size_t size) {
if (!IsControllerActivated()) { if (!IsControllerActivated()) {
keyboard_lifo.buffer_count = 0; shared_memory->keyboard_lifo.buffer_count = 0;
keyboard_lifo.buffer_tail = 0; shared_memory->keyboard_lifo.buffer_tail = 0;
std::memcpy(data + SHARED_MEMORY_OFFSET, &keyboard_lifo, sizeof(keyboard_lifo));
return; 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; next_state.sampling_number = last_entry.sampling_number + 1;
if (Settings::values.keyboard_enabled) { 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); next_state.attribute.is_connected.Assign(1);
} }
keyboard_lifo.WriteNextEntry(next_state); shared_memory->keyboard_lifo.WriteNextEntry(next_state);
std::memcpy(data + SHARED_MEMORY_OFFSET, &keyboard_lifo, sizeof(keyboard_lifo));
} }
} // namespace Service::HID } // namespace Service::HID

View file

@ -16,7 +16,7 @@ struct KeyboardKey;
namespace Service::HID { namespace Service::HID {
class Controller_Keyboard final : public ControllerBase { class Controller_Keyboard final : public ControllerBase {
public: public:
explicit Controller_Keyboard(Core::HID::HIDCore& hid_core_); explicit Controller_Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
~Controller_Keyboard() override; ~Controller_Keyboard() override;
// Called when the controller is initialized // Called when the controller is initialized
@ -26,7 +26,7 @@ public:
void OnRelease() override; void OnRelease() override;
// When the controller is requesting an update for the shared memory // 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: private:
// This is nn::hid::detail::KeyboardState // This is nn::hid::detail::KeyboardState
@ -38,11 +38,16 @@ private:
}; };
static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size"); static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size");
struct KeyboardSharedMemory {
// This is nn::hid::detail::KeyboardLifo // This is nn::hid::detail::KeyboardLifo
Lifo<KeyboardState, hid_entry_count> keyboard_lifo{}; Lifo<KeyboardState, hid_entry_count> keyboard_lifo{};
static_assert(sizeof(keyboard_lifo) == 0x3D8, "keyboard_lifo is an invalid size"); static_assert(sizeof(keyboard_lifo) == 0x3D8, "keyboard_lifo is an invalid size");
KeyboardState next_state{}; INSERT_PADDING_WORDS(0xA);
};
static_assert(sizeof(KeyboardSharedMemory) == 0x400, "KeyboardSharedMemory is an invalid size");
KeyboardSharedMemory* shared_memory;
KeyboardState next_state{};
Core::HID::EmulatedDevices* emulated_devices; Core::HID::EmulatedDevices* emulated_devices;
}; };
} // namespace Service::HID } // namespace Service::HID

View file

@ -12,7 +12,11 @@
namespace Service::HID { namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400; 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(); emulated_devices = hid_core.GetEmulatedDevices();
} }
@ -21,16 +25,14 @@ Controller_Mouse::~Controller_Mouse() = default;
void Controller_Mouse::OnInit() {} void Controller_Mouse::OnInit() {}
void Controller_Mouse::OnRelease() {} void Controller_Mouse::OnRelease() {}
void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
std::size_t size) {
if (!IsControllerActivated()) { if (!IsControllerActivated()) {
mouse_lifo.buffer_count = 0; shared_memory->mouse_lifo.buffer_count = 0;
mouse_lifo.buffer_tail = 0; shared_memory->mouse_lifo.buffer_tail = 0;
std::memcpy(data + SHARED_MEMORY_OFFSET, &mouse_lifo, sizeof(mouse_lifo));
return; 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.sampling_number = last_entry.sampling_number + 1;
next_state.attribute.raw = 0; next_state.attribute.raw = 0;
@ -50,8 +52,7 @@ void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
next_state.button = mouse_button_state; next_state.button = mouse_button_state;
} }
mouse_lifo.WriteNextEntry(next_state); shared_memory->mouse_lifo.WriteNextEntry(next_state);
std::memcpy(data + SHARED_MEMORY_OFFSET, &mouse_lifo, sizeof(mouse_lifo));
} }
} // namespace Service::HID } // namespace Service::HID

View file

@ -16,7 +16,7 @@ struct AnalogStickState;
namespace Service::HID { namespace Service::HID {
class Controller_Mouse final : public ControllerBase { class Controller_Mouse final : public ControllerBase {
public: public:
explicit Controller_Mouse(Core::HID::HIDCore& hid_core_); explicit Controller_Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
~Controller_Mouse() override; ~Controller_Mouse() override;
// Called when the controller is initialized // Called when the controller is initialized
@ -26,15 +26,20 @@ public:
void OnRelease() override; void OnRelease() override;
// When the controller is requesting an update for the shared memory // 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: private:
struct MouseSharedMemory {
// This is nn::hid::detail::MouseLifo // This is nn::hid::detail::MouseLifo
Lifo<Core::HID::MouseState, hid_entry_count> mouse_lifo{}; Lifo<Core::HID::MouseState, hid_entry_count> mouse_lifo{};
static_assert(sizeof(mouse_lifo) == 0x350, "mouse_lifo is an invalid size"); static_assert(sizeof(mouse_lifo) == 0x350, "mouse_lifo is an invalid size");
Core::HID::MouseState next_state{}; INSERT_PADDING_WORDS(0x2C);
};
static_assert(sizeof(MouseSharedMemory) == 0x400, "MouseSharedMemory is an invalid size");
Core::HID::AnalogStickState last_mouse_wheel_state; MouseSharedMemory* shared_memory;
Core::HID::MouseState next_state{};
Core::HID::AnalogStickState last_mouse_wheel_state{};
Core::HID::EmulatedDevices* emulated_devices; Core::HID::EmulatedDevices* emulated_devices;
}; };
} // namespace Service::HID } // namespace Service::HID

View file

@ -61,11 +61,14 @@ bool Controller_NPad::IsDeviceHandleValid(const Core::HID::SixAxisSensorHandle&
return npad_id && npad_type && device_index; 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_) KernelHelpers::ServiceContext& service_context_)
: ControllerBase{hid_core_}, service_context{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) { for (std::size_t i = 0; i < controller_data.size(); ++i) {
auto& controller = controller_data[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.device = hid_core.GetEmulatedControllerByIndex(i);
controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value = controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value =
Core::HID::DEFAULT_VIBRATION_VALUE; Core::HID::DEFAULT_VIBRATION_VALUE;
@ -115,11 +118,11 @@ void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type,
if (!controller.device->IsConnected()) { if (!controller.device->IsConnected()) {
return; return;
} }
auto& shared_memory = controller.shared_memory_entry; auto* shared_memory = controller.shared_memory;
const auto& battery_level = controller.device->GetBattery(); const auto& battery_level = controller.device->GetBattery();
shared_memory.battery_level_dual = battery_level.dual.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_left = battery_level.left.battery_level;
shared_memory.battery_level_right = battery_level.right.battery_level; shared_memory->battery_level_right = battery_level.right.battery_level;
break; break;
} }
default: default:
@ -134,99 +137,100 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
} }
LOG_DEBUG(Service_HID, "Npad connected {}", npad_id); LOG_DEBUG(Service_HID, "Npad connected {}", npad_id);
const auto controller_type = controller.device->GetNpadStyleIndex(); 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) { if (controller_type == Core::HID::NpadStyleIndex::None) {
controller.styleset_changed_event->GetWritableEvent().Signal(); controller.styleset_changed_event->GetWritableEvent().Signal();
return; return;
} }
shared_memory.style_tag.raw = Core::HID::NpadStyleSet::None; shared_memory->style_tag.raw = Core::HID::NpadStyleSet::None;
shared_memory.device_type.raw = 0; shared_memory->device_type.raw = 0;
shared_memory.system_properties.raw = 0; shared_memory->system_properties.raw = 0;
switch (controller_type) { switch (controller_type) {
case Core::HID::NpadStyleIndex::None: case Core::HID::NpadStyleIndex::None:
UNREACHABLE(); UNREACHABLE();
break; break;
case Core::HID::NpadStyleIndex::ProController: case Core::HID::NpadStyleIndex::ProController:
shared_memory.style_tag.fullkey.Assign(1); shared_memory->style_tag.fullkey.Assign(1);
shared_memory.device_type.fullkey.Assign(1); shared_memory->device_type.fullkey.Assign(1);
shared_memory.system_properties.is_vertical.Assign(1); shared_memory->system_properties.is_vertical.Assign(1);
shared_memory.system_properties.use_plus.Assign(1); shared_memory->system_properties.use_plus.Assign(1);
shared_memory.system_properties.use_minus.Assign(1); shared_memory->system_properties.use_minus.Assign(1);
shared_memory.applet_footer.type = AppletFooterUiType::SwitchProController; shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::SwitchProController;
break; break;
case Core::HID::NpadStyleIndex::Handheld: case Core::HID::NpadStyleIndex::Handheld:
shared_memory.style_tag.handheld.Assign(1); shared_memory->style_tag.handheld.Assign(1);
shared_memory.device_type.handheld_left.Assign(1); shared_memory->device_type.handheld_left.Assign(1);
shared_memory.device_type.handheld_right.Assign(1); shared_memory->device_type.handheld_right.Assign(1);
shared_memory.system_properties.is_vertical.Assign(1); shared_memory->system_properties.is_vertical.Assign(1);
shared_memory.system_properties.use_plus.Assign(1); shared_memory->system_properties.use_plus.Assign(1);
shared_memory.system_properties.use_minus.Assign(1); shared_memory->system_properties.use_minus.Assign(1);
shared_memory.system_properties.use_directional_buttons.Assign(1); shared_memory->system_properties.use_directional_buttons.Assign(1);
shared_memory.assignment_mode = NpadJoyAssignmentMode::Dual; shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual;
shared_memory.applet_footer.type = AppletFooterUiType::HandheldJoyConLeftJoyConRight; shared_memory->applet_nfc_xcd.applet_footer.type =
AppletFooterUiType::HandheldJoyConLeftJoyConRight;
break; break;
case Core::HID::NpadStyleIndex::JoyconDual: 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) { if (controller.is_dual_left_connected) {
shared_memory.device_type.joycon_left.Assign(1); shared_memory->device_type.joycon_left.Assign(1);
shared_memory.system_properties.use_minus.Assign(1); shared_memory->system_properties.use_minus.Assign(1);
} }
if (controller.is_dual_right_connected) { if (controller.is_dual_right_connected) {
shared_memory.device_type.joycon_right.Assign(1); shared_memory->device_type.joycon_right.Assign(1);
shared_memory.system_properties.use_plus.Assign(1); shared_memory->system_properties.use_plus.Assign(1);
} }
shared_memory.system_properties.use_directional_buttons.Assign(1); shared_memory->system_properties.use_directional_buttons.Assign(1);
shared_memory.system_properties.is_vertical.Assign(1); shared_memory->system_properties.is_vertical.Assign(1);
shared_memory.assignment_mode = NpadJoyAssignmentMode::Dual; shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual;
if (controller.is_dual_left_connected && controller.is_dual_right_connected) { 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) { } 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 { } else {
shared_memory.applet_footer.type = AppletFooterUiType::JoyDualRightOnly; shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualRightOnly;
} }
break; break;
case Core::HID::NpadStyleIndex::JoyconLeft: case Core::HID::NpadStyleIndex::JoyconLeft:
shared_memory.style_tag.joycon_left.Assign(1); shared_memory->style_tag.joycon_left.Assign(1);
shared_memory.device_type.joycon_left.Assign(1); shared_memory->device_type.joycon_left.Assign(1);
shared_memory.system_properties.is_horizontal.Assign(1); shared_memory->system_properties.is_horizontal.Assign(1);
shared_memory.system_properties.use_minus.Assign(1); shared_memory->system_properties.use_minus.Assign(1);
shared_memory.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal; shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal;
break; break;
case Core::HID::NpadStyleIndex::JoyconRight: case Core::HID::NpadStyleIndex::JoyconRight:
shared_memory.style_tag.joycon_right.Assign(1); shared_memory->style_tag.joycon_right.Assign(1);
shared_memory.device_type.joycon_right.Assign(1); shared_memory->device_type.joycon_right.Assign(1);
shared_memory.system_properties.is_horizontal.Assign(1); shared_memory->system_properties.is_horizontal.Assign(1);
shared_memory.system_properties.use_plus.Assign(1); shared_memory->system_properties.use_plus.Assign(1);
shared_memory.applet_footer.type = AppletFooterUiType::JoyRightHorizontal; shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyRightHorizontal;
break; break;
case Core::HID::NpadStyleIndex::GameCube: case Core::HID::NpadStyleIndex::GameCube:
shared_memory.style_tag.gamecube.Assign(1); shared_memory->style_tag.gamecube.Assign(1);
shared_memory.device_type.fullkey.Assign(1); shared_memory->device_type.fullkey.Assign(1);
shared_memory.system_properties.is_vertical.Assign(1); shared_memory->system_properties.is_vertical.Assign(1);
shared_memory.system_properties.use_plus.Assign(1); shared_memory->system_properties.use_plus.Assign(1);
break; break;
case Core::HID::NpadStyleIndex::Pokeball: case Core::HID::NpadStyleIndex::Pokeball:
shared_memory.style_tag.palma.Assign(1); shared_memory->style_tag.palma.Assign(1);
shared_memory.device_type.palma.Assign(1); shared_memory->device_type.palma.Assign(1);
break; break;
case Core::HID::NpadStyleIndex::NES: case Core::HID::NpadStyleIndex::NES:
shared_memory.style_tag.lark.Assign(1); shared_memory->style_tag.lark.Assign(1);
shared_memory.device_type.fullkey.Assign(1); shared_memory->device_type.fullkey.Assign(1);
break; break;
case Core::HID::NpadStyleIndex::SNES: case Core::HID::NpadStyleIndex::SNES:
shared_memory.style_tag.lucia.Assign(1); shared_memory->style_tag.lucia.Assign(1);
shared_memory.device_type.fullkey.Assign(1); shared_memory->device_type.fullkey.Assign(1);
shared_memory.applet_footer.type = AppletFooterUiType::Lucia; shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::Lucia;
break; break;
case Core::HID::NpadStyleIndex::N64: case Core::HID::NpadStyleIndex::N64:
shared_memory.style_tag.lagoon.Assign(1); shared_memory->style_tag.lagoon.Assign(1);
shared_memory.device_type.fullkey.Assign(1); shared_memory->device_type.fullkey.Assign(1);
shared_memory.applet_footer.type = AppletFooterUiType::Lagon; shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::Lagon;
break; break;
case Core::HID::NpadStyleIndex::SegaGenesis: case Core::HID::NpadStyleIndex::SegaGenesis:
shared_memory.style_tag.lager.Assign(1); shared_memory->style_tag.lager.Assign(1);
shared_memory.device_type.fullkey.Assign(1); shared_memory->device_type.fullkey.Assign(1);
break; break;
default: default:
break; break;
@ -234,23 +238,23 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
const auto& body_colors = controller.device->GetColors(); const auto& body_colors = controller.device->GetColors();
shared_memory.fullkey_color.attribute = ColorAttribute::Ok; shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
shared_memory.fullkey_color.fullkey = body_colors.fullkey; shared_memory->fullkey_color.fullkey = body_colors.fullkey;
shared_memory.joycon_color.attribute = ColorAttribute::Ok; shared_memory->joycon_color.attribute = ColorAttribute::Ok;
shared_memory.joycon_color.left = body_colors.left; shared_memory->joycon_color.left = body_colors.left;
shared_memory.joycon_color.right = body_colors.right; shared_memory->joycon_color.right = body_colors.right;
// TODO: Investigate when we should report all batery types // TODO: Investigate when we should report all batery types
const auto& battery_level = controller.device->GetBattery(); const auto& battery_level = controller.device->GetBattery();
shared_memory.battery_level_dual = battery_level.dual.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_left = battery_level.left.battery_level;
shared_memory.battery_level_right = battery_level.right.battery_level; shared_memory->battery_level_right = battery_level.right.battery_level;
controller.is_connected = true; controller.is_connected = true;
controller.device->Connect(); controller.device->Connect();
SignalStyleSetChangedEvent(npad_id); SignalStyleSetChangedEvent(npad_id);
WriteEmptyEntry(controller.shared_memory_entry); WriteEmptyEntry(controller.shared_memory);
} }
void Controller_NPad::OnInit() { void Controller_NPad::OnInit() {
@ -270,12 +274,12 @@ void Controller_NPad::OnInit() {
// Prefill controller buffers // Prefill controller buffers
for (auto& controller : controller_data) { for (auto& controller : controller_data) {
auto& npad = controller.shared_memory_entry; auto* npad = controller.shared_memory;
npad.fullkey_color = { npad->fullkey_color = {
.attribute = ColorAttribute::NoController, .attribute = ColorAttribute::NoController,
.fullkey = {}, .fullkey = {},
}; };
npad.joycon_color = { npad->joycon_color = {
.attribute = ColorAttribute::NoController, .attribute = ColorAttribute::NoController,
.left = {}, .left = {},
.right = {}, .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{}; NPadGenericState dummy_pad_state{};
NpadGcTriggerState dummy_gc_state{}; NpadGcTriggerState dummy_gc_state{};
dummy_pad_state.sampling_number = npad.fullkey_lifo.ReadCurrentEntry().sampling_number + 1; dummy_pad_state.sampling_number = npad->fullkey_lifo.ReadCurrentEntry().sampling_number + 1;
npad.fullkey_lifo.WriteNextEntry(dummy_pad_state); npad->fullkey_lifo.WriteNextEntry(dummy_pad_state);
dummy_pad_state.sampling_number = npad.handheld_lifo.ReadCurrentEntry().sampling_number + 1; dummy_pad_state.sampling_number = npad->handheld_lifo.ReadCurrentEntry().sampling_number + 1;
npad.handheld_lifo.WriteNextEntry(dummy_pad_state); npad->handheld_lifo.WriteNextEntry(dummy_pad_state);
dummy_pad_state.sampling_number = npad.joy_dual_lifo.ReadCurrentEntry().sampling_number + 1; dummy_pad_state.sampling_number = npad->joy_dual_lifo.ReadCurrentEntry().sampling_number + 1;
npad.joy_dual_lifo.WriteNextEntry(dummy_pad_state); npad->joy_dual_lifo.WriteNextEntry(dummy_pad_state);
dummy_pad_state.sampling_number = npad.joy_left_lifo.ReadCurrentEntry().sampling_number + 1; dummy_pad_state.sampling_number = npad->joy_left_lifo.ReadCurrentEntry().sampling_number + 1;
npad.joy_left_lifo.WriteNextEntry(dummy_pad_state); npad->joy_left_lifo.WriteNextEntry(dummy_pad_state);
dummy_pad_state.sampling_number = npad.joy_right_lifo.ReadCurrentEntry().sampling_number + 1; dummy_pad_state.sampling_number = npad->joy_right_lifo.ReadCurrentEntry().sampling_number + 1;
npad.joy_right_lifo.WriteNextEntry(dummy_pad_state); npad->joy_right_lifo.WriteNextEntry(dummy_pad_state);
dummy_pad_state.sampling_number = npad.palma_lifo.ReadCurrentEntry().sampling_number + 1; dummy_pad_state.sampling_number = npad->palma_lifo.ReadCurrentEntry().sampling_number + 1;
npad.palma_lifo.WriteNextEntry(dummy_pad_state); npad->palma_lifo.WriteNextEntry(dummy_pad_state);
dummy_pad_state.sampling_number = npad.system_ext_lifo.ReadCurrentEntry().sampling_number + 1; dummy_pad_state.sampling_number = npad->system_ext_lifo.ReadCurrentEntry().sampling_number + 1;
npad.system_ext_lifo.WriteNextEntry(dummy_pad_state); npad->system_ext_lifo.WriteNextEntry(dummy_pad_state);
dummy_gc_state.sampling_number = npad.gc_trigger_lifo.ReadCurrentEntry().sampling_number + 1; dummy_gc_state.sampling_number = npad->gc_trigger_lifo.ReadCurrentEntry().sampling_number + 1;
npad.gc_trigger_lifo.WriteNextEntry(dummy_gc_state); npad->gc_trigger_lifo.WriteNextEntry(dummy_gc_state);
} }
void Controller_NPad::OnRelease() { 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, void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
std::size_t data_len) {
if (!IsControllerActivated()) { if (!IsControllerActivated()) {
return; return;
} }
for (std::size_t i = 0; i < controller_data.size(); ++i) { for (std::size_t i = 0; i < controller_data.size(); ++i) {
auto& controller = controller_data[i]; auto& controller = controller_data[i];
auto& npad = controller.shared_memory_entry; auto* npad = controller.shared_memory;
const auto& controller_type = controller.device->GetNpadStyleIndex(); const auto& controller_type = controller.device->GetNpadStyleIndex();
if (controller_type == Core::HID::NpadStyleIndex::None || if (controller_type == Core::HID::NpadStyleIndex::None ||
!controller.device->IsConnected()) { !controller.device->IsConnected()) {
// Refresh shared memory
std::memcpy(data + NPAD_OFFSET + (i * sizeof(NpadInternalState)),
&controller.shared_memory_entry, sizeof(NpadInternalState));
continue; continue;
} }
@ -415,8 +415,8 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
libnx_state.connection_status.is_wired.Assign(1); libnx_state.connection_status.is_wired.Assign(1);
pad_state.sampling_number = pad_state.sampling_number =
npad.fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; npad->fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1;
npad.fullkey_lifo.WriteNextEntry(pad_state); npad->fullkey_lifo.WriteNextEntry(pad_state);
break; break;
case Core::HID::NpadStyleIndex::Handheld: case Core::HID::NpadStyleIndex::Handheld:
pad_state.connection_status.raw = 0; 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_left_wired.Assign(1);
libnx_state.connection_status.is_right_wired.Assign(1); libnx_state.connection_status.is_right_wired.Assign(1);
pad_state.sampling_number = pad_state.sampling_number =
npad.handheld_lifo.ReadCurrentEntry().state.sampling_number + 1; npad->handheld_lifo.ReadCurrentEntry().state.sampling_number + 1;
npad.handheld_lifo.WriteNextEntry(pad_state); npad->handheld_lifo.WriteNextEntry(pad_state);
break; break;
case Core::HID::NpadStyleIndex::JoyconDual: case Core::HID::NpadStyleIndex::JoyconDual:
pad_state.connection_status.raw = 0; 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 = pad_state.sampling_number =
npad.joy_dual_lifo.ReadCurrentEntry().state.sampling_number + 1; npad->joy_dual_lifo.ReadCurrentEntry().state.sampling_number + 1;
npad.joy_dual_lifo.WriteNextEntry(pad_state); npad->joy_dual_lifo.WriteNextEntry(pad_state);
break; break;
case Core::HID::NpadStyleIndex::JoyconLeft: case Core::HID::NpadStyleIndex::JoyconLeft:
pad_state.connection_status.raw = 0; 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); libnx_state.connection_status.is_left_connected.Assign(1);
pad_state.sampling_number = pad_state.sampling_number =
npad.joy_left_lifo.ReadCurrentEntry().state.sampling_number + 1; npad->joy_left_lifo.ReadCurrentEntry().state.sampling_number + 1;
npad.joy_left_lifo.WriteNextEntry(pad_state); npad->joy_left_lifo.WriteNextEntry(pad_state);
break; break;
case Core::HID::NpadStyleIndex::JoyconRight: case Core::HID::NpadStyleIndex::JoyconRight:
pad_state.connection_status.raw = 0; 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); libnx_state.connection_status.is_right_connected.Assign(1);
pad_state.sampling_number = pad_state.sampling_number =
npad.joy_right_lifo.ReadCurrentEntry().state.sampling_number + 1; npad->joy_right_lifo.ReadCurrentEntry().state.sampling_number + 1;
npad.joy_right_lifo.WriteNextEntry(pad_state); npad->joy_right_lifo.WriteNextEntry(pad_state);
break; break;
case Core::HID::NpadStyleIndex::GameCube: case Core::HID::NpadStyleIndex::GameCube:
pad_state.connection_status.raw = 0; 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); libnx_state.connection_status.is_wired.Assign(1);
pad_state.sampling_number = pad_state.sampling_number =
npad.fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; npad->fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1;
trigger_state.sampling_number = trigger_state.sampling_number =
npad.gc_trigger_lifo.ReadCurrentEntry().state.sampling_number + 1; npad->gc_trigger_lifo.ReadCurrentEntry().state.sampling_number + 1;
npad.fullkey_lifo.WriteNextEntry(pad_state); npad->fullkey_lifo.WriteNextEntry(pad_state);
npad.gc_trigger_lifo.WriteNextEntry(trigger_state); npad->gc_trigger_lifo.WriteNextEntry(trigger_state);
break; break;
case Core::HID::NpadStyleIndex::Pokeball: case Core::HID::NpadStyleIndex::Pokeball:
pad_state.connection_status.raw = 0; pad_state.connection_status.raw = 0;
pad_state.connection_status.is_connected.Assign(1); pad_state.connection_status.is_connected.Assign(1);
pad_state.sampling_number = pad_state.sampling_number =
npad.palma_lifo.ReadCurrentEntry().state.sampling_number + 1; npad->palma_lifo.ReadCurrentEntry().state.sampling_number + 1;
npad.palma_lifo.WriteNextEntry(pad_state); npad->palma_lifo.WriteNextEntry(pad_state);
break; break;
default: default:
break; 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.npad_buttons.raw = pad_state.npad_buttons.raw;
libnx_state.l_stick = pad_state.l_stick; libnx_state.l_stick = pad_state.l_stick;
libnx_state.r_stick = pad_state.r_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); 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, void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) {
std::size_t data_len) {
if (!IsControllerActivated()) { if (!IsControllerActivated()) {
return; return;
} }
@ -524,7 +520,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing
continue; continue;
} }
auto& npad = controller.shared_memory_entry; auto* npad = controller.shared_memory;
const auto& motion_state = controller.device->GetMotions(); const auto& motion_state = controller.device->GetMotions();
auto& sixaxis_fullkey_state = controller.sixaxis_fullkey_state; auto& sixaxis_fullkey_state = controller.sixaxis_fullkey_state;
auto& sixaxis_handheld_state = controller.sixaxis_handheld_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 = 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 = 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 = 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 = 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 = 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 = 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) { if (Core::HID::IndexToNpadIdType(i) == Core::HID::NpadIdType::Handheld) {
// This buffer only is updated on handheld on HW // 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 { } else {
// Handheld doesn't update this buffer on HW // 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_left_lifo.WriteNextEntry(sixaxis_dual_left_state);
npad.sixaxis_dual_right_lifo.WriteNextEntry(sixaxis_dual_right_state); npad->sixaxis_dual_right_lifo.WriteNextEntry(sixaxis_dual_right_state);
npad.sixaxis_left_lifo.WriteNextEntry(sixaxis_left_lifo_state); npad->sixaxis_left_lifo.WriteNextEntry(sixaxis_left_lifo_state);
npad.sixaxis_right_lifo.WriteNextEntry(sixaxis_right_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));
} }
} }
@ -713,8 +707,8 @@ void Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceTy
} }
auto& controller = GetControllerFromNpadIdType(npad_id); auto& controller = GetControllerFromNpadIdType(npad_id);
if (controller.shared_memory_entry.assignment_mode != assignment_mode) { if (controller.shared_memory->assignment_mode != assignment_mode) {
controller.shared_memory_entry.assignment_mode = assignment_mode; controller.shared_memory->assignment_mode = assignment_mode;
} }
if (!controller.device->IsConnected()) { if (!controller.device->IsConnected()) {
@ -981,32 +975,32 @@ void Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) {
controller.vibration[device_idx].device_mounted = false; controller.vibration[device_idx].device_mounted = false;
} }
auto& shared_memory_entry = controller.shared_memory_entry; auto* shared_memory = controller.shared_memory;
// Don't reset shared_memory_entry.assignment_mode this value is persistent // Don't reset shared_memory->assignment_mode this value is persistent
shared_memory_entry.style_tag.raw = Core::HID::NpadStyleSet::None; // Zero out shared_memory->style_tag.raw = Core::HID::NpadStyleSet::None; // Zero out
shared_memory_entry.device_type.raw = 0; shared_memory->device_type.raw = 0;
shared_memory_entry.system_properties.raw = 0; shared_memory->system_properties.raw = 0;
shared_memory_entry.button_properties.raw = 0; shared_memory->button_properties.raw = 0;
shared_memory_entry.battery_level_dual = 0; shared_memory->battery_level_dual = 0;
shared_memory_entry.battery_level_left = 0; shared_memory->battery_level_left = 0;
shared_memory_entry.battery_level_right = 0; shared_memory->battery_level_right = 0;
shared_memory_entry.fullkey_color = { shared_memory->fullkey_color = {
.attribute = ColorAttribute::NoController, .attribute = ColorAttribute::NoController,
.fullkey = {}, .fullkey = {},
}; };
shared_memory_entry.joycon_color = { shared_memory->joycon_color = {
.attribute = ColorAttribute::NoController, .attribute = ColorAttribute::NoController,
.left = {}, .left = {},
.right = {}, .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_left_connected = true;
controller.is_dual_right_connected = true; controller.is_dual_right_connected = true;
controller.is_connected = false; controller.is_connected = false;
controller.device->Disconnect(); controller.device->Disconnect();
SignalStyleSetChangedEvent(npad_id); SignalStyleSetChangedEvent(npad_id);
WriteEmptyEntry(controller.shared_memory_entry); WriteEmptyEntry(shared_memory);
} }
ResultCode Controller_NPad::SetGyroscopeZeroDriftMode(Core::HID::SixAxisSensorHandle sixaxis_handle, ResultCode Controller_NPad::SetGyroscopeZeroDriftMode(Core::HID::SixAxisSensorHandle sixaxis_handle,

View file

@ -35,7 +35,7 @@ namespace Service::HID {
class Controller_NPad final : public ControllerBase { class Controller_NPad final : public ControllerBase {
public: 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_); KernelHelpers::ServiceContext& service_context_);
~Controller_NPad() override; ~Controller_NPad() override;
@ -46,11 +46,10 @@ public:
void OnRelease() override; void OnRelease() override;
// When the controller is requesting an update for the shared memory // 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 // When the controller is requesting a motion update for the shared memory
void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) override;
std::size_t size) override;
// This is nn::hid::GyroscopeZeroDriftMode // This is nn::hid::GyroscopeZeroDriftMode
enum class GyroscopeZeroDriftMode : u32 { enum class GyroscopeZeroDriftMode : u32 {
@ -188,6 +187,8 @@ public:
static bool IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle); static bool IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle);
private: private:
static const std::size_t NPAD_COUNT = 10;
// This is nn::hid::detail::ColorAttribute // This is nn::hid::detail::ColorAttribute
enum class ColorAttribute : u32 { enum class ColorAttribute : u32 {
Ok = 0, Ok = 0,
@ -409,6 +410,13 @@ private:
U, U,
}; };
struct AppletNfcXcd {
union {
AppletFooterUi applet_footer{};
Lifo<NfcXcdDeviceHandleStateImpl, 0x2> nfc_xcd_device_lifo;
};
};
// This is nn::hid::detail::NpadInternalState // This is nn::hid::detail::NpadInternalState
struct NpadInternalState { struct NpadInternalState {
Core::HID::NpadStyleTag style_tag{Core::HID::NpadStyleSet::None}; 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_dual{};
Core::HID::NpadBatteryLevel battery_level_left{}; Core::HID::NpadBatteryLevel battery_level_left{};
Core::HID::NpadBatteryLevel battery_level_right{}; Core::HID::NpadBatteryLevel battery_level_right{};
union { AppletNfcXcd applet_nfc_xcd{};
AppletFooterUi applet_footer{};
Lifo<NfcXcdDeviceHandleStateImpl, 0x2> nfc_xcd_device_lifo;
};
INSERT_PADDING_BYTES(0x20); // Unknown INSERT_PADDING_BYTES(0x20); // Unknown
Lifo<NpadGcTriggerState, hid_entry_count> gc_trigger_lifo{}; Lifo<NpadGcTriggerState, hid_entry_count> gc_trigger_lifo{};
NpadLarkType lark_type_l_and_main{}; NpadLarkType lark_type_l_and_main{};
@ -467,7 +472,7 @@ private:
struct NpadControllerData { struct NpadControllerData {
Core::HID::EmulatedController* device; Core::HID::EmulatedController* device;
Kernel::KEvent* styleset_changed_event{}; Kernel::KEvent* styleset_changed_event{};
NpadInternalState shared_memory_entry{}; NpadInternalState* shared_memory;
std::array<VibrationData, 2> vibration{}; std::array<VibrationData, 2> vibration{};
bool unintended_home_button_input_protection{}; bool unintended_home_button_input_protection{};
@ -505,7 +510,7 @@ private:
void InitNewlyAddedController(Core::HID::NpadIdType npad_id); void InitNewlyAddedController(Core::HID::NpadIdType npad_id);
bool IsControllerSupported(Core::HID::NpadStyleIndex controller) const; bool IsControllerSupported(Core::HID::NpadStyleIndex controller) const;
void RequestPadStateUpdate(Core::HID::NpadIdType npad_id); void RequestPadStateUpdate(Core::HID::NpadIdType npad_id);
void WriteEmptyEntry(NpadInternalState& npad); void WriteEmptyEntry(NpadInternalState* npad);
NpadControllerData& GetControllerFromHandle( NpadControllerData& GetControllerFromHandle(
const Core::HID::SixAxisSensorHandle& device_handle); const Core::HID::SixAxisSensorHandle& device_handle);
@ -520,7 +525,7 @@ private:
std::atomic<u64> press_state{}; std::atomic<u64> press_state{};
std::array<NpadControllerData, 10> controller_data{}; std::array<NpadControllerData, NPAD_COUNT> controller_data{};
KernelHelpers::ServiceContext& service_context; KernelHelpers::ServiceContext& service_context;
std::mutex mutex; std::mutex mutex;
std::vector<Core::HID::NpadIdType> supported_npad_id_types{}; std::vector<Core::HID::NpadIdType> supported_npad_id_types{};

View file

@ -9,15 +9,18 @@
namespace Service::HID { 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; Controller_Stubbed::~Controller_Stubbed() = default;
void Controller_Stubbed::OnInit() {} void Controller_Stubbed::OnInit() {}
void Controller_Stubbed::OnRelease() {} void Controller_Stubbed::OnRelease() {}
void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
std::size_t size) {
if (!smart_update) { if (!smart_update) {
return; return;
} }
@ -28,7 +31,7 @@ void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing, u
header.entry_count = 0; header.entry_count = 0;
header.last_entry_index = 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) { void Controller_Stubbed::SetCommonHeaderOffset(std::size_t off) {

View file

@ -9,7 +9,7 @@
namespace Service::HID { namespace Service::HID {
class Controller_Stubbed final : public ControllerBase { class Controller_Stubbed final : public ControllerBase {
public: public:
explicit Controller_Stubbed(Core::HID::HIDCore& hid_core_); explicit Controller_Stubbed(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
~Controller_Stubbed() override; ~Controller_Stubbed() override;
// Called when the controller is initialized // Called when the controller is initialized
@ -19,7 +19,7 @@ public:
void OnRelease() override; void OnRelease() override;
// When the controller is requesting an update for the shared memory // 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); void SetCommonHeaderOffset(std::size_t off);
@ -32,6 +32,7 @@ private:
}; };
static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size");
u8* raw_shared_memory;
bool smart_update{}; bool smart_update{};
std::size_t common_offset{}; std::size_t common_offset{};
}; };

View file

@ -15,8 +15,12 @@
namespace Service::HID { namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; 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_} { : 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(); console = hid_core.GetEmulatedConsole();
} }
@ -26,14 +30,12 @@ void Controller_Touchscreen::OnInit() {}
void Controller_Touchscreen::OnRelease() {} void Controller_Touchscreen::OnRelease() {}
void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
std::size_t size) { shared_memory->touch_screen_lifo.timestamp = core_timing.GetCPUTicks();
touch_screen_lifo.timestamp = core_timing.GetCPUTicks();
if (!IsControllerActivated()) { if (!IsControllerActivated()) {
touch_screen_lifo.buffer_count = 0; shared_memory->touch_screen_lifo.buffer_count = 0;
touch_screen_lifo.buffer_tail = 0; shared_memory->touch_screen_lifo.buffer_tail = 0;
std::memcpy(data, &touch_screen_lifo, sizeof(touch_screen_lifo));
return; return;
} }
@ -74,7 +76,7 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin
static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter)); static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter));
const u64 tick = core_timing.GetCPUTicks(); 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.sampling_number = last_entry.sampling_number + 1;
next_state.entry_count = static_cast<s32>(active_fingers_count); next_state.entry_count = static_cast<s32>(active_fingers_count);
@ -106,8 +108,7 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin
} }
} }
touch_screen_lifo.WriteNextEntry(next_state); shared_memory->touch_screen_lifo.WriteNextEntry(next_state);
std::memcpy(data + SHARED_MEMORY_OFFSET, &touch_screen_lifo, sizeof(touch_screen_lifo));
} }
} // namespace Service::HID } // namespace Service::HID

View file

@ -32,7 +32,7 @@ public:
static_assert(sizeof(TouchScreenConfigurationForNx) == 0x17, static_assert(sizeof(TouchScreenConfigurationForNx) == 0x17,
"TouchScreenConfigurationForNx is an invalid size"); "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; ~Controller_Touchscreen() override;
// Called when the controller is initialized // Called when the controller is initialized
@ -42,7 +42,7 @@ public:
void OnRelease() override; void OnRelease() override;
// When the controller is requesting an update for the shared memory // 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: private:
static constexpr std::size_t MAX_FINGERS = 16; static constexpr std::size_t MAX_FINGERS = 16;
@ -56,11 +56,17 @@ private:
}; };
static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size"); static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size");
struct TouchSharedMemory {
// This is nn::hid::detail::TouchScreenLifo // This is nn::hid::detail::TouchScreenLifo
Lifo<TouchScreenState, hid_entry_count> touch_screen_lifo{}; Lifo<TouchScreenState, hid_entry_count> touch_screen_lifo{};
static_assert(sizeof(touch_screen_lifo) == 0x2C38, "touch_screen_lifo is an invalid size"); static_assert(sizeof(touch_screen_lifo) == 0x2C38, "touch_screen_lifo is an invalid size");
TouchScreenState next_state{}; INSERT_PADDING_WORDS(0xF2);
};
static_assert(sizeof(TouchSharedMemory) == 0x3000, "TouchSharedMemory is an invalid size");
TouchSharedMemory* shared_memory;
TouchScreenState next_state{};
std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers; std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers;
Core::HID::EmulatedConsole* console; Core::HID::EmulatedConsole* console;
}; };

View file

@ -10,28 +10,30 @@
namespace Service::HID { namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00; 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; Controller_XPad::~Controller_XPad() = default;
void Controller_XPad::OnInit() {} void Controller_XPad::OnInit() {}
void Controller_XPad::OnRelease() {} void Controller_XPad::OnRelease() {}
void Controller_XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, void Controller_XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
std::size_t size) {
if (!IsControllerActivated()) { if (!IsControllerActivated()) {
basic_xpad_lifo.buffer_count = 0; shared_memory->basic_xpad_lifo.buffer_count = 0;
basic_xpad_lifo.buffer_tail = 0; shared_memory->basic_xpad_lifo.buffer_tail = 0;
std::memcpy(data + SHARED_MEMORY_OFFSET, &basic_xpad_lifo, sizeof(basic_xpad_lifo));
return; 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; next_state.sampling_number = last_entry.sampling_number + 1;
// TODO(ogniK): Update xpad states // TODO(ogniK): Update xpad states
basic_xpad_lifo.WriteNextEntry(next_state); shared_memory->basic_xpad_lifo.WriteNextEntry(next_state);
std::memcpy(data + SHARED_MEMORY_OFFSET, &basic_xpad_lifo, sizeof(basic_xpad_lifo));
} }
} // namespace Service::HID } // namespace Service::HID

View file

@ -12,7 +12,7 @@
namespace Service::HID { namespace Service::HID {
class Controller_XPad final : public ControllerBase { class Controller_XPad final : public ControllerBase {
public: public:
explicit Controller_XPad(Core::HID::HIDCore& hid_core_); explicit Controller_XPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
~Controller_XPad() override; ~Controller_XPad() override;
// Called when the controller is initialized // Called when the controller is initialized
@ -22,7 +22,7 @@ public:
void OnRelease() override; void OnRelease() override;
// When the controller is requesting an update for the shared memory // 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: private:
// This is nn::hid::BasicXpadAttributeSet // This is nn::hid::BasicXpadAttributeSet
@ -98,9 +98,15 @@ private:
}; };
static_assert(sizeof(BasicXpadState) == 0x20, "BasicXpadState is an invalid size"); static_assert(sizeof(BasicXpadState) == 0x20, "BasicXpadState is an invalid size");
struct XpadSharedMemory {
// This is nn::hid::detail::BasicXpadLifo // This is nn::hid::detail::BasicXpadLifo
Lifo<BasicXpadState, hid_entry_count> basic_xpad_lifo{}; Lifo<BasicXpadState, hid_entry_count> basic_xpad_lifo{};
static_assert(sizeof(basic_xpad_lifo) == 0x2C8, "basic_xpad_lifo is an invalid size"); 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");
XpadSharedMemory* shared_memory;
BasicXpadState next_state{}; BasicXpadState next_state{};
}; };
} // namespace Service::HID } // namespace Service::HID

View file

@ -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) 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 // 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 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_, IAppletResource::IAppletResource(Core::System& system_,
KernelHelpers::ServiceContext& service_context_) KernelHelpers::ServiceContext& service_context_)
@ -48,20 +47,20 @@ IAppletResource::IAppletResource(Core::System& system_,
{0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"}, {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
}; };
RegisterHandlers(functions); RegisterHandlers(functions);
u8* shared_memory = system.Kernel().GetHidSharedMem().GetPointer();
MakeController<Controller_DebugPad>(HidController::DebugPad); MakeController<Controller_DebugPad>(HidController::DebugPad, shared_memory);
MakeController<Controller_Touchscreen>(HidController::Touchscreen); MakeController<Controller_Touchscreen>(HidController::Touchscreen, shared_memory);
MakeController<Controller_Mouse>(HidController::Mouse); MakeController<Controller_Mouse>(HidController::Mouse, shared_memory);
MakeController<Controller_Keyboard>(HidController::Keyboard); MakeController<Controller_Keyboard>(HidController::Keyboard, shared_memory);
MakeController<Controller_XPad>(HidController::XPad); MakeController<Controller_XPad>(HidController::XPad, shared_memory);
MakeController<Controller_Stubbed>(HidController::HomeButton); MakeController<Controller_Stubbed>(HidController::HomeButton, shared_memory);
MakeController<Controller_Stubbed>(HidController::SleepButton); MakeController<Controller_Stubbed>(HidController::SleepButton, shared_memory);
MakeController<Controller_Stubbed>(HidController::CaptureButton); MakeController<Controller_Stubbed>(HidController::CaptureButton, shared_memory);
MakeController<Controller_Stubbed>(HidController::InputDetector); MakeController<Controller_Stubbed>(HidController::InputDetector, shared_memory);
MakeController<Controller_Stubbed>(HidController::UniquePad); MakeController<Controller_Stubbed>(HidController::UniquePad, shared_memory);
MakeControllerWithServiceContext<Controller_NPad>(HidController::NPad); MakeControllerWithServiceContext<Controller_NPad>(HidController::NPad, shared_memory);
MakeController<Controller_Gesture>(HidController::Gesture); MakeController<Controller_Gesture>(HidController::Gesture, shared_memory);
MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor); MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor, shared_memory);
// Homebrew doesn't try to activate some controllers, so we activate them by default // Homebrew doesn't try to activate some controllers, so we activate them by default
GetController<Controller_NPad>(HidController::NPad).ActivateController(); 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)]) { if (controller == controllers[static_cast<size_t>(HidController::Mouse)]) {
continue; continue;
} }
controller->OnUpdate(core_timing, system.Kernel().GetHidSharedMem().GetPointer(), controller->OnUpdate(core_timing);
SHARED_MEMORY_SIZE);
} }
// If ns_late is higher than the update rate ignore the delay // 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) { std::chrono::nanoseconds ns_late) {
auto& core_timing = system.CoreTiming(); auto& core_timing = system.CoreTiming();
controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate( controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate(core_timing);
core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE); controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate(core_timing);
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 is higher than the update rate ignore the delay
if (ns_late > mouse_keyboard_update_ns) { 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) { void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
auto& core_timing = system.CoreTiming(); auto& core_timing = system.CoreTiming();
controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate( controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate(core_timing);
core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE);
// If ns_late is higher than the update rate ignore the delay // If ns_late is higher than the update rate ignore the delay
if (ns_late > motion_update_ns) { if (ns_late > motion_update_ns) {

View file

@ -58,13 +58,14 @@ public:
private: private:
template <typename T> template <typename T>
void MakeController(HidController controller) { void MakeController(HidController controller, u8* shared_memory) {
controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(system.HIDCore()); controllers[static_cast<std::size_t>(controller)] =
std::make_unique<T>(system.HIDCore(), shared_memory);
} }
template <typename T> template <typename T>
void MakeControllerWithServiceContext(HidController controller) { void MakeControllerWithServiceContext(HidController controller, u8* shared_memory) {
controllers[static_cast<std::size_t>(controller)] = 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); void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);