diff options
Diffstat (limited to 'src/core/hle/service/hid/controllers')
18 files changed, 1289 insertions, 0 deletions
diff --git a/src/core/hle/service/hid/controllers/controller_base.cpp b/src/core/hle/service/hid/controllers/controller_base.cpp new file mode 100644 index 000000000..f2aef5642 --- /dev/null +++ b/src/core/hle/service/hid/controllers/controller_base.cpp @@ -0,0 +1,27 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/hid/controllers/controller_base.h" + +namespace Service::HID { +void ControllerBase::ActivateController() { + if (is_activated) { + OnRelease(); + } + is_activated = true; + OnInit(); +} + +void ControllerBase::DeactivateController() { + if (is_activated) { + OnRelease(); + } + is_activated = false; +} + +bool ControllerBase::IsControllerActivated() const { + return is_activated; +} +// ControllerBase::~ControllerBase() = default; +}; // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h new file mode 100644 index 000000000..3b1c8aad6 --- /dev/null +++ b/src/core/hle/service/hid/controllers/controller_base.h @@ -0,0 +1,43 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once +#include "common/common_types.h" +#include "common/swap.h" + +namespace Service::HID { +class ControllerBase { +public: + ControllerBase() = default; + + // Called when the controller is initialized + virtual void OnInit() = 0; + + // When the controller is released + virtual void OnRelease() = 0; + + // When the controller is requesting an update for the shared memory + virtual void OnUpdate(u8* data, size_t size) = 0; + + // Called when input devices should be loaded + virtual void OnLoadInputDevices() = 0; + + void ActivateController(); + + void DeactivateController(); + + bool IsControllerActivated() const; + +protected: + bool is_activated{false}; + + struct CommonHeader { + s64_le timestamp; + s64_le total_entry_count; + s64_le last_entry_index; + s64_le entry_count; + }; + static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); +}; +}; // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp new file mode 100644 index 000000000..04799b233 --- /dev/null +++ b/src/core/hle/service/hid/controllers/debug_pad.cpp @@ -0,0 +1,35 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/common_types.h" +#include "common/swap.h" +#include "core/core_timing.h" +#include "core/hle/service/hid/controllers/debug_pad.h" + +namespace Service::HID { +void Controller_DebugPad::OnInit() {} +void Controller_DebugPad::OnRelease() {} +void Controller_DebugPad::OnUpdate(u8* data, size_t size) { + shared_memory.header.timestamp = CoreTiming::GetTicks(); + shared_memory.header.total_entry_count = 17; + + if (!IsControllerActivated()) { + shared_memory.header.entry_count = 0; + shared_memory.header.last_entry_index = 0; + return; + } + shared_memory.header.entry_count = 16; + + auto& last_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; + shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; + auto& cur_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; + + cur_entry.sampling_number = last_entry.sampling_number + 1; + cur_entry.sampling_number2 = cur_entry.sampling_number; + // TODO(ogniK): Update debug pad states + + std::memcpy(data, &shared_memory, sizeof(SharedMemory)); +} +void Controller_DebugPad::OnLoadInputDevices() {} +}; // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h new file mode 100644 index 000000000..fc6f99a0b --- /dev/null +++ b/src/core/hle/service/hid/controllers/debug_pad.h @@ -0,0 +1,54 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once +#include <array> +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "common/swap.h" +#include "core/hle/service/hid/controllers/controller_base.h" + +namespace Service::HID { +class Controller_DebugPad final : public ControllerBase { +public: + Controller_DebugPad() = default; + + // Called when the controller is initialized + void OnInit() override; + + // When the controller is released + void OnRelease() override; + + // When the controller is requesting an update for the shared memory + void OnUpdate(u8* data, size_t size) override; + + // Called when input devices should be loaded + void OnLoadInputDevices() override; + +private: + struct AnalogStick { + s32_le x; + s32_le y; + }; + static_assert(sizeof(AnalogStick) == 0x8); + + struct PadStates { + s64_le sampling_number; + s64_le sampling_number2; + u32_le attribute; + u32_le button_state; + AnalogStick r_stick; + AnalogStick l_stick; + }; + static_assert(sizeof(PadStates) == 0x28, "PadStates is an invalid state"); + + struct SharedMemory { + CommonHeader header; + std::array<PadStates, 17> pad_states; + INSERT_PADDING_BYTES(0x138); + }; + static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size"); + SharedMemory shared_memory{}; +}; +}; // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp new file mode 100644 index 000000000..851ea66f3 --- /dev/null +++ b/src/core/hle/service/hid/controllers/gesture.cpp @@ -0,0 +1,36 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/common_types.h" +#include "common/swap.h" +#include "core/core_timing.h" +#include "core/hle/service/hid/controllers/gesture.h" + +namespace Service::HID { +constexpr size_t SHARED_MEMORY_OFFSET = 0x3BA00; +void Controller_Gesture::OnInit() {} +void Controller_Gesture::OnRelease() {} +void Controller_Gesture::OnUpdate(u8* data, size_t size) { + shared_memory.header.timestamp = CoreTiming::GetTicks(); + shared_memory.header.total_entry_count = 17; + + if (!IsControllerActivated()) { + shared_memory.header.entry_count = 0; + shared_memory.header.last_entry_index = 0; + return; + } + shared_memory.header.entry_count = 16; + + auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; + auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + + cur_entry.sampling_number = last_entry.sampling_number + 1; + cur_entry.sampling_number2 = cur_entry.sampling_number; + // TODO(ogniK): Update gesture states + + std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); +} +void Controller_Gesture::OnLoadInputDevices() {} +}; // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h new file mode 100644 index 000000000..f46819829 --- /dev/null +++ b/src/core/hle/service/hid/controllers/gesture.h @@ -0,0 +1,61 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once +#include <array> +#include "common/common_types.h" +#include "common/swap.h" +#include "core/hle/service/hid/controllers/controller_base.h" + +namespace Service::HID { +class Controller_Gesture final : public ControllerBase { +public: + Controller_Gesture() = default; + + // Called when the controller is initialized + void OnInit() override; + + // When the controller is released + void OnRelease() override; + + // When the controller is requesting an update for the shared memory + void OnUpdate(u8* data, size_t size) override; + + // Called when input devices should be loaded + void OnLoadInputDevices() override; + +private: + struct Locations { + s32_le x; + s32_le y; + }; + + struct GestureState { + s64_le sampling_number; + s64_le sampling_number2; + + s64_le detection_count; + s32_le type; + s32_le dir; + s32_le x; + s32_le y; + s32_le delta_x; + s32_le delta_y; + f32 vel_x; + f32 vel_y; + s32_le attributes; + f32 scale; + f32 rotation; + s32_le location_count; + std::array<Locations, 4> locations{}; + }; + static_assert(sizeof(GestureState) == 0x68, "GestureState is an invalid size"); + + struct SharedMemory { + CommonHeader header; + std::array<GestureState, 17> gesture_states; + }; + SharedMemory shared_memory{}; +}; +}; // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp new file mode 100644 index 000000000..27c39ad08 --- /dev/null +++ b/src/core/hle/service/hid/controllers/keyboard.cpp @@ -0,0 +1,36 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/common_types.h" +#include "common/swap.h" +#include "core/core_timing.h" +#include "core/hle/service/hid/controllers/keyboard.h" + +namespace Service::HID { +constexpr size_t SHARED_MEMORY_OFFSET = 0x3800; +void Controller_Keyboard::OnInit() {} +void Controller_Keyboard::OnRelease() {} +void Controller_Keyboard::OnUpdate(u8* data, size_t size) { + shared_memory.header.timestamp = CoreTiming::GetTicks(); + shared_memory.header.total_entry_count = 17; + + if (!IsControllerActivated()) { + shared_memory.header.entry_count = 0; + shared_memory.header.last_entry_index = 0; + return; + } + shared_memory.header.entry_count = 16; + + auto& last_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; + shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; + auto& cur_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; + + cur_entry.sampling_number = last_entry.sampling_number + 1; + cur_entry.sampling_number2 = cur_entry.sampling_number; + // TODO(ogniK): Update keyboard states + + std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); +} +void Controller_Keyboard::OnLoadInputDevices() {} +}; // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h new file mode 100644 index 000000000..0463e1619 --- /dev/null +++ b/src/core/hle/service/hid/controllers/keyboard.h @@ -0,0 +1,48 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once +#include <array> +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "common/swap.h" +#include "core/hle/service/hid/controllers/controller_base.h" + +namespace Service::HID { +class Controller_Keyboard final : public ControllerBase { +public: + Controller_Keyboard() = default; + + // Called when the controller is initialized + void OnInit() override; + + // When the controller is released + void OnRelease() override; + + // When the controller is requesting an update for the shared memory + void OnUpdate(u8* data, size_t size) override; + + // Called when input devices should be loaded + void OnLoadInputDevices() override; + +private: + struct KeyboardState { + s64_le sampling_number; + s64_le sampling_number2; + + s32_le modifier; + s32_le attribute; + std::array<u8, 32> key{}; + }; + static_assert(sizeof(KeyboardState) == 0x38, "KeyboardState is an invalid size"); + + struct SharedMemory { + CommonHeader header; + std::array<KeyboardState, 17> pad_states; + INSERT_PADDING_BYTES(0x28); + }; + static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size"); + SharedMemory shared_memory{}; +}; +}; // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp new file mode 100644 index 000000000..df30239e2 --- /dev/null +++ b/src/core/hle/service/hid/controllers/mouse.cpp @@ -0,0 +1,36 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/common_types.h" +#include "common/swap.h" +#include "core/core_timing.h" +#include "core/hle/service/hid/controllers/mouse.h" + +namespace Service::HID { +constexpr size_t SHARED_MEMORY_OFFSET = 0x3400; +void Controller_Mouse::OnInit() {} +void Controller_Mouse::OnRelease() {} +void Controller_Mouse::OnUpdate(u8* data, size_t size) { + shared_memory.header.timestamp = CoreTiming::GetTicks(); + shared_memory.header.total_entry_count = 17; + + if (!IsControllerActivated()) { + shared_memory.header.entry_count = 0; + shared_memory.header.last_entry_index = 0; + return; + } + shared_memory.header.entry_count = 16; + + auto& last_entry = shared_memory.mouse_states[shared_memory.header.last_entry_index]; + shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; + auto& cur_entry = shared_memory.mouse_states[shared_memory.header.last_entry_index]; + + cur_entry.sampling_number = last_entry.sampling_number + 1; + cur_entry.sampling_number2 = cur_entry.sampling_number; + // TODO(ogniK): Update mouse states + + std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); +} +void Controller_Mouse::OnLoadInputDevices() {} +}; // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h new file mode 100644 index 000000000..0d7fd372d --- /dev/null +++ b/src/core/hle/service/hid/controllers/mouse.h @@ -0,0 +1,48 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once +#include <array> +#include "common/common_types.h" +#include "common/swap.h" +#include "core/hle/service/hid/controllers/controller_base.h" + +namespace Service::HID { +class Controller_Mouse final : public ControllerBase { +public: + Controller_Mouse() = default; + + // Called when the controller is initialized + void OnInit() override; + + // When the controller is released + void OnRelease() override; + + // When the controller is requesting an update for the shared memory + void OnUpdate(u8* data, size_t size) override; + + // Called when input devices should be loaded + void OnLoadInputDevices() override; + +private: + struct MouseState { + s64_le sampling_number; + s64_le sampling_number2; + s32_le x; + s32_le y; + s32_le delta_x; + s32_le delta_y; + s32_le mouse_wheel; + s32_le button; + s32_le attribute; + }; + static_assert(sizeof(MouseState) == 0x30, "MouseState is an invalid size"); + + struct SharedMemory { + CommonHeader header; + std::array<MouseState, 17> mouse_states; + }; + SharedMemory shared_memory{}; +}; +}; // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp new file mode 100644 index 000000000..a53687b91 --- /dev/null +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -0,0 +1,336 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once +#include <array> +#include "common/assert.h" +#include "common/bit_field.h" +#include "common/common_types.h" +#include "common/swap.h" +#include "core/core.h" +#include "core/core_timing.h" +#include "core/frontend/input.h" +#include "core/hle/kernel/event.h" +#include "core/hle/service/hid/controllers/npad.h" +#include "core/settings.h" + +namespace Service::HID { +constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28; +constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A; +constexpr u32 JOYCON_BODY_NEON_BLUE = 0x0AB9E6; +constexpr u32 JOYCON_BUTTONS_NEON_BLUE = 0x001E1E; +constexpr s32 HID_JOYSTICK_MAX = 0x7fff; +constexpr s32 HID_JOYSTICK_MIN = -0x7fff; +constexpr size_t NPAD_OFFSET = 0x9A00; +constexpr size_t MAX_CONTROLLER_COUNT = 9; + +enum class JoystickId : size_t { Joystick_Left, Joystick_Right }; +constexpr std::array<u32, MAX_CONTROLLER_COUNT> NPAD_ID_LIST{0, 1, 2, 3, 4, 5, 6, 7, 32}; +size_t CONTROLLER_COUNT{}; +std::array<Controller_NPad::NPadControllerType, MAX_CONTROLLER_COUNT> CONNECTED_CONTROLLERS{}; + +void Controller_NPad::InitNewlyAddedControler(size_t controller_idx) { + const auto controller_type = CONNECTED_CONTROLLERS[controller_idx]; + auto& controller = shared_memory_entries[controller_idx]; + if (controller_type == NPadControllerType::None) { + return; + } + controller.joy_styles.raw = 0; // Zero out + controller.device_type.raw = 0; + switch (controller_type) { + case NPadControllerType::Handheld: + controller.joy_styles.handheld.Assign(1); + controller.device_type.handheld.Assign(1); + controller.pad_assignment = NPadAssignments::Dual; + break; + case NPadControllerType::JoyLeft: + controller.joy_styles.joycon_left.Assign(1); + controller.device_type.joycon_left.Assign(1); + controller.pad_assignment = NPadAssignments::Dual; + break; + case NPadControllerType::JoyRight: + controller.joy_styles.joycon_right.Assign(1); + controller.device_type.joycon_right.Assign(1); + controller.pad_assignment = NPadAssignments::Dual; + break; + case NPadControllerType::Tabletop: + UNIMPLEMENTED_MSG("Tabletop is not implemented"); + break; + case NPadControllerType::Pokeball: + controller.joy_styles.pokeball.Assign(1); + controller.device_type.pokeball.Assign(1); + controller.pad_assignment = NPadAssignments::Single; + break; + case NPadControllerType::ProController: + controller.joy_styles.pro_controller.Assign(1); + controller.device_type.pro_controller.Assign(1); + controller.pad_assignment = NPadAssignments::Single; + break; + } + + controller.single_color_error = ColorReadError::ReadOk; + controller.single_color.body_color = 0; + controller.single_color.button_color = 0; + + controller.dual_color_error = ColorReadError::ReadOk; + controller.left_color.body_color = JOYCON_BODY_NEON_BLUE; + controller.left_color.button_color = JOYCON_BUTTONS_NEON_BLUE; + controller.right_color.body_color = JOYCON_BODY_NEON_RED; + controller.right_color.button_color = JOYCON_BUTTONS_NEON_RED; + + controller.properties.is_verticle.Assign(1); // TODO(ogniK): Swap joycons orientations +} + +void Controller_NPad::OnInit() { + auto& kernel = Core::System::GetInstance().Kernel(); + styleset_changed_event = + Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "npad:NpadStyleSetChanged"); + + if (!IsControllerActivated()) + return; + size_t controller{}; + supported_npad_id_types.resize(NPAD_ID_LIST.size()); + if (style.raw == 0) { + // We want to support all controllers + style.handheld.Assign(1); + style.joycon_left.Assign(1); + style.joycon_right.Assign(1); + style.joycon_dual.Assign(1); + style.pro_controller.Assign(1); + style.pokeball.Assign(1); + } + std::memcpy(supported_npad_id_types.data(), NPAD_ID_LIST.data(), + NPAD_ID_LIST.size() * sizeof(u32)); + if (CONTROLLER_COUNT == 0) { + AddNewController(NPadControllerType::Handheld); + } +} + +void Controller_NPad::OnLoadInputDevices() { + std::transform(Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, + Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_END, + buttons.begin(), Input::CreateDevice<Input::ButtonDevice>); + std::transform(Settings::values.analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, + Settings::values.analogs.begin() + Settings::NativeAnalog::STICK_HID_END, + sticks.begin(), Input::CreateDevice<Input::AnalogDevice>); +} + +void Controller_NPad::OnRelease() {} + +void Controller_NPad::OnUpdate(u8* data, size_t data_len) { + if (!IsControllerActivated()) + return; + for (size_t i = 0; i < shared_memory_entries.size(); i++) { + auto& npad = shared_memory_entries[i]; + const std::array<NPadGeneric*, 7> controller_npads{&npad.main_controller_states, + &npad.handheld_states, + &npad.dual_states, + &npad.left_joy_states, + &npad.right_joy_states, + &npad.pokeball_states, + &npad.libnx}; + + for (auto main_controller : controller_npads) { + main_controller->common.entry_count = 16; + main_controller->common.total_entry_count = 17; + + auto& last_entry = main_controller->npad[main_controller->common.last_entry_index]; + + main_controller->common.timestamp = CoreTiming::GetTicks(); + main_controller->common.last_entry_index = + (main_controller->common.last_entry_index + 1) % 17; + + auto& cur_entry = main_controller->npad[main_controller->common.last_entry_index]; + + cur_entry.timestamp = last_entry.timestamp + 1; + cur_entry.timestamp2 = cur_entry.timestamp; + } + + if (CONNECTED_CONTROLLERS[i] == NPadControllerType::None) { + continue; + } + + const auto& controller_type = CONNECTED_CONTROLLERS[i]; + + // Pad states + auto pad_state = ControllerPadState{}; + using namespace Settings::NativeButton; + pad_state.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.l_stick.Assign(buttons[LStick - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.r_stick.Assign(buttons[RStick - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus()); + + pad_state.dleft.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.dup.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.dright.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.ddown.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus()); + + pad_state.lstickleft.Assign(buttons[LStick_Left - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.lstickup.Assign(buttons[LStick_Up - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.lstickright.Assign(buttons[LStick_Right - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.lstickdown.Assign(buttons[LStick_Down - BUTTON_HID_BEGIN]->GetStatus()); + + pad_state.rstickleft.Assign(buttons[RStick_Left - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.rstickup.Assign(buttons[RStick_Up - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.rstickright.Assign(buttons[RStick_Right - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.rstickdown.Assign(buttons[RStick_Down - BUTTON_HID_BEGIN]->GetStatus()); + + pad_state.sl.Assign(buttons[SL - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.sr.Assign(buttons[SR - BUTTON_HID_BEGIN]->GetStatus()); + + AnalogPosition lstick_entry{}; + AnalogPosition rstick_entry{}; + + const auto [stick_l_x_f, stick_l_y_f] = + sticks[static_cast<size_t>(JoystickId::Joystick_Left)]->GetStatus(); + const auto [stick_r_x_f, stick_r_y_f] = + sticks[static_cast<size_t>(JoystickId::Joystick_Right)]->GetStatus(); + lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX); + lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX); + rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX); + rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX); + + auto& main_controller = + npad.main_controller_states.npad[npad.main_controller_states.common.last_entry_index]; + auto& handheld_entry = + npad.handheld_states.npad[npad.handheld_states.common.last_entry_index]; + auto& dual_entry = npad.dual_states.npad[npad.dual_states.common.last_entry_index]; + auto& left_entry = npad.left_joy_states.npad[npad.left_joy_states.common.last_entry_index]; + auto& right_entry = + npad.right_joy_states.npad[npad.right_joy_states.common.last_entry_index]; + auto& pokeball_entry = + npad.pokeball_states.npad[npad.pokeball_states.common.last_entry_index]; + auto& libnx_entry = npad.libnx.npad[npad.libnx.common.last_entry_index]; + + if (hold_type == NpadHoldType::Horizontal) { + // TODO(ogniK): Remap buttons for different orientations + } + + switch (controller_type) { + case NPadControllerType::Handheld: + handheld_entry.connection_status.IsConnected.Assign(1); + handheld_entry.connection_status.IsWired.Assign(1); + handheld_entry.pad_states.raw = pad_state.raw; + handheld_entry.lstick = lstick_entry; + handheld_entry.rstick = rstick_entry; + break; + case NPadControllerType::JoyLeft: + left_entry.connection_status.IsConnected.Assign(1); + left_entry.pad_states.raw = pad_state.raw; + left_entry.lstick = lstick_entry; + left_entry.rstick = rstick_entry; + break; + case NPadControllerType::JoyRight: + right_entry.connection_status.IsConnected.Assign(1); + right_entry.pad_states.raw = pad_state.raw; + right_entry.lstick = lstick_entry; + right_entry.rstick = rstick_entry; + break; + case NPadControllerType::Tabletop: + // TODO(ogniK): Figure out how to add proper tabletop support + dual_entry.pad_states.raw = pad_state.raw; + dual_entry.lstick = lstick_entry; + dual_entry.rstick = rstick_entry; + dual_entry.connection_status.IsConnected.Assign(1); + break; + case NPadControllerType::Pokeball: + pokeball_entry.connection_status.IsConnected.Assign(1); + pokeball_entry.connection_status.IsWired.Assign(1); + + pokeball_entry.pad_states.raw = pad_state.raw; + pokeball_entry.lstick = lstick_entry; + pokeball_entry.rstick = rstick_entry; + break; + case NPadControllerType::ProController: + main_controller.pad_states.raw = pad_state.raw; + main_controller.lstick = lstick_entry; + main_controller.rstick = rstick_entry; + main_controller.connection_status.IsConnected.Assign(1); + main_controller.connection_status.IsWired.Assign(1); + break; + } + + // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate + // any controllers. + libnx_entry.connection_status.IsConnected.Assign(1); + libnx_entry.connection_status.IsWired.Assign(1); + libnx_entry.pad_states.raw = pad_state.raw; + libnx_entry.lstick = lstick_entry; + libnx_entry.rstick = rstick_entry; + } + std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(), + shared_memory_entries.size() * sizeof(NPadEntry)); +} + +void Controller_NPad::SetSupportedStyleSet(NPadType style_set) { + style.raw = style_set.raw; +} + +Controller_NPad::NPadType Controller_NPad::GetSupportedStyleSet() const { + return style; +} + +void Controller_NPad::SetSupportedNPadIdTypes(u8* data, size_t length) { + ASSERT(length > 0 && (length % sizeof(u32)) == 0); + supported_npad_id_types.resize(length / 4); + std::memcpy(supported_npad_id_types.data(), data, length); +} + +void Controller_NPad::GetSupportedNpadIdTypes(u32* data, size_t max_length) { + ASSERT(max_length < supported_npad_id_types.size()); + std::memcpy(data, supported_npad_id_types.data(), supported_npad_id_types.size()); +} + +size_t Controller_NPad::GetSupportedNPadIdTypesSize() const { + return supported_npad_id_types.size(); +} + +void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) { + hold_type = joy_hold_type; +} +Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const { + return hold_type; +} + +void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) { + ASSERT(npad_id < shared_memory_entries.size()); + shared_memory_entries[npad_id].pad_assignment = assignment_mode; +} + +void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids, + const std::vector<Vibration>& vibrations) { + for (size_t i = 0; i < controller_ids.size(); i++) { + if (i >= CONTROLLER_COUNT) { + continue; + } + // TODO(ogniK): Vibrate the physical controller + } + LOG_WARNING(Service_HID, "(STUBBED) called"); + last_processed_vibration = vibrations.back(); +} + +Kernel::SharedPtr<Kernel::Event> Controller_NPad::GetStyleSetChangedEvent() const { + return styleset_changed_event; +} + +Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { + return last_processed_vibration; +} +void Controller_NPad::AddNewController(NPadControllerType controller) { + if (CONTROLLER_COUNT >= MAX_CONTROLLER_COUNT) { + LOG_ERROR(Service_HID, "Cannot connect any more controllers!"); + return; + } + CONNECTED_CONTROLLERS[CONTROLLER_COUNT] = controller; + InitNewlyAddedControler(CONTROLLER_COUNT++); +} +}; // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h new file mode 100644 index 000000000..e57b67da4 --- /dev/null +++ b/src/core/hle/service/hid/controllers/npad.h @@ -0,0 +1,249 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once +#include <array> +#include "common/common_types.h" +#include "core/frontend/input.h" +#include "core/hle/service/hid/controllers/controller_base.h" +#include "core/settings.h" + +namespace Service::HID { + +class Controller_NPad final : public ControllerBase { +public: + Controller_NPad() = default; + + // Called when the controller is initialized + void OnInit() override; + + // When the controller is released + void OnRelease() override; + + // When the controller is requesting an update for the shared memory + void OnUpdate(u8* data, size_t size) override; + + // Called when input devices should be loaded + void OnLoadInputDevices() override; + + struct NPadType { + union { + u32_le raw{}; + + BitField<0, 1, u32_le> pro_controller; + BitField<1, 1, u32_le> handheld; + BitField<2, 1, u32_le> joycon_dual; + BitField<3, 1, u32_le> joycon_left; + BitField<4, 1, u32_le> joycon_right; + + BitField<6, 1, u32_le> pokeball; // TODO(ogniK): Confirm when possible + }; + }; + static_assert(sizeof(NPadType) == 4, "NPadType is an invalid size"); + + struct Vibration { + f32 amp_low; + f32 freq_low; + f32 amp_high; + f32 freq_high; + }; + static_assert(sizeof(Vibration) == 0x10, "Vibration is an invalid size"); + + enum class NpadHoldType : u64 { + Vertical = 0, + Horizontal = 1, + }; + + enum class NPadAssignments : u32_le { + Dual = 0, + Single = 1, + }; + + enum class NPadControllerType { + None, + ProController, + Handheld, + JoyLeft, + JoyRight, + Tabletop, + Pokeball + }; + + void SetSupportedStyleSet(NPadType style_set); + NPadType GetSupportedStyleSet() const; + + void SetSupportedNPadIdTypes(u8* data, size_t length); + void GetSupportedNpadIdTypes(u32* data, size_t max_length); + size_t GetSupportedNPadIdTypesSize() const; + + void SetHoldType(NpadHoldType joy_hold_type); + NpadHoldType GetHoldType() const; + + void SetNpadMode(u32 npad_id, NPadAssignments assignment_mode); + + void VibrateController(const std::vector<u32>& controller_ids, + const std::vector<Vibration>& vibrations); + + Kernel::SharedPtr<Kernel::Event> GetStyleSetChangedEvent() const; + Vibration GetLastVibration() const; + + void AddNewController(NPadControllerType controller); + +private: + struct CommonHeader { + s64_le timestamp; + s64_le total_entry_count; + s64_le last_entry_index; + s64_le entry_count; + }; + static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); + + struct ControllerColor { + u32_le body_color; + u32_le button_color; + }; + static_assert(sizeof(ControllerColor) == 8, "ControllerColor is an invalid size"); + + struct ControllerPadState { + union { + u64_le raw{}; + // Button states + BitField<0, 1, u64_le> a; + BitField<1, 1, u64_le> b; + BitField<2, 1, u64_le> x; + BitField<3, 1, u64_le> y; + BitField<4, 1, u64_le> l_stick; + BitField<5, 1, u64_le> r_stick; + BitField<6, 1, u64_le> l; + BitField<7, 1, u64_le> r; + BitField<8, 1, u64_le> zl; + BitField<9, 1, u64_le> zr; + BitField<10, 1, u64_le> plus; + BitField<11, 1, u64_le> minus; + + // D-Pad + BitField<12, 1, u64_le> dleft; + BitField<13, 1, u64_le> dup; + BitField<14, 1, u64_le> dright; + BitField<15, 1, u64_le> ddown; + + // Left JoyStick + BitField<16, 1, u64_le> lstickleft; + BitField<17, 1, u64_le> lstickup; + BitField<18, 1, u64_le> lstickright; + BitField<19, 1, u64_le> lstickdown; + + // Right JoyStick + BitField<20, 1, u64_le> rstickleft; + BitField<21, 1, u64_le> rstickup; + BitField<22, 1, u64_le> rstickright; + BitField<23, 1, u64_le> rstickdown; + + // Not always active? + BitField<24, 1, u64_le> sl; + BitField<25, 1, u64_le> sr; + }; + }; + static_assert(sizeof(ControllerPadState) == 8, "ControllerPadState is an invalid size"); + + struct AnalogPosition { + s32_le x; + s32_le y; + }; + static_assert(sizeof(AnalogPosition) == 8, "AnalogPosition is an invalid size"); + + struct ConnectionState { + union { + u32_le raw{}; + BitField<0, 1, u32_le> IsConnected; + BitField<1, 1, u32_le> IsWired; + }; + }; + static_assert(sizeof(ConnectionState) == 4, "ConnectionState is an invalid size"); + + struct GenericStates { + s64_le timestamp; + s64_le timestamp2; + ControllerPadState pad_states; + AnalogPosition lstick; + AnalogPosition rstick; + ConnectionState connection_status; + }; + static_assert(sizeof(GenericStates) == 0x30, "NPadGenericStates is an invalid size"); + + struct NPadGeneric { + CommonHeader common; + std::array<GenericStates, 17> npad; + }; + static_assert(sizeof(NPadGeneric) == 0x350, "NPadGeneric is an invalid size"); + + enum class ColorReadError : u32_le { + ReadOk = 0, + ColorDoesntExist = 1, + NoController = 2, + }; + + struct NPadProperties { + union { + s64_le raw{}; + BitField<11, 1, s64_le> is_verticle; + BitField<12, 1, s64_le> is_horizontal; + }; + }; + + struct NPadDevice { + union { + u32_le raw{}; + BitField<0, 1, s32_le> pro_controller; + BitField<1, 1, s32_le> handheld; + BitField<2, 1, s32_le> handheld_left; + BitField<3, 1, s32_le> handheld_right; + BitField<4, 1, s32_le> joycon_left; + BitField<5, 1, s32_le> joycon_right; + BitField<6, 1, s32_le> pokeball; + }; + }; + + struct NPadEntry { + NPadType joy_styles; + NPadAssignments pad_assignment; + + ColorReadError single_color_error; + ControllerColor single_color; + + ColorReadError dual_color_error; + ControllerColor left_color; + ControllerColor right_color; + + NPadGeneric main_controller_states; + NPadGeneric handheld_states; + NPadGeneric dual_states; + NPadGeneric left_joy_states; + NPadGeneric right_joy_states; + NPadGeneric pokeball_states; + NPadGeneric libnx; // TODO(ogniK): Find out what this actually is, libnx seems to only be + // relying on this for the time being + INSERT_PADDING_BYTES( + 0x708 * + 6); // TODO(ogniK)L SixAxis states, require more information before implementation + NPadDevice device_type; + NPadProperties properties; + INSERT_PADDING_WORDS(4); + INSERT_PADDING_BYTES(0x60); + INSERT_PADDING_BYTES(0xdf8); + }; + static_assert(sizeof(NPadEntry) == 0x5000, "NPadEntry is an invalid size"); + NPadType style{}; + std::array<NPadEntry, 10> shared_memory_entries{}; + std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID> + buttons; + std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID> sticks; + std::vector<u32> supported_npad_id_types{}; + NpadHoldType hold_type{NpadHoldType::Vertical}; + Kernel::SharedPtr<Kernel::Event> styleset_changed_event; + size_t dump_idx{}; + Vibration last_processed_vibration{}; + void InitNewlyAddedControler(size_t controller_idx); +}; +}; // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/stubbed.cpp b/src/core/hle/service/hid/controllers/stubbed.cpp new file mode 100644 index 000000000..0a602fce2 --- /dev/null +++ b/src/core/hle/service/hid/controllers/stubbed.cpp @@ -0,0 +1,32 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/common_types.h" +#include "common/swap.h" +#include "core/core_timing.h" +#include "core/hle/service/hid/controllers/stubbed.h" + +namespace Service::HID { +void Controller_Stubbed::OnInit() {} +void Controller_Stubbed::OnRelease() {} +void Controller_Stubbed::OnUpdate(u8* data, size_t size) { + if (!smart_update) { + return; + } + + CommonHeader header{}; + header.timestamp = CoreTiming::GetTicks(); + header.total_entry_count = 17; + header.entry_count = 0; + header.last_entry_index = 0; + + std::memcpy(data + common_offset, &header, sizeof(CommonHeader)); +} +void Controller_Stubbed::OnLoadInputDevices() {} + +void Controller_Stubbed::SetCommonHeaderOffset(size_t off) { + common_offset = off; + smart_update = true; +} +}; // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/stubbed.h b/src/core/hle/service/hid/controllers/stubbed.h new file mode 100644 index 000000000..ec7adacb3 --- /dev/null +++ b/src/core/hle/service/hid/controllers/stubbed.h @@ -0,0 +1,32 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once +#include "common/common_types.h" +#include "core/hle/service/hid/controllers/controller_base.h" + +namespace Service::HID { +class Controller_Stubbed final : public ControllerBase { +public: + Controller_Stubbed() = default; + + // Called when the controller is initialized + void OnInit() override; + + // When the controller is released + void OnRelease() override; + + // When the controller is requesting an update for the shared memory + void OnUpdate(u8* data, size_t size) override; + + // Called when input devices should be loaded + void OnLoadInputDevices() override; + + void SetCommonHeaderOffset(size_t off); + +private: + bool smart_update{}; + size_t common_offset{}; +}; +}; // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp new file mode 100644 index 000000000..b675dec8e --- /dev/null +++ b/src/core/hle/service/hid/controllers/touchscreen.cpp @@ -0,0 +1,58 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/common_types.h" +#include "common/swap.h" +#include "core/core_timing.h" +#include "core/frontend/emu_window.h" +#include "core/frontend/input.h" +#include "core/hle/service/hid/controllers/touchscreen.h" +#include "core/settings.h" + +namespace Service::HID { +constexpr size_t SHARED_MEMORY_OFFSET = 0x400; +void Controller_Touchscreen::OnInit() {} +void Controller_Touchscreen::OnRelease() {} +void Controller_Touchscreen::OnUpdate(u8* data, size_t size) { + shared_memory.header.timestamp = CoreTiming::GetTicks(); + shared_memory.header.total_entry_count = 17; + + if (!IsControllerActivated()) { + shared_memory.header.entry_count = 0; + shared_memory.header.last_entry_index = 0; + return; + } + shared_memory.header.entry_count = 16; + + auto& last_entry = shared_memory.shared_memory_entries[shared_memory.header.last_entry_index]; + shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; + auto& cur_entry = shared_memory.shared_memory_entries[shared_memory.header.last_entry_index]; + + cur_entry.sampling_number = last_entry.sampling_number + 1; + cur_entry.sampling_number2 = cur_entry.sampling_number; + + auto [x, y, pressed] = touch_device->GetStatus(); + auto& touch_entry = cur_entry.states[0]; + if (pressed) { + touch_entry.x = static_cast<u16>(x * Layout::ScreenUndocked::Width); + touch_entry.y = static_cast<u16>(y * Layout::ScreenUndocked::Height); + touch_entry.diameter_x = 15; + touch_entry.diameter_y = 15; + touch_entry.rotation_angle = 0; + const u64 tick = CoreTiming::GetTicks(); + touch_entry.delta_time = tick - last_touch; + last_touch = tick; + touch_entry.finger = 0; + cur_entry.entry_count = 1; + } else { + cur_entry.entry_count = 0; + } + + std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(TouchScreenSharedMemory)); +} + +void Controller_Touchscreen::OnLoadInputDevices() { + touch_device = Input::CreateDevice<Input::TouchDevice>(Settings::values.touch_device); +} +}; // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h new file mode 100644 index 000000000..a516128ac --- /dev/null +++ b/src/core/hle/service/hid/controllers/touchscreen.h @@ -0,0 +1,61 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "common/swap.h" +#include "core/frontend/input.h" +#include "core/hle/service/hid/controllers/controller_base.h" + +namespace Service::HID { +class Controller_Touchscreen final : public ControllerBase { +public: + Controller_Touchscreen() = default; + + // Called when the controller is initialized + void OnInit() override; + + // When the controller is released + void OnRelease() override; + + // When the controller is requesting an update for the shared memory + void OnUpdate(u8* data, size_t size) override; + + // Called when input devices should be loaded + void OnLoadInputDevices() override; + +private: + struct TouchState { + u64_le delta_time; + u32_le attribute; + u32_le finger; + u32_le x; + u32_le y; + u32_le diameter_x; + u32_le diameter_y; + u32_le rotation_angle; + }; + static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size"); + + struct TouchScreenEntry { + s64_le sampling_number; + s64_le sampling_number2; + s32_le entry_count; + std::array<TouchState, 16> states; + }; + static_assert(sizeof(TouchScreenEntry) == 0x298, "TouchScreenEntry is an invalid size"); + + struct TouchScreenSharedMemory { + CommonHeader header; + std::array<TouchScreenEntry, 17> shared_memory_entries{}; + INSERT_PADDING_BYTES(0x3c8); + }; + static_assert(sizeof(TouchScreenSharedMemory) == 0x3000, + "TouchScreenSharedMemory is an invalid size"); + TouchScreenSharedMemory shared_memory{}; + std::unique_ptr<Input::TouchDevice> touch_device; + s64_le last_touch{}; +}; +}; // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/xpad.cpp b/src/core/hle/service/hid/controllers/xpad.cpp new file mode 100644 index 000000000..521e925b7 --- /dev/null +++ b/src/core/hle/service/hid/controllers/xpad.cpp @@ -0,0 +1,38 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/common_types.h" +#include "common/swap.h" +#include "core/core_timing.h" +#include "core/hle/service/hid/controllers/xpad.h" + +namespace Service::HID { +constexpr size_t SHARED_MEMORY_OFFSET = 0x3C00; +void Controller_XPad::OnInit() {} +void Controller_XPad::OnRelease() {} +void Controller_XPad::OnUpdate(u8* data, size_t size) { + for (auto& xpad_entry : shared_memory.shared_memory_entries) { + xpad_entry.header.timestamp = CoreTiming::GetTicks(); + xpad_entry.header.total_entry_count = 17; + + if (!IsControllerActivated()) { + xpad_entry.header.entry_count = 0; + xpad_entry.header.last_entry_index = 0; + return; + } + xpad_entry.header.entry_count = 16; + + auto& last_entry = xpad_entry.pad_states[xpad_entry.header.last_entry_index]; + xpad_entry.header.last_entry_index = (xpad_entry.header.last_entry_index + 1) % 17; + auto& cur_entry = xpad_entry.pad_states[xpad_entry.header.last_entry_index]; + + cur_entry.sampling_number = last_entry.sampling_number + 1; + cur_entry.sampling_number2 = cur_entry.sampling_number; + } + // TODO(ogniK): Update xpad states + + std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); +} +void Controller_XPad::OnLoadInputDevices() {} +}; // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/xpad.h b/src/core/hle/service/hid/controllers/xpad.h new file mode 100644 index 000000000..898fadfdc --- /dev/null +++ b/src/core/hle/service/hid/controllers/xpad.h @@ -0,0 +1,59 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "common/swap.h" +#include "core/frontend/input.h" +#include "core/hle/service/hid/controllers/controller_base.h" + +namespace Service::HID { +class Controller_XPad final : public ControllerBase { +public: + Controller_XPad() = default; + + // Called when the controller is initialized + void OnInit() override; + + // When the controller is released + void OnRelease() override; + + // When the controller is requesting an update for the shared memory + void OnUpdate(u8* data, size_t size) override; + + // Called when input devices should be loaded + void OnLoadInputDevices() override; + +private: + struct AnalogStick { + s32_le x; + s32_le y; + }; + static_assert(sizeof(AnalogStick) == 0x8, "AnalogStick is an invalid size"); + + struct XPadState { + s64_le sampling_number; + s64_le sampling_number2; + s32_le attributes; + u32_le pad_states; + AnalogStick x_stick; + AnalogStick y_stick; + }; + static_assert(sizeof(XPadState) == 0x28, "XPadState is an invalid size"); + + struct XPadEntry { + CommonHeader header; + std::array<XPadState, 17> pad_states{}; + INSERT_PADDING_BYTES(0x138); + }; + static_assert(sizeof(XPadEntry) == 0x400, "XPadEntry is an invalid size"); + + struct SharedMemory { + std::array<XPadEntry, 4> shared_memory_entries{}; + }; + static_assert(sizeof(SharedMemory) == 0x1000, "SharedMemory is an invalid size"); + SharedMemory shared_memory{}; +}; +}; // namespace Service::HID |