diff options
| author | bunnei <bunneidev@gmail.com> | 2018-10-17 20:25:17 -0400 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-10-17 20:25:17 -0400 | 
| commit | 7dee60d7d24dabcc2c52c8c2135f1c89adb57ff6 (patch) | |
| tree | 042bae044e7b1f05eb5a561eefe37d847e0417cf | |
| parent | 77e2d68df7ef87168f286169c620701a2b2f298e (diff) | |
| parent | 8144fa42bdeb96524f506f935109df128f961847 (diff) | |
Merge pull request #1444 from ogniK5377/better-hid
"Better Hid" Rework Part 1
22 files changed, 1720 insertions, 648 deletions
| diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 78986deb5..4755ec822 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -236,6 +236,24 @@ add_library(core STATIC      hle/service/hid/irs.h      hle/service/hid/xcd.cpp      hle/service/hid/xcd.h +    hle/service/hid/controllers/controller_base.cpp +    hle/service/hid/controllers/controller_base.h +    hle/service/hid/controllers/debug_pad.cpp +    hle/service/hid/controllers/debug_pad.h +    hle/service/hid/controllers/gesture.cpp +    hle/service/hid/controllers/gesture.h +    hle/service/hid/controllers/keyboard.cpp +    hle/service/hid/controllers/keyboard.h +    hle/service/hid/controllers/mouse.cpp +    hle/service/hid/controllers/mouse.h +    hle/service/hid/controllers/npad.cpp +    hle/service/hid/controllers/npad.h +    hle/service/hid/controllers/stubbed.cpp +    hle/service/hid/controllers/stubbed.h +    hle/service/hid/controllers/touchscreen.cpp +    hle/service/hid/controllers/touchscreen.h +    hle/service/hid/controllers/xpad.cpp +    hle/service/hid/controllers/xpad.h      hle/service/lbl/lbl.cpp      hle/service/lbl/lbl.h      hle/service/ldn/ldn.cpp 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..1625e9c3d --- /dev/null +++ b/src/core/hle/service/hid/controllers/controller_base.cpp @@ -0,0 +1,28 @@ +// 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 { +ControllerBase::~ControllerBase() = default; + +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; +} +} // 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..fa98e2354 --- /dev/null +++ b/src/core/hle/service/hid/controllers/controller_base.h @@ -0,0 +1,45 @@ +// 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; +    virtual ~ControllerBase() = 0; + +    // 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, std::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..6f8ef6e3f --- /dev/null +++ b/src/core/hle/service/hid/controllers/debug_pad.cpp @@ -0,0 +1,42 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <cstring> +#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 { + +Controller_DebugPad::Controller_DebugPad() = default; + +void Controller_DebugPad::OnInit() {} + +void Controller_DebugPad::OnRelease() {} + +void Controller_DebugPad::OnUpdate(u8* data, std::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; + +    const auto& last_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; +    shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; +    auto& cur_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; + +    cur_entry.sampling_number = last_entry.sampling_number + 1; +    cur_entry.sampling_number2 = cur_entry.sampling_number; +    // 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..e35675fa1 --- /dev/null +++ b/src/core/hle/service/hid/controllers/debug_pad.h @@ -0,0 +1,55 @@ +// 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(); + +    // 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, std::size_t size) override; + +    // Called when input devices should be loaded +    void OnLoadInputDevices() override; + +private: +    struct AnalogStick { +        s32_le x; +        s32_le y; +    }; +    static_assert(sizeof(AnalogStick) == 0x8); + +    struct 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..b473b9e2b --- /dev/null +++ b/src/core/hle/service/hid/controllers/gesture.cpp @@ -0,0 +1,43 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <cstring> +#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 std::size_t SHARED_MEMORY_OFFSET = 0x3BA00; + +Controller_Gesture::Controller_Gesture() = default; + +void Controller_Gesture::OnInit() {} + +void Controller_Gesture::OnRelease() {} + +void Controller_Gesture::OnUpdate(u8* data, std::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; + +    const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; +    shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; +    auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + +    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..0ced50dfd --- /dev/null +++ b/src/core/hle/service/hid/controllers/gesture.h @@ -0,0 +1,62 @@ +// 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(); + +    // 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..089c02ac4 --- /dev/null +++ b/src/core/hle/service/hid/controllers/keyboard.cpp @@ -0,0 +1,43 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <cstring> +#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 std::size_t SHARED_MEMORY_OFFSET = 0x3800; + +Controller_Keyboard::Controller_Keyboard() = default; + +void Controller_Keyboard::OnInit() {} + +void Controller_Keyboard::OnRelease() {} + +void Controller_Keyboard::OnUpdate(u8* data, std::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; + +    const auto& last_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; +    shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; +    auto& cur_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; + +    cur_entry.sampling_number = last_entry.sampling_number + 1; +    cur_entry.sampling_number2 = cur_entry.sampling_number; +    // 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..778e14f7e --- /dev/null +++ b/src/core/hle/service/hid/controllers/keyboard.h @@ -0,0 +1,49 @@ +// 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(); + +    // 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, std::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..78e9b5e9e --- /dev/null +++ b/src/core/hle/service/hid/controllers/mouse.cpp @@ -0,0 +1,43 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <cstring> +#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 std::size_t SHARED_MEMORY_OFFSET = 0x3400; + +Controller_Mouse::Controller_Mouse() = default; + +void Controller_Mouse::OnInit() {} + +void Controller_Mouse::OnRelease() {} + +void Controller_Mouse::OnUpdate(u8* data, std::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..05358a4f5 --- /dev/null +++ b/src/core/hle/service/hid/controllers/mouse.h @@ -0,0 +1,49 @@ +// 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(); + +    // 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, std::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..d17e64b2a --- /dev/null +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -0,0 +1,429 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <algorithm> +#include <array> +#include <cstring> +#include "common/assert.h" +#include "common/bit_field.h" +#include "common/common_types.h" +#include "common/logging/log.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 std::size_t NPAD_OFFSET = 0x9A00; +constexpr u32 BATTERY_FULL = 2; +enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right }; + +Controller_NPad::Controller_NPad() = default; + +void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) { +    const auto controller_type = connected_controllers[controller_idx].type; +    auto& controller = shared_memory_entries[controller_idx]; +    if (controller_type == NPadControllerType::None) { +        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::JoyDual: +        controller.joy_styles.joycon_dual.Assign(1); +        controller.device_type.joycon_left.Assign(1); +        controller.device_type.joycon_right.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::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_vertical.Assign(1); // TODO(ogniK): Swap joycons orientations +    controller.properties.use_plus.Assign(1); +    controller.properties.use_minus.Assign(1); +    controller.battery_level[0] = BATTERY_FULL; +    controller.battery_level[1] = BATTERY_FULL; +    controller.battery_level[2] = BATTERY_FULL; +} + +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; +    std::size_t controller{}; +    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); +    } +    if (std::none_of(connected_controllers.begin(), connected_controllers.end(), +                     [](const ControllerHolder& controller) { return controller.is_connected; })) { +        supported_npad_id_types.resize(npad_id_list.size()); +        std::memcpy(supported_npad_id_types.data(), npad_id_list.data(), +                    npad_id_list.size() * sizeof(u32)); +        AddNewController(NPadControllerType::JoyDual); +    } +} + +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, std::size_t data_len) { +    if (!IsControllerActivated()) +        return; +    for (std::size_t i = 0; i < shared_memory_entries.size(); i++) { +        auto& npad = shared_memory_entries[i]; +        const std::array<NPadGeneric*, 7> controller_npads{&npad.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; + +            const 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; +        } + +        const auto& controller_type = connected_controllers[i].type; + +        if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) { +            continue; +        } + +        // Pad states +        ControllerPadState pad_state{}; +        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.d_left.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus()); +        pad_state.d_up.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus()); +        pad_state.d_right.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus()); +        pad_state.d_down.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus()); + +        pad_state.l_stick_left.Assign(buttons[LStick_Left - BUTTON_HID_BEGIN]->GetStatus()); +        pad_state.l_stick_up.Assign(buttons[LStick_Up - BUTTON_HID_BEGIN]->GetStatus()); +        pad_state.l_stick_right.Assign(buttons[LStick_Right - BUTTON_HID_BEGIN]->GetStatus()); +        pad_state.l_stick_down.Assign(buttons[LStick_Down - BUTTON_HID_BEGIN]->GetStatus()); + +        pad_state.r_stick_left.Assign(buttons[RStick_Left - BUTTON_HID_BEGIN]->GetStatus()); +        pad_state.r_stick_up.Assign(buttons[RStick_Up - BUTTON_HID_BEGIN]->GetStatus()); +        pad_state.r_stick_right.Assign(buttons[RStick_Right - BUTTON_HID_BEGIN]->GetStatus()); +        pad_state.r_stick_down.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<std::size_t>(JoystickId::Joystick_Left)]->GetStatus(); +        const auto [stick_r_x_f, stick_r_y_f] = +            sticks[static_cast<std::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 +        } +        libnx_entry.connection_status.raw = 0; + +        switch (controller_type) { +        case NPadControllerType::Handheld: +            handheld_entry.connection_status.raw = 0; +            handheld_entry.connection_status.IsConnected.Assign(1); +            if (!Settings::values.use_docked_mode) { +                handheld_entry.connection_status.IsWired.Assign(1); +            } +            handheld_entry.pad_states.raw = pad_state.raw; +            handheld_entry.l_stick = lstick_entry; +            handheld_entry.r_stick = rstick_entry; +            break; +        case NPadControllerType::JoyDual: +            dual_entry.connection_status.raw = 0; + +            dual_entry.connection_status.IsLeftJoyConnected.Assign(1); +            dual_entry.connection_status.IsRightJoyConnected.Assign(1); +            dual_entry.connection_status.IsConnected.Assign(1); + +            libnx_entry.connection_status.IsLeftJoyConnected.Assign(1); +            libnx_entry.connection_status.IsRightJoyConnected.Assign(1); +            libnx_entry.connection_status.IsConnected.Assign(1); + +            dual_entry.pad_states.raw = pad_state.raw; +            dual_entry.l_stick = lstick_entry; +            dual_entry.r_stick = rstick_entry; +        case NPadControllerType::JoyLeft: +            left_entry.connection_status.raw = 0; + +            left_entry.connection_status.IsConnected.Assign(1); +            left_entry.pad_states.raw = pad_state.raw; +            left_entry.l_stick = lstick_entry; +            left_entry.r_stick = rstick_entry; +            break; +        case NPadControllerType::JoyRight: +            right_entry.connection_status.raw = 0; + +            right_entry.connection_status.IsConnected.Assign(1); +            right_entry.pad_states.raw = pad_state.raw; +            right_entry.l_stick = lstick_entry; +            right_entry.r_stick = rstick_entry; +            break; +        case NPadControllerType::Pokeball: +            pokeball_entry.connection_status.raw = 0; + +            pokeball_entry.connection_status.IsConnected.Assign(1); +            pokeball_entry.connection_status.IsWired.Assign(1); + +            pokeball_entry.pad_states.raw = pad_state.raw; +            pokeball_entry.l_stick = lstick_entry; +            pokeball_entry.r_stick = rstick_entry; +            break; +        case NPadControllerType::ProController: +            main_controller.connection_status.raw = 0; + +            main_controller.connection_status.IsConnected.Assign(1); +            main_controller.connection_status.IsWired.Assign(1); +            main_controller.pad_states.raw = pad_state.raw; +            main_controller.l_stick = lstick_entry; +            main_controller.r_stick = rstick_entry; +            break; +        } + +        // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate +        // any controllers. +        libnx_entry.pad_states.raw = pad_state.raw; +        libnx_entry.l_stick = lstick_entry; +        libnx_entry.r_stick = rstick_entry; +    } +    std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(), +                shared_memory_entries.size() * sizeof(NPadEntry)); +} // namespace Service::HID + +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, std::size_t length) { +    ASSERT(length > 0 && (length % sizeof(u32)) == 0); +    supported_npad_id_types.clear(); +    supported_npad_id_types.resize(length / sizeof(u32)); +    std::memcpy(supported_npad_id_types.data(), data, length); +} + +const void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::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()); +} + +std::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) { +    if (!can_controllers_vibrate) { +        return; +    } +    for (std::size_t i = 0; i < controller_ids.size(); i++) { +        std::size_t controller_pos = i; +        // Handheld controller conversion +        if (controller_pos == 32) { +            controller_pos = 8; +        } +        // Unknown controller conversion +        if (controller_pos == 16) { +            controller_pos = 9; +        } +        if (connected_controllers[controller_pos].is_connected) { +            // 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 == NPadControllerType::Handheld) { +        connected_controllers[8] = {controller, true}; +        InitNewlyAddedControler(8); +        return; +    } +    const auto pos = +        std::find_if(connected_controllers.begin(), connected_controllers.end() - 2, +                     [](const ControllerHolder& holder) { return !holder.is_connected; }); +    if (pos == connected_controllers.end() - 2) { +        LOG_ERROR(Service_HID, "Cannot connect any more controllers!"); +        return; +    } +    const auto controller_id = std::distance(connected_controllers.begin(), pos); +    connected_controllers[controller_id] = {controller, true}; +    InitNewlyAddedControler(controller_id); +} + +void Controller_NPad::ConnectNPad(u32 npad_id) { +    if (npad_id >= connected_controllers.size()) +        return; +    connected_controllers[npad_id].is_connected = true; +} + +void Controller_NPad::DisconnectNPad(u32 npad_id) { +    if (npad_id >= connected_controllers.size()) +        return; +    connected_controllers[npad_id].is_connected = false; +} + +Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) { +    if (npad_id == npad_id_list.back() || npad_id == npad_id_list[npad_id_list.size() - 2]) { +        // These are controllers without led patterns +        return LedPattern{0, 0, 0, 0}; +    } +    switch (npad_id) { +    case 0: +        return LedPattern{1, 0, 0, 0}; +    case 1: +        return LedPattern{0, 1, 0, 0}; +    case 2: +        return LedPattern{0, 0, 1, 0}; +    case 3: +        return LedPattern{0, 0, 0, 1}; +    case 4: +        return LedPattern{1, 0, 0, 1}; +    case 5: +        return LedPattern{1, 0, 1, 0}; +    case 6: +        return LedPattern{1, 0, 1, 1}; +    case 7: +        return LedPattern{0, 1, 1, 0}; +    default: +        UNIMPLEMENTED_MSG("Unhandled npad_id {}", npad_id); +        return LedPattern{0, 0, 0, 0}; +    }; +} +void Controller_NPad::SetVibrationEnabled(bool can_vibrate) { +    can_controllers_vibrate = can_vibrate; +} +} // 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..9d07d258d --- /dev/null +++ b/src/core/hle/service/hid/controllers/npad.h @@ -0,0 +1,288 @@ +// 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(); + +    // 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, std::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, +        JoyDual, +        JoyLeft, +        JoyRight, +        Pokeball, +    }; + +    struct LedPattern { +        explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) { +            position1.Assign(light1); +            position1.Assign(light2); +            position1.Assign(light3); +            position1.Assign(light4); +        }; +        union { +            u64 raw{}; +            BitField<0, 1, u64> position1; +            BitField<1, 1, u64> position2; +            BitField<2, 1, u64> position3; +            BitField<3, 1, u64> position4; +        }; +    }; + +    void SetSupportedStyleSet(NPadType style_set); +    NPadType GetSupportedStyleSet() const; + +    void SetSupportedNPadIdTypes(u8* data, std::size_t length); +    const void GetSupportedNpadIdTypes(u32* data, std::size_t max_length); +    std::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); + +    void ConnectNPad(u32 npad_id); +    void DisconnectNPad(u32 npad_id); +    LedPattern GetLedPattern(u32 npad_id); +    void SetVibrationEnabled(bool can_vibrate); + +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> d_left; +            BitField<13, 1, u64_le> d_up; +            BitField<14, 1, u64_le> d_right; +            BitField<15, 1, u64_le> d_down; + +            // Left JoyStick +            BitField<16, 1, u64_le> l_stick_left; +            BitField<17, 1, u64_le> l_stick_up; +            BitField<18, 1, u64_le> l_stick_right; +            BitField<19, 1, u64_le> l_stick_down; + +            // Right JoyStick +            BitField<20, 1, u64_le> r_stick_left; +            BitField<21, 1, u64_le> r_stick_up; +            BitField<22, 1, u64_le> r_stick_right; +            BitField<23, 1, u64_le> r_stick_down; + +            // 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; +            BitField<2, 1, u32_le> IsLeftJoyConnected; +            BitField<3, 1, u32_le> IsLeftJoyWired; +            BitField<4, 1, u32_le> IsRightJoyConnected; +            BitField<5, 1, u32_le> IsRightJoyWired; +        }; +    }; +    static_assert(sizeof(ConnectionState) == 4, "ConnectionState is an invalid size"); + +    struct GenericStates { +        s64_le timestamp; +        s64_le timestamp2; +        ControllerPadState pad_states; +        AnalogPosition l_stick; +        AnalogPosition r_stick; +        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_vertical; +            BitField<12, 1, s64_le> is_horizontal; +            BitField<13, 1, s64_le> use_plus; +            BitField<14, 1, s64_le> use_minus; +        }; +    }; + +    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): SixAxis states, require more information before implementation +        NPadDevice device_type; +        NPadProperties properties; +        INSERT_PADDING_WORDS(1); +        std::array<u32, 3> battery_level; +        INSERT_PADDING_BYTES(0x5c); +        INSERT_PADDING_BYTES(0xdf8); +    }; +    static_assert(sizeof(NPadEntry) == 0x5000, "NPadEntry is an invalid size"); + +    struct ControllerHolder { +        Controller_NPad::NPadControllerType type; +        bool is_connected; +    }; + +    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; +    std::size_t dump_idx{}; +    Vibration last_processed_vibration{}; +    static constexpr std::array<u32, 10> npad_id_list{0, 1, 2, 3, 4, 5, 6, 7, 32, 16}; +    std::array<ControllerHolder, 10> connected_controllers{}; +    bool can_controllers_vibrate{true}; + +    void InitNewlyAddedControler(std::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..3a13d5991 --- /dev/null +++ b/src/core/hle/service/hid/controllers/stubbed.cpp @@ -0,0 +1,39 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <cstring> +#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 { + +Controller_Stubbed::Controller_Stubbed() = default; + +void Controller_Stubbed::OnInit() {} + +void Controller_Stubbed::OnRelease() {} + +void Controller_Stubbed::OnUpdate(u8* data, std::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(std::size_t off) { +    common_offset = off; +    smart_update = true; +} +} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/stubbed.h b/src/core/hle/service/hid/controllers/stubbed.h new file mode 100644 index 000000000..9c1b57f83 --- /dev/null +++ b/src/core/hle/service/hid/controllers/stubbed.h @@ -0,0 +1,33 @@ +// 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(); + +    // 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, std::size_t size) override; + +    // Called when input devices should be loaded +    void OnLoadInputDevices() override; + +    void SetCommonHeaderOffset(std::size_t off); + +private: +    bool smart_update{}; +    std::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..e97f84ea1 --- /dev/null +++ b/src/core/hle/service/hid/controllers/touchscreen.cpp @@ -0,0 +1,65 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <cstring> +#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 std::size_t SHARED_MEMORY_OFFSET = 0x400; + +Controller_Touchscreen::Controller_Touchscreen() = default; + +void Controller_Touchscreen::OnInit() {} + +void Controller_Touchscreen::OnRelease() {} + +void Controller_Touchscreen::OnUpdate(u8* data, std::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; + +    const auto& last_entry = +        shared_memory.shared_memory_entries[shared_memory.header.last_entry_index]; +    shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; +    auto& cur_entry = shared_memory.shared_memory_entries[shared_memory.header.last_entry_index]; + +    cur_entry.sampling_number = last_entry.sampling_number + 1; +    cur_entry.sampling_number2 = cur_entry.sampling_number; + +    const 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..1d97b6c2a --- /dev/null +++ b/src/core/hle/service/hid/controllers/touchscreen.h @@ -0,0 +1,62 @@ +// 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(); + +    // 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, std::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..df0b48451 --- /dev/null +++ b/src/core/hle/service/hid/controllers/xpad.cpp @@ -0,0 +1,45 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <cstring> +#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 std::size_t SHARED_MEMORY_OFFSET = 0x3C00; + +Controller_XPad::Controller_XPad() = default; + +void Controller_XPad::OnInit() {} + +void Controller_XPad::OnRelease() {} + +void Controller_XPad::OnUpdate(u8* data, std::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; + +        const auto& last_entry = xpad_entry.pad_states[xpad_entry.header.last_entry_index]; +        xpad_entry.header.last_entry_index = (xpad_entry.header.last_entry_index + 1) % 17; +        auto& cur_entry = xpad_entry.pad_states[xpad_entry.header.last_entry_index]; + +        cur_entry.sampling_number = last_entry.sampling_number + 1; +        cur_entry.sampling_number2 = cur_entry.sampling_number; +    } +    // 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..e2007183d --- /dev/null +++ b/src/core/hle/service/hid/controllers/xpad.h @@ -0,0 +1,60 @@ +// 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(); + +    // 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, std::size_t size) override; + +    // Called when input devices should be loaded +    void OnLoadInputDevices() override; + +private: +    struct AnalogStick { +        s32_le x; +        s32_le y; +    }; +    static_assert(sizeof(AnalogStick) == 0x8, "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 diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 7c6b0a4e6..8aca0f197 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -2,6 +2,8 @@  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. +#include <array> +#include "common/common_types.h"  #include "common/logging/log.h"  #include "core/core.h"  #include "core/core_timing.h" @@ -19,6 +21,16 @@  #include "core/hle/service/service.h"  #include "core/settings.h" +#include "core/hle/service/hid/controllers/controller_base.h" +#include "core/hle/service/hid/controllers/debug_pad.h" +#include "core/hle/service/hid/controllers/gesture.h" +#include "core/hle/service/hid/controllers/keyboard.h" +#include "core/hle/service/hid/controllers/mouse.h" +#include "core/hle/service/hid/controllers/npad.h" +#include "core/hle/service/hid/controllers/stubbed.h" +#include "core/hle/service/hid/controllers/touchscreen.h" +#include "core/hle/service/hid/controllers/xpad.h" +  namespace Service::HID {  // Updating period for each HID device. @@ -26,6 +38,22 @@ namespace Service::HID {  constexpr u64 pad_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100;  constexpr u64 accelerometer_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100;  constexpr u64 gyroscope_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; +constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; +enum class HidController : std::size_t { +    DebugPad, +    Touchscreen, +    Mouse, +    Keyboard, +    XPad, +    Unknown1, +    Unknown2, +    Unknown3, +    SixAxisSensor, +    NPad, +    Gesture, + +    MaxControllers, +};  class IAppletResource final : public ServiceFramework<IAppletResource> {  public: @@ -37,19 +65,57 @@ public:          auto& kernel = Core::System::GetInstance().Kernel();          shared_mem = Kernel::SharedMemory::Create( -            kernel, nullptr, 0x40000, Kernel::MemoryPermission::ReadWrite, +            kernel, nullptr, SHARED_MEMORY_SIZE, Kernel::MemoryPermission::ReadWrite,              Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "HID:SharedMemory"); +        MakeController<Controller_DebugPad>(HidController::DebugPad); +        MakeController<Controller_Touchscreen>(HidController::Touchscreen); +        MakeController<Controller_Mouse>(HidController::Mouse); +        MakeController<Controller_Keyboard>(HidController::Keyboard); +        MakeController<Controller_XPad>(HidController::XPad); +        MakeController<Controller_Stubbed>(HidController::Unknown1); +        MakeController<Controller_Stubbed>(HidController::Unknown2); +        MakeController<Controller_Stubbed>(HidController::Unknown3); +        MakeController<Controller_Stubbed>(HidController::SixAxisSensor); +        MakeController<Controller_NPad>(HidController::NPad); +        MakeController<Controller_Gesture>(HidController::Gesture); + +        // Homebrew doesn't try to activate some controllers, so we activate them by default +        GetController<Controller_NPad>(HidController::NPad).ActivateController(); +        GetController<Controller_Touchscreen>(HidController::Touchscreen).ActivateController(); + +        GetController<Controller_Stubbed>(HidController::Unknown1).SetCommonHeaderOffset(0x4c00); +        GetController<Controller_Stubbed>(HidController::Unknown2).SetCommonHeaderOffset(0x4e00); +        GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000); +          // Register update callbacks          pad_update_event = CoreTiming::RegisterEvent(              "HID::UpdatePadCallback", -            [this](u64 userdata, int cycles_late) { UpdatePadCallback(userdata, cycles_late); }); +            [this](u64 userdata, int cycles_late) { UpdateControllers(userdata, cycles_late); });          // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?)          CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event);      } +    void ActivateController(HidController controller) { +        controllers[static_cast<size_t>(controller)]->ActivateController(); +    } + +    void DeactivateController(HidController controller) { +        controllers[static_cast<size_t>(controller)]->DeactivateController(); +    } + +    template <typename T> +    void MakeController(HidController controller) { +        controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(); +    } + +    template <typename T> +    T& GetController(HidController controller) { +        return static_cast<T&>(*controllers[static_cast<size_t>(controller)]); +    } +      ~IAppletResource() {          CoreTiming::UnscheduleEvent(pad_update_event, 0);      } @@ -62,200 +128,15 @@ private:          LOG_DEBUG(Service_HID, "called");      } -    void LoadInputDevices() { -        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>); -        touch_device = Input::CreateDevice<Input::TouchDevice>(Settings::values.touch_device); -        // TODO(shinyquagsire23): gyro, mouse, keyboard -    } - -    void UpdatePadCallback(u64 userdata, int cycles_late) { -        SharedMemory mem{}; -        std::memcpy(&mem, shared_mem->GetPointer(), sizeof(SharedMemory)); - -        if (Settings::values.is_device_reload_pending.exchange(false)) -            LoadInputDevices(); - -        // Set up controllers as neon red+blue Joy-Con attached to console -        ControllerHeader& controller_header = mem.controllers[Controller_Handheld].header; -        controller_header.type = ControllerType_Handheld; -        controller_header.single_colors_descriptor = ColorDesc_ColorsNonexistent; -        controller_header.right_color_body = JOYCON_BODY_NEON_RED; -        controller_header.right_color_buttons = JOYCON_BUTTONS_NEON_RED; -        controller_header.left_color_body = JOYCON_BODY_NEON_BLUE; -        controller_header.left_color_buttons = JOYCON_BUTTONS_NEON_BLUE; - -        for (std::size_t controller = 0; controller < mem.controllers.size(); controller++) { -            for (auto& layout : mem.controllers[controller].layouts) { -                layout.header.num_entries = HID_NUM_ENTRIES; -                layout.header.max_entry_index = HID_NUM_ENTRIES - 1; - -                // HID shared memory stores the state of the past 17 samples in a circlular buffer, -                // each with a timestamp in number of samples since boot. -                const ControllerInputEntry& last_entry = layout.entries[layout.header.latest_entry]; - -                layout.header.timestamp_ticks = CoreTiming::GetTicks(); -                layout.header.latest_entry = (layout.header.latest_entry + 1) % HID_NUM_ENTRIES; - -                ControllerInputEntry& entry = layout.entries[layout.header.latest_entry]; -                entry.timestamp = last_entry.timestamp + 1; -                // TODO(shinyquagsire23): Is this always identical to timestamp? -                entry.timestamp_2 = entry.timestamp; - -                // TODO(shinyquagsire23): More than just handheld input -                if (controller != Controller_Handheld) -                    continue; - -                entry.connection_state = ConnectionState_Connected | ConnectionState_Wired; - -                // TODO(shinyquagsire23): Set up some LUTs for each layout mapping in the future? -                // For now everything is just the default handheld layout, but split Joy-Con will -                // rotate the face buttons and directions for certain layouts. -                ControllerPadState& state = entry.buttons; -                using namespace Settings::NativeButton; -                state.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus()); -                state.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus()); -                state.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus()); -                state.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus()); -                state.lstick.Assign(buttons[LStick - BUTTON_HID_BEGIN]->GetStatus()); -                state.rstick.Assign(buttons[RStick - BUTTON_HID_BEGIN]->GetStatus()); -                state.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus()); -                state.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus()); -                state.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus()); -                state.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus()); -                state.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus()); -                state.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus()); - -                state.dleft.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus()); -                state.dup.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus()); -                state.dright.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus()); -                state.ddown.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus()); - -                state.lstick_left.Assign(buttons[LStick_Left - BUTTON_HID_BEGIN]->GetStatus()); -                state.lstick_up.Assign(buttons[LStick_Up - BUTTON_HID_BEGIN]->GetStatus()); -                state.lstick_right.Assign(buttons[LStick_Right - BUTTON_HID_BEGIN]->GetStatus()); -                state.lstick_down.Assign(buttons[LStick_Down - BUTTON_HID_BEGIN]->GetStatus()); - -                state.rstick_left.Assign(buttons[RStick_Left - BUTTON_HID_BEGIN]->GetStatus()); -                state.rstick_up.Assign(buttons[RStick_Up - BUTTON_HID_BEGIN]->GetStatus()); -                state.rstick_right.Assign(buttons[RStick_Right - BUTTON_HID_BEGIN]->GetStatus()); -                state.rstick_down.Assign(buttons[RStick_Down - BUTTON_HID_BEGIN]->GetStatus()); - -                state.sl.Assign(buttons[SL - BUTTON_HID_BEGIN]->GetStatus()); -                state.sr.Assign(buttons[SR - BUTTON_HID_BEGIN]->GetStatus()); - -                const auto [stick_l_x_f, stick_l_y_f] = sticks[Joystick_Left]->GetStatus(); -                const auto [stick_r_x_f, stick_r_y_f] = sticks[Joystick_Right]->GetStatus(); -                entry.joystick_left_x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX); -                entry.joystick_left_y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX); -                entry.joystick_right_x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX); -                entry.joystick_right_y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX); +    void UpdateControllers(u64 userdata, int cycles_late) { +        const bool should_reload = Settings::values.is_device_reload_pending.exchange(false); +        for (const auto& controller : controllers) { +            if (should_reload) { +                controller->OnLoadInputDevices();              } +            controller->OnUpdate(shared_mem->GetPointer(), SHARED_MEMORY_SIZE);          } -        TouchScreen& touchscreen = mem.touchscreen; -        const u64 last_entry = touchscreen.header.latest_entry; -        const u64 curr_entry = (last_entry + 1) % touchscreen.entries.size(); -        const u64 timestamp = CoreTiming::GetTicks(); -        const u64 sample_counter = touchscreen.entries[last_entry].header.timestamp + 1; -        touchscreen.header.timestamp_ticks = timestamp; -        touchscreen.header.num_entries = touchscreen.entries.size(); -        touchscreen.header.latest_entry = curr_entry; -        touchscreen.header.max_entry_index = touchscreen.entries.size(); -        touchscreen.header.timestamp = timestamp; -        touchscreen.entries[curr_entry].header.timestamp = sample_counter; - -        TouchScreenEntryTouch touch_entry{}; -        auto [x, y, pressed] = touch_device->GetStatus(); -        touch_entry.timestamp = timestamp; -        touch_entry.x = static_cast<u16>(x * Layout::ScreenUndocked::Width); -        touch_entry.y = static_cast<u16>(y * Layout::ScreenUndocked::Height); -        touch_entry.touch_index = 0; - -        // TODO(DarkLordZach): Maybe try to derive these from EmuWindow? -        touch_entry.diameter_x = 15; -        touch_entry.diameter_y = 15; -        touch_entry.angle = 0; - -        // TODO(DarkLordZach): Implement multi-touch support -        if (pressed) { -            touchscreen.entries[curr_entry].header.num_touches = 1; -            touchscreen.entries[curr_entry].touches[0] = touch_entry; -        } else { -            touchscreen.entries[curr_entry].header.num_touches = 0; -        } - -        // TODO(shinyquagsire23): Properly implement mouse -        Mouse& mouse = mem.mouse; -        const u64 last_mouse_entry = mouse.header.latest_entry; -        const u64 curr_mouse_entry = (mouse.header.latest_entry + 1) % mouse.entries.size(); -        const u64 mouse_sample_counter = mouse.entries[last_mouse_entry].timestamp + 1; -        mouse.header.timestamp_ticks = timestamp; -        mouse.header.num_entries = mouse.entries.size(); -        mouse.header.max_entry_index = mouse.entries.size(); -        mouse.header.latest_entry = curr_mouse_entry; - -        mouse.entries[curr_mouse_entry].timestamp = mouse_sample_counter; -        mouse.entries[curr_mouse_entry].timestamp_2 = mouse_sample_counter; - -        // TODO(shinyquagsire23): Properly implement keyboard -        Keyboard& keyboard = mem.keyboard; -        const u64 last_keyboard_entry = keyboard.header.latest_entry; -        const u64 curr_keyboard_entry = -            (keyboard.header.latest_entry + 1) % keyboard.entries.size(); -        const u64 keyboard_sample_counter = keyboard.entries[last_keyboard_entry].timestamp + 1; -        keyboard.header.timestamp_ticks = timestamp; -        keyboard.header.num_entries = keyboard.entries.size(); -        keyboard.header.latest_entry = last_keyboard_entry; -        keyboard.header.max_entry_index = keyboard.entries.size(); - -        keyboard.entries[curr_keyboard_entry].timestamp = keyboard_sample_counter; -        keyboard.entries[curr_keyboard_entry].timestamp_2 = keyboard_sample_counter; - -        // TODO(shinyquagsire23): Figure out what any of these are -        for (auto& input : mem.unk_input_1) { -            const u64 last_input_entry = input.header.latest_entry; -            const u64 curr_input_entry = (input.header.latest_entry + 1) % input.entries.size(); -            const u64 input_sample_counter = input.entries[last_input_entry].timestamp + 1; - -            input.header.timestamp_ticks = timestamp; -            input.header.num_entries = input.entries.size(); -            input.header.latest_entry = last_input_entry; -            input.header.max_entry_index = input.entries.size(); - -            input.entries[curr_input_entry].timestamp = input_sample_counter; -            input.entries[curr_input_entry].timestamp_2 = input_sample_counter; -        } - -        for (auto& input : mem.unk_input_2) { -            input.header.timestamp_ticks = timestamp; -            input.header.num_entries = 17; -            input.header.latest_entry = 0; -            input.header.max_entry_index = 0; -        } - -        UnkInput3& input = mem.unk_input_3; -        const u64 last_input_entry = input.header.latest_entry; -        const u64 curr_input_entry = (input.header.latest_entry + 1) % input.entries.size(); -        const u64 input_sample_counter = input.entries[last_input_entry].timestamp + 1; - -        input.header.timestamp_ticks = timestamp; -        input.header.num_entries = input.entries.size(); -        input.header.latest_entry = last_input_entry; -        input.header.max_entry_index = input.entries.size(); - -        input.entries[curr_input_entry].timestamp = input_sample_counter; -        input.entries[curr_input_entry].timestamp_2 = input_sample_counter; - -        // TODO(shinyquagsire23): Signal events - -        std::memcpy(shared_mem->GetPointer(), &mem, sizeof(SharedMemory)); - -        // Reschedule recurrent event          CoreTiming::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event);      } @@ -265,11 +146,8 @@ private:      // CoreTiming update events      CoreTiming::EventType* pad_update_event; -    // Stored input state info -    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::unique_ptr<Input::TouchDevice> touch_device; +    std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)> +        controllers{};  };  class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> { @@ -301,7 +179,7 @@ public:              {31, &Hid::ActivateKeyboard, "ActivateKeyboard"},              {40, nullptr, "AcquireXpadIdEventHandle"},              {41, nullptr, "ReleaseXpadIdEventHandle"}, -            {51, nullptr, "ActivateXpad"}, +            {51, &Hid::ActivateXpad, "ActivateXpad"},              {55, nullptr, "GetXpadIds"},              {56, nullptr, "ActivateJoyXpad"},              {58, nullptr, "GetJoyXpadLifoHandle"}, @@ -362,8 +240,8 @@ public:              {206, &Hid::SendVibrationValues, "SendVibrationValues"},              {207, nullptr, "SendVibrationGcErmCommand"},              {208, nullptr, "GetActualVibrationGcErmCommand"}, -            {209, nullptr, "BeginPermitVibrationSession"}, -            {210, nullptr, "EndPermitVibrationSession"}, +            {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"}, +            {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"},              {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"},              {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"},              {302, nullptr, "StopConsoleSixAxisSensor"}, @@ -401,16 +279,11 @@ public:          // clang-format on          RegisterHandlers(functions); - -        auto& kernel = Core::System::GetInstance().Kernel(); -        event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "hid:EventHandle");      }      ~Hid() = default;  private:      std::shared_ptr<IAppletResource> applet_resource; -    u32 joy_hold_type{0}; -    Kernel::SharedPtr<Kernel::Event> event;      void CreateAppletResource(Kernel::HLERequestContext& ctx) {          if (applet_resource == nullptr) { @@ -423,31 +296,59 @@ private:          LOG_DEBUG(Service_HID, "called");      } +    void ActivateXpad(Kernel::HLERequestContext& ctx) { +        applet_resource->ActivateController(HidController::XPad); +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +        LOG_DEBUG(Service_HID, "called"); +    } +      void ActivateDebugPad(Kernel::HLERequestContext& ctx) { +        applet_resource->ActivateController(HidController::DebugPad);          IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS); -        LOG_WARNING(Service_HID, "(STUBBED) called"); +        LOG_DEBUG(Service_HID, "called");      }      void ActivateTouchScreen(Kernel::HLERequestContext& ctx) { +        applet_resource->ActivateController(HidController::Touchscreen);          IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS); -        LOG_WARNING(Service_HID, "(STUBBED) called"); +        LOG_DEBUG(Service_HID, "called");      }      void ActivateMouse(Kernel::HLERequestContext& ctx) { +        applet_resource->ActivateController(HidController::Mouse);          IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS); -        LOG_WARNING(Service_HID, "(STUBBED) called"); +        LOG_DEBUG(Service_HID, "called");      }      void ActivateKeyboard(Kernel::HLERequestContext& ctx) { +        applet_resource->ActivateController(HidController::Keyboard);          IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS); -        LOG_WARNING(Service_HID, "(STUBBED) called"); +        LOG_DEBUG(Service_HID, "called"); +    } + +    void ActivateGesture(Kernel::HLERequestContext& ctx) { +        applet_resource->ActivateController(HidController::Gesture); +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +        LOG_DEBUG(Service_HID, "called"); +    } + +    void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { +        // Should have no effect with how our npad sets up the data +        applet_resource->ActivateController(HidController::NPad); +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +        LOG_DEBUG(Service_HID, "called");      }      void StartSixAxisSensor(Kernel::HLERequestContext& ctx) { +        IPC::RequestParser rp{ctx}; +        auto handle = rp.PopRaw<u32>();          IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS);          LOG_WARNING(Service_HID, "(STUBBED) called"); @@ -468,84 +369,168 @@ private:      }      void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { +        IPC::RequestParser rp{ctx}; +        auto supported_styleset = rp.PopRaw<u32>(); +        applet_resource->GetController<Controller_NPad>(HidController::NPad) +            .SetSupportedStyleSet({supported_styleset}); +          IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS); -        LOG_WARNING(Service_HID, "(STUBBED) called"); + +        LOG_DEBUG(Service_HID, "called");      }      void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { +        auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); +          IPC::ResponseBuilder rb{ctx, 3};          rb.Push(RESULT_SUCCESS); -        rb.Push<u32>(0); -        LOG_WARNING(Service_HID, "(STUBBED) called"); +        rb.Push<u32>(controller.GetSupportedStyleSet().raw); +        LOG_DEBUG(Service_HID, "called");      }      void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { +        applet_resource->GetController<Controller_NPad>(HidController::NPad) +            .SetSupportedNPadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize());          IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS); -        LOG_WARNING(Service_HID, "(STUBBED) called"); +        LOG_DEBUG(Service_HID, "called");      }      void ActivateNpad(Kernel::HLERequestContext& ctx) {          IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS); -        LOG_WARNING(Service_HID, "(STUBBED) called"); +        applet_resource->ActivateController(HidController::NPad); +        LOG_DEBUG(Service_HID, "called");      }      void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { +        IPC::RequestParser rp{ctx}; +        auto npad_id = rp.PopRaw<u32>();          IPC::ResponseBuilder rb{ctx, 2, 1};          rb.Push(RESULT_SUCCESS); -        rb.PushCopyObjects(event); -        LOG_WARNING(Service_HID, "(STUBBED) called"); +        rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad) +                               .GetStyleSetChangedEvent()); +        LOG_DEBUG(Service_HID, "called");      }      void DisconnectNpad(Kernel::HLERequestContext& ctx) { +        IPC::RequestParser rp{ctx}; +        auto npad_id = rp.PopRaw<u32>(); +        applet_resource->GetController<Controller_NPad>(HidController::NPad) +            .DisconnectNPad(npad_id);          IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS); -        LOG_WARNING(Service_HID, "(STUBBED) called"); +        LOG_DEBUG(Service_HID, "called");      }      void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { -        IPC::ResponseBuilder rb{ctx, 2}; +        IPC::RequestParser rp{ctx}; +        auto npad_id = rp.PopRaw<u32>(); +        IPC::ResponseBuilder rb{ctx, 4};          rb.Push(RESULT_SUCCESS); -        LOG_WARNING(Service_HID, "(STUBBED) called"); +        rb.PushRaw<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad) +                            .GetLedPattern(npad_id) +                            .raw); +        LOG_DEBUG(Service_HID, "called");      }      void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { +        auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); +        IPC::RequestParser rp{ctx}; +        const auto hold_type = rp.PopRaw<u64>(); +        controller.SetHoldType(Controller_NPad::NpadHoldType{hold_type}); +          IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS); -        LOG_WARNING(Service_HID, "(STUBBED) called"); +        LOG_DEBUG(Service_HID, "called");      }      void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { -        IPC::ResponseBuilder rb{ctx, 3}; +        const auto& controller = +            applet_resource->GetController<Controller_NPad>(HidController::NPad); +        IPC::ResponseBuilder rb{ctx, 4};          rb.Push(RESULT_SUCCESS); -        rb.Push(joy_hold_type); -        LOG_WARNING(Service_HID, "(STUBBED) called"); +        rb.Push<u64>(static_cast<u64>(controller.GetHoldType())); +        LOG_DEBUG(Service_HID, "called");      }      void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { +        IPC::RequestParser rp{ctx}; +        auto npad_id = rp.PopRaw<u32>();          IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS);          LOG_WARNING(Service_HID, "(STUBBED) called");      } +    void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) { +        applet_resource->GetController<Controller_NPad>(HidController::NPad) +            .SetVibrationEnabled(true); +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +        LOG_DEBUG(Service_HID, "called"); +    } + +    void EndPermitVibrationSession(Kernel::HLERequestContext& ctx) { +        applet_resource->GetController<Controller_NPad>(HidController::NPad) +            .SetVibrationEnabled(false); +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +        LOG_DEBUG(Service_HID, "called"); +    } +      void SendVibrationValue(Kernel::HLERequestContext& ctx) { +        IPC::RequestParser rp{ctx}; +        const auto controller_id = rp.PopRaw<u32>(); +        const auto vibration_values = rp.PopRaw<Controller_NPad::Vibration>(); +          IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS); -        LOG_WARNING(Service_HID, "(STUBBED) called"); + +        applet_resource->GetController<Controller_NPad>(HidController::NPad) +            .VibrateController({controller_id}, {vibration_values}); +        LOG_DEBUG(Service_HID, "called");      } -    void GetActualVibrationValue(Kernel::HLERequestContext& ctx) { +    void SendVibrationValues(Kernel::HLERequestContext& ctx) { +        const auto controllers = ctx.ReadBuffer(0); +        const auto vibrations = ctx.ReadBuffer(1); + +        std::vector<u32> controller_list(controllers.size() / sizeof(u32)); +        std::vector<Controller_NPad::Vibration> vibration_list(vibrations.size() / +                                                               sizeof(Controller_NPad::Vibration)); + +        std::memcpy(controller_list.data(), controllers.data(), controllers.size()); +        std::memcpy(vibration_list.data(), vibrations.data(), vibrations.size()); +        std::transform(controller_list.begin(), controller_list.end(), controller_list.begin(), +                       [](u32 controller_id) { return controller_id - 3; }); + +        applet_resource->GetController<Controller_NPad>(HidController::NPad) +            .VibrateController(controller_list, vibration_list); +          IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS); -        LOG_WARNING(Service_HID, "(STUBBED) called"); +        LOG_DEBUG(Service_HID, "called"); +    } + +    void GetActualVibrationValue(Kernel::HLERequestContext& ctx) { +        IPC::ResponseBuilder rb{ctx, 6}; +        rb.Push(RESULT_SUCCESS); +        rb.PushRaw<Controller_NPad::Vibration>( +            applet_resource->GetController<Controller_NPad>(HidController::NPad) +                .GetLastVibration()); +        LOG_DEBUG(Service_HID, "called");      }      void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { +        IPC::RequestParser rp{ctx}; +        const auto npad_id = rp.PopRaw<u32>(); +        auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); +        controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual); +          IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS); -        LOG_WARNING(Service_HID, "(STUBBED) called"); +        LOG_DEBUG(Service_HID, "called");      }      void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { @@ -555,6 +540,8 @@ private:      }      void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { +        IPC::RequestParser rp{ctx}; +        auto mode = rp.PopRaw<u32>();          IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS);          LOG_WARNING(Service_HID, "(STUBBED) called"); @@ -563,8 +550,9 @@ private:      void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {          IPC::ResponseBuilder rb{ctx, 4};          rb.Push(RESULT_SUCCESS); -        rb.Push<u64>(0); -        LOG_WARNING(Service_HID, "(STUBBED) called"); +        rb.Push<u32>(1); +        rb.Push<u32>(0); +        LOG_DEBUG(Service_HID, "called");      }      void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) { @@ -574,12 +562,6 @@ private:          LOG_DEBUG(Service_HID, "called");      } -    void SendVibrationValues(Kernel::HLERequestContext& ctx) { -        IPC::ResponseBuilder rb{ctx, 2}; -        rb.Push(RESULT_SUCCESS); -        LOG_WARNING(Service_HID, "(STUBBED) called"); -    } -      void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {          IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS); @@ -597,18 +579,6 @@ private:          rb.Push(RESULT_SUCCESS);          LOG_WARNING(Service_HID, "(STUBBED) called");      } - -    void ActivateGesture(Kernel::HLERequestContext& ctx) { -        IPC::ResponseBuilder rb{ctx, 2}; -        rb.Push(RESULT_SUCCESS); -        LOG_WARNING(Service_HID, "(STUBBED) called"); -    } - -    void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { -        IPC::ResponseBuilder rb{ctx, 2}; -        rb.Push(RESULT_SUCCESS); -        LOG_WARNING(Service_HID, "(STUBBED) called"); -    }  };  class HidDbg final : public ServiceFramework<HidDbg> { diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 88d926808..773035460 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -4,408 +4,12 @@  #pragma once -#include <array> -#include "common/bit_field.h" -#include "common/common_types.h" -#include "core/hle/service/service.h" +namespace SM { +class ServiceManager; +}  namespace Service::HID { -// Begin enums and output structs - -constexpr u32 HID_NUM_ENTRIES = 17; -constexpr u32 HID_NUM_LAYOUTS = 7; -constexpr s32 HID_JOYSTICK_MAX = 0x8000; -constexpr s32 HID_JOYSTICK_MIN = -0x8000; - -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; - -enum ControllerType : u32 { -    ControllerType_ProController = 1 << 0, -    ControllerType_Handheld = 1 << 1, -    ControllerType_JoyconPair = 1 << 2, -    ControllerType_JoyconLeft = 1 << 3, -    ControllerType_JoyconRight = 1 << 4, -}; - -enum ControllerLayoutType : u32 { -    Layout_ProController = 0, // Pro Controller or HID gamepad -    Layout_Handheld = 1,      // Two Joy-Con docked to rails -    Layout_Single = 2, // Horizontal single Joy-Con or pair of Joy-Con, adjusted for orientation -    Layout_Left = 3,   // Only raw left Joy-Con state, no orientation adjustment -    Layout_Right = 4,  // Only raw right Joy-Con state, no orientation adjustment -    Layout_DefaultDigital = 5, // Same as next, but sticks have 8-direction values only -    Layout_Default = 6, // Safe default, single Joy-Con have buttons/sticks rotated for orientation -}; - -enum ControllerColorDescription { -    ColorDesc_ColorsNonexistent = 1 << 1, -}; - -enum ControllerConnectionState { -    ConnectionState_Connected = 1 << 0, -    ConnectionState_Wired = 1 << 1, -}; - -enum ControllerJoystick { -    Joystick_Left = 0, -    Joystick_Right = 1, -}; - -enum ControllerID { -    Controller_Player1 = 0, -    Controller_Player2 = 1, -    Controller_Player3 = 2, -    Controller_Player4 = 3, -    Controller_Player5 = 4, -    Controller_Player6 = 5, -    Controller_Player7 = 6, -    Controller_Player8 = 7, -    Controller_Handheld = 8, -    Controller_Unknown = 9, -}; - -// End enums and output structs - -// Begin UnkInput3 - -struct UnkInput3Header { -    u64 timestamp_ticks; -    u64 num_entries; -    u64 latest_entry; -    u64 max_entry_index; -}; -static_assert(sizeof(UnkInput3Header) == 0x20, "HID UnkInput3 header structure has incorrect size"); - -struct UnkInput3Entry { -    u64 timestamp; -    u64 timestamp_2; -    u64 unk_8; -    u64 unk_10; -    u64 unk_18; -}; -static_assert(sizeof(UnkInput3Entry) == 0x28, "HID UnkInput3 entry structure has incorrect size"); - -struct UnkInput3 { -    UnkInput3Header header; -    std::array<UnkInput3Entry, 17> entries; -    std::array<u8, 0x138> padding; -}; -static_assert(sizeof(UnkInput3) == 0x400, "HID UnkInput3 structure has incorrect size"); - -// End UnkInput3 - -// Begin TouchScreen - -struct TouchScreenHeader { -    u64 timestamp_ticks; -    u64 num_entries; -    u64 latest_entry; -    u64 max_entry_index; -    u64 timestamp; -}; -static_assert(sizeof(TouchScreenHeader) == 0x28, -              "HID touch screen header structure has incorrect size"); - -struct TouchScreenEntryHeader { -    u64 timestamp; -    u64 num_touches; -}; -static_assert(sizeof(TouchScreenEntryHeader) == 0x10, -              "HID touch screen entry header structure has incorrect size"); - -struct TouchScreenEntryTouch { -    u64 timestamp; -    u32 padding; -    u32 touch_index; -    u32 x; -    u32 y; -    u32 diameter_x; -    u32 diameter_y; -    u32 angle; -    u32 padding_2; -}; -static_assert(sizeof(TouchScreenEntryTouch) == 0x28, -              "HID touch screen touch structure has incorrect size"); - -struct TouchScreenEntry { -    TouchScreenEntryHeader header; -    std::array<TouchScreenEntryTouch, 16> touches; -    u64 unk; -}; -static_assert(sizeof(TouchScreenEntry) == 0x298, -              "HID touch screen entry structure has incorrect size"); - -struct TouchScreen { -    TouchScreenHeader header; -    std::array<TouchScreenEntry, 17> entries; -    std::array<u8, 0x3c0> padding; -}; -static_assert(sizeof(TouchScreen) == 0x3000, "HID touch screen structure has incorrect size"); - -// End TouchScreen - -// Begin Mouse - -struct MouseHeader { -    u64 timestamp_ticks; -    u64 num_entries; -    u64 latest_entry; -    u64 max_entry_index; -}; -static_assert(sizeof(MouseHeader) == 0x20, "HID mouse header structure has incorrect size"); - -struct MouseButtonState { -    union { -        u64 hex{}; - -        // Buttons -        BitField<0, 1, u64> left; -        BitField<1, 1, u64> right; -        BitField<2, 1, u64> middle; -        BitField<3, 1, u64> forward; -        BitField<4, 1, u64> back; -    }; -}; - -struct MouseEntry { -    u64 timestamp; -    u64 timestamp_2; -    u32 x; -    u32 y; -    u32 velocity_x; -    u32 velocity_y; -    u32 scroll_velocity_x; -    u32 scroll_velocity_y; -    MouseButtonState buttons; -}; -static_assert(sizeof(MouseEntry) == 0x30, "HID mouse entry structure has incorrect size"); - -struct Mouse { -    MouseHeader header; -    std::array<MouseEntry, 17> entries; -    std::array<u8, 0xB0> padding; -}; -static_assert(sizeof(Mouse) == 0x400, "HID mouse structure has incorrect size"); - -// End Mouse - -// Begin Keyboard - -struct KeyboardHeader { -    u64 timestamp_ticks; -    u64 num_entries; -    u64 latest_entry; -    u64 max_entry_index; -}; -static_assert(sizeof(KeyboardHeader) == 0x20, "HID keyboard header structure has incorrect size"); - -struct KeyboardModifierKeyState { -    union { -        u64 hex{}; - -        // Buttons -        BitField<0, 1, u64> lctrl; -        BitField<1, 1, u64> lshift; -        BitField<2, 1, u64> lalt; -        BitField<3, 1, u64> lmeta; -        BitField<4, 1, u64> rctrl; -        BitField<5, 1, u64> rshift; -        BitField<6, 1, u64> ralt; -        BitField<7, 1, u64> rmeta; -        BitField<8, 1, u64> capslock; -        BitField<9, 1, u64> scrolllock; -        BitField<10, 1, u64> numlock; -    }; -}; - -struct KeyboardEntry { -    u64 timestamp; -    u64 timestamp_2; -    KeyboardModifierKeyState modifier; -    u32 keys[8]; -}; -static_assert(sizeof(KeyboardEntry) == 0x38, "HID keyboard entry structure has incorrect size"); - -struct Keyboard { -    KeyboardHeader header; -    std::array<KeyboardEntry, 17> entries; -    std::array<u8, 0x28> padding; -}; -static_assert(sizeof(Keyboard) == 0x400, "HID keyboard structure has incorrect size"); - -// End Keyboard - -// Begin UnkInput1 - -struct UnkInput1Header { -    u64 timestamp_ticks; -    u64 num_entries; -    u64 latest_entry; -    u64 max_entry_index; -}; -static_assert(sizeof(UnkInput1Header) == 0x20, "HID UnkInput1 header structure has incorrect size"); - -struct UnkInput1Entry { -    u64 timestamp; -    u64 timestamp_2; -    u64 unk_8; -    u64 unk_10; -    u64 unk_18; -}; -static_assert(sizeof(UnkInput1Entry) == 0x28, "HID UnkInput1 entry structure has incorrect size"); - -struct UnkInput1 { -    UnkInput1Header header; -    std::array<UnkInput1Entry, 17> entries; -    std::array<u8, 0x138> padding; -}; -static_assert(sizeof(UnkInput1) == 0x400, "HID UnkInput1 structure has incorrect size"); - -// End UnkInput1 - -// Begin UnkInput2 - -struct UnkInput2Header { -    u64 timestamp_ticks; -    u64 num_entries; -    u64 latest_entry; -    u64 max_entry_index; -}; -static_assert(sizeof(UnkInput2Header) == 0x20, "HID UnkInput2 header structure has incorrect size"); - -struct UnkInput2 { -    UnkInput2Header header; -    std::array<u8, 0x1E0> padding; -}; -static_assert(sizeof(UnkInput2) == 0x200, "HID UnkInput2 structure has incorrect size"); - -// End UnkInput2 - -// Begin Controller - -struct ControllerMAC { -    u64 timestamp; -    std::array<u8, 0x8> mac; -    u64 unk; -    u64 timestamp_2; -}; -static_assert(sizeof(ControllerMAC) == 0x20, "HID controller MAC structure has incorrect size"); - -struct ControllerHeader { -    u32 type; -    u32 is_half; -    u32 single_colors_descriptor; -    u32 single_color_body; -    u32 single_color_buttons; -    u32 split_colors_descriptor; -    u32 left_color_body; -    u32 left_color_buttons; -    u32 right_color_body; -    u32 right_color_buttons; -}; -static_assert(sizeof(ControllerHeader) == 0x28, -              "HID controller header structure has incorrect size"); - -struct ControllerLayoutHeader { -    u64 timestamp_ticks; -    u64 num_entries; -    u64 latest_entry; -    u64 max_entry_index; -}; -static_assert(sizeof(ControllerLayoutHeader) == 0x20, -              "HID controller layout header structure has incorrect size"); - -struct ControllerPadState { -    union { -        u64 hex{}; - -        // Buttons -        BitField<0, 1, u64> a; -        BitField<1, 1, u64> b; -        BitField<2, 1, u64> x; -        BitField<3, 1, u64> y; -        BitField<4, 1, u64> lstick; -        BitField<5, 1, u64> rstick; -        BitField<6, 1, u64> l; -        BitField<7, 1, u64> r; -        BitField<8, 1, u64> zl; -        BitField<9, 1, u64> zr; -        BitField<10, 1, u64> plus; -        BitField<11, 1, u64> minus; - -        // D-pad buttons -        BitField<12, 1, u64> dleft; -        BitField<13, 1, u64> dup; -        BitField<14, 1, u64> dright; -        BitField<15, 1, u64> ddown; - -        // Left stick directions -        BitField<16, 1, u64> lstick_left; -        BitField<17, 1, u64> lstick_up; -        BitField<18, 1, u64> lstick_right; -        BitField<19, 1, u64> lstick_down; - -        // Right stick directions -        BitField<20, 1, u64> rstick_left; -        BitField<21, 1, u64> rstick_up; -        BitField<22, 1, u64> rstick_right; -        BitField<23, 1, u64> rstick_down; - -        BitField<24, 1, u64> sl; -        BitField<25, 1, u64> sr; -    }; -}; - -struct ControllerInputEntry { -    u64 timestamp; -    u64 timestamp_2; -    ControllerPadState buttons; -    s32 joystick_left_x; -    s32 joystick_left_y; -    s32 joystick_right_x; -    s32 joystick_right_y; -    u64 connection_state; -}; -static_assert(sizeof(ControllerInputEntry) == 0x30, -              "HID controller input entry structure has incorrect size"); - -struct ControllerLayout { -    ControllerLayoutHeader header; -    std::array<ControllerInputEntry, 17> entries; -}; -static_assert(sizeof(ControllerLayout) == 0x350, -              "HID controller layout structure has incorrect size"); - -struct Controller { -    ControllerHeader header; -    std::array<ControllerLayout, HID_NUM_LAYOUTS> layouts; -    std::array<u8, 0x2a70> unk_1; -    ControllerMAC mac_left; -    ControllerMAC mac_right; -    std::array<u8, 0xdf8> unk_2; -}; -static_assert(sizeof(Controller) == 0x5000, "HID controller structure has incorrect size"); - -// End Controller - -struct SharedMemory { -    UnkInput3 unk_input_3; -    TouchScreen touchscreen; -    Mouse mouse; -    Keyboard keyboard; -    std::array<UnkInput1, 4> unk_input_1; -    std::array<UnkInput2, 3> unk_input_2; -    std::array<u8, 0x800> unk_section_8; -    std::array<u8, 0x4000> controller_serials; -    std::array<Controller, 10> controllers; -    std::array<u8, 0x4600> unk_section_9; -}; -static_assert(sizeof(SharedMemory) == 0x40000, "HID Shared Memory structure has incorrect size"); -  /// Reload input devices. Used when input configuration changed  void ReloadInputDevices(); diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index 8c07a05c2..39c0c1e63 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp @@ -144,7 +144,7 @@ private:      }      const u64 device_handle{0xDEAD}; -    const HID::ControllerID npad_id{HID::Controller_Player1}; +    const u32 npad_id{0}; // This is the first player controller id      State state{State::NonInitialized};      DeviceState device_state{DeviceState::Initialized};      Kernel::SharedPtr<Kernel::Event> activate_event; | 
