diff options
Diffstat (limited to 'src')
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 | |||
| 236 | hle/service/hid/irs.h | 236 | hle/service/hid/irs.h |
| 237 | hle/service/hid/xcd.cpp | 237 | hle/service/hid/xcd.cpp |
| 238 | hle/service/hid/xcd.h | 238 | hle/service/hid/xcd.h |
| 239 | hle/service/hid/controllers/controller_base.cpp | ||
| 240 | hle/service/hid/controllers/controller_base.h | ||
| 241 | hle/service/hid/controllers/debug_pad.cpp | ||
| 242 | hle/service/hid/controllers/debug_pad.h | ||
| 243 | hle/service/hid/controllers/gesture.cpp | ||
| 244 | hle/service/hid/controllers/gesture.h | ||
| 245 | hle/service/hid/controllers/keyboard.cpp | ||
| 246 | hle/service/hid/controllers/keyboard.h | ||
| 247 | hle/service/hid/controllers/mouse.cpp | ||
| 248 | hle/service/hid/controllers/mouse.h | ||
| 249 | hle/service/hid/controllers/npad.cpp | ||
| 250 | hle/service/hid/controllers/npad.h | ||
| 251 | hle/service/hid/controllers/stubbed.cpp | ||
| 252 | hle/service/hid/controllers/stubbed.h | ||
| 253 | hle/service/hid/controllers/touchscreen.cpp | ||
| 254 | hle/service/hid/controllers/touchscreen.h | ||
| 255 | hle/service/hid/controllers/xpad.cpp | ||
| 256 | hle/service/hid/controllers/xpad.h | ||
| 239 | hle/service/lbl/lbl.cpp | 257 | hle/service/lbl/lbl.cpp |
| 240 | hle/service/lbl/lbl.h | 258 | hle/service/lbl/lbl.h |
| 241 | hle/service/ldn/ldn.cpp | 259 | 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 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/hid/controllers/controller_base.h" | ||
| 6 | |||
| 7 | namespace Service::HID { | ||
| 8 | ControllerBase::~ControllerBase() = default; | ||
| 9 | |||
| 10 | void ControllerBase::ActivateController() { | ||
| 11 | if (is_activated) { | ||
| 12 | OnRelease(); | ||
| 13 | } | ||
| 14 | is_activated = true; | ||
| 15 | OnInit(); | ||
| 16 | } | ||
| 17 | |||
| 18 | void ControllerBase::DeactivateController() { | ||
| 19 | if (is_activated) { | ||
| 20 | OnRelease(); | ||
| 21 | } | ||
| 22 | is_activated = false; | ||
| 23 | } | ||
| 24 | |||
| 25 | bool ControllerBase::IsControllerActivated() const { | ||
| 26 | return is_activated; | ||
| 27 | } | ||
| 28 | } // 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 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/swap.h" | ||
| 9 | |||
| 10 | namespace Service::HID { | ||
| 11 | class ControllerBase { | ||
| 12 | public: | ||
| 13 | ControllerBase() = default; | ||
| 14 | virtual ~ControllerBase() = 0; | ||
| 15 | |||
| 16 | // Called when the controller is initialized | ||
| 17 | virtual void OnInit() = 0; | ||
| 18 | |||
| 19 | // When the controller is released | ||
| 20 | virtual void OnRelease() = 0; | ||
| 21 | |||
| 22 | // When the controller is requesting an update for the shared memory | ||
| 23 | virtual void OnUpdate(u8* data, std::size_t size) = 0; | ||
| 24 | |||
| 25 | // Called when input devices should be loaded | ||
| 26 | virtual void OnLoadInputDevices() = 0; | ||
| 27 | |||
| 28 | void ActivateController(); | ||
| 29 | |||
| 30 | void DeactivateController(); | ||
| 31 | |||
| 32 | bool IsControllerActivated() const; | ||
| 33 | |||
| 34 | protected: | ||
| 35 | bool is_activated{false}; | ||
| 36 | |||
| 37 | struct CommonHeader { | ||
| 38 | s64_le timestamp; | ||
| 39 | s64_le total_entry_count; | ||
| 40 | s64_le last_entry_index; | ||
| 41 | s64_le entry_count; | ||
| 42 | }; | ||
| 43 | static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); | ||
| 44 | }; | ||
| 45 | } // 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 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cstring> | ||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "common/swap.h" | ||
| 8 | #include "core/core_timing.h" | ||
| 9 | #include "core/hle/service/hid/controllers/debug_pad.h" | ||
| 10 | |||
| 11 | namespace Service::HID { | ||
| 12 | |||
| 13 | Controller_DebugPad::Controller_DebugPad() = default; | ||
| 14 | |||
| 15 | void Controller_DebugPad::OnInit() {} | ||
| 16 | |||
| 17 | void Controller_DebugPad::OnRelease() {} | ||
| 18 | |||
| 19 | void Controller_DebugPad::OnUpdate(u8* data, std::size_t size) { | ||
| 20 | shared_memory.header.timestamp = CoreTiming::GetTicks(); | ||
| 21 | shared_memory.header.total_entry_count = 17; | ||
| 22 | |||
| 23 | if (!IsControllerActivated()) { | ||
| 24 | shared_memory.header.entry_count = 0; | ||
| 25 | shared_memory.header.last_entry_index = 0; | ||
| 26 | return; | ||
| 27 | } | ||
| 28 | shared_memory.header.entry_count = 16; | ||
| 29 | |||
| 30 | const auto& last_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; | ||
| 31 | shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; | ||
| 32 | auto& cur_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; | ||
| 33 | |||
| 34 | cur_entry.sampling_number = last_entry.sampling_number + 1; | ||
| 35 | cur_entry.sampling_number2 = cur_entry.sampling_number; | ||
| 36 | // TODO(ogniK): Update debug pad states | ||
| 37 | |||
| 38 | std::memcpy(data, &shared_memory, sizeof(SharedMemory)); | ||
| 39 | } | ||
| 40 | |||
| 41 | void Controller_DebugPad::OnLoadInputDevices() {} | ||
| 42 | } // 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 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include "common/common_funcs.h" | ||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "common/swap.h" | ||
| 11 | #include "core/hle/service/hid/controllers/controller_base.h" | ||
| 12 | |||
| 13 | namespace Service::HID { | ||
| 14 | class Controller_DebugPad final : public ControllerBase { | ||
| 15 | public: | ||
| 16 | Controller_DebugPad(); | ||
| 17 | |||
| 18 | // Called when the controller is initialized | ||
| 19 | void OnInit() override; | ||
| 20 | |||
| 21 | // When the controller is released | ||
| 22 | void OnRelease() override; | ||
| 23 | |||
| 24 | // When the controller is requesting an update for the shared memory | ||
| 25 | void OnUpdate(u8* data, std::size_t size) override; | ||
| 26 | |||
| 27 | // Called when input devices should be loaded | ||
| 28 | void OnLoadInputDevices() override; | ||
| 29 | |||
| 30 | private: | ||
| 31 | struct AnalogStick { | ||
| 32 | s32_le x; | ||
| 33 | s32_le y; | ||
| 34 | }; | ||
| 35 | static_assert(sizeof(AnalogStick) == 0x8); | ||
| 36 | |||
| 37 | struct PadStates { | ||
| 38 | s64_le sampling_number; | ||
| 39 | s64_le sampling_number2; | ||
| 40 | u32_le attribute; | ||
| 41 | u32_le button_state; | ||
| 42 | AnalogStick r_stick; | ||
| 43 | AnalogStick l_stick; | ||
| 44 | }; | ||
| 45 | static_assert(sizeof(PadStates) == 0x28, "PadStates is an invalid state"); | ||
| 46 | |||
| 47 | struct SharedMemory { | ||
| 48 | CommonHeader header; | ||
| 49 | std::array<PadStates, 17> pad_states; | ||
| 50 | INSERT_PADDING_BYTES(0x138); | ||
| 51 | }; | ||
| 52 | static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size"); | ||
| 53 | SharedMemory shared_memory{}; | ||
| 54 | }; | ||
| 55 | } // 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 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cstring> | ||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "common/swap.h" | ||
| 8 | #include "core/core_timing.h" | ||
| 9 | #include "core/hle/service/hid/controllers/gesture.h" | ||
| 10 | |||
| 11 | namespace Service::HID { | ||
| 12 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00; | ||
| 13 | |||
| 14 | Controller_Gesture::Controller_Gesture() = default; | ||
| 15 | |||
| 16 | void Controller_Gesture::OnInit() {} | ||
| 17 | |||
| 18 | void Controller_Gesture::OnRelease() {} | ||
| 19 | |||
| 20 | void Controller_Gesture::OnUpdate(u8* data, std::size_t size) { | ||
| 21 | shared_memory.header.timestamp = CoreTiming::GetTicks(); | ||
| 22 | shared_memory.header.total_entry_count = 17; | ||
| 23 | |||
| 24 | if (!IsControllerActivated()) { | ||
| 25 | shared_memory.header.entry_count = 0; | ||
| 26 | shared_memory.header.last_entry_index = 0; | ||
| 27 | return; | ||
| 28 | } | ||
| 29 | shared_memory.header.entry_count = 16; | ||
| 30 | |||
| 31 | const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; | ||
| 32 | shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; | ||
| 33 | auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; | ||
| 34 | |||
| 35 | cur_entry.sampling_number = last_entry.sampling_number + 1; | ||
| 36 | cur_entry.sampling_number2 = cur_entry.sampling_number; | ||
| 37 | // TODO(ogniK): Update gesture states | ||
| 38 | |||
| 39 | std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); | ||
| 40 | } | ||
| 41 | |||
| 42 | void Controller_Gesture::OnLoadInputDevices() {} | ||
| 43 | } // 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 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "common/swap.h" | ||
| 10 | #include "core/hle/service/hid/controllers/controller_base.h" | ||
| 11 | |||
| 12 | namespace Service::HID { | ||
| 13 | class Controller_Gesture final : public ControllerBase { | ||
| 14 | public: | ||
| 15 | Controller_Gesture(); | ||
| 16 | |||
| 17 | // Called when the controller is initialized | ||
| 18 | void OnInit() override; | ||
| 19 | |||
| 20 | // When the controller is released | ||
| 21 | void OnRelease() override; | ||
| 22 | |||
| 23 | // When the controller is requesting an update for the shared memory | ||
| 24 | void OnUpdate(u8* data, size_t size) override; | ||
| 25 | |||
| 26 | // Called when input devices should be loaded | ||
| 27 | void OnLoadInputDevices() override; | ||
| 28 | |||
| 29 | private: | ||
| 30 | struct Locations { | ||
| 31 | s32_le x; | ||
| 32 | s32_le y; | ||
| 33 | }; | ||
| 34 | |||
| 35 | struct GestureState { | ||
| 36 | s64_le sampling_number; | ||
| 37 | s64_le sampling_number2; | ||
| 38 | |||
| 39 | s64_le detection_count; | ||
| 40 | s32_le type; | ||
| 41 | s32_le dir; | ||
| 42 | s32_le x; | ||
| 43 | s32_le y; | ||
| 44 | s32_le delta_x; | ||
| 45 | s32_le delta_y; | ||
| 46 | f32 vel_x; | ||
| 47 | f32 vel_y; | ||
| 48 | s32_le attributes; | ||
| 49 | f32 scale; | ||
| 50 | f32 rotation; | ||
| 51 | s32_le location_count; | ||
| 52 | std::array<Locations, 4> locations; | ||
| 53 | }; | ||
| 54 | static_assert(sizeof(GestureState) == 0x68, "GestureState is an invalid size"); | ||
| 55 | |||
| 56 | struct SharedMemory { | ||
| 57 | CommonHeader header; | ||
| 58 | std::array<GestureState, 17> gesture_states; | ||
| 59 | }; | ||
| 60 | SharedMemory shared_memory{}; | ||
| 61 | }; | ||
| 62 | } // 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 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cstring> | ||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "common/swap.h" | ||
| 8 | #include "core/core_timing.h" | ||
| 9 | #include "core/hle/service/hid/controllers/keyboard.h" | ||
| 10 | |||
| 11 | namespace Service::HID { | ||
| 12 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; | ||
| 13 | |||
| 14 | Controller_Keyboard::Controller_Keyboard() = default; | ||
| 15 | |||
| 16 | void Controller_Keyboard::OnInit() {} | ||
| 17 | |||
| 18 | void Controller_Keyboard::OnRelease() {} | ||
| 19 | |||
| 20 | void Controller_Keyboard::OnUpdate(u8* data, std::size_t size) { | ||
| 21 | shared_memory.header.timestamp = CoreTiming::GetTicks(); | ||
| 22 | shared_memory.header.total_entry_count = 17; | ||
| 23 | |||
| 24 | if (!IsControllerActivated()) { | ||
| 25 | shared_memory.header.entry_count = 0; | ||
| 26 | shared_memory.header.last_entry_index = 0; | ||
| 27 | return; | ||
| 28 | } | ||
| 29 | shared_memory.header.entry_count = 16; | ||
| 30 | |||
| 31 | const auto& last_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; | ||
| 32 | shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; | ||
| 33 | auto& cur_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; | ||
| 34 | |||
| 35 | cur_entry.sampling_number = last_entry.sampling_number + 1; | ||
| 36 | cur_entry.sampling_number2 = cur_entry.sampling_number; | ||
| 37 | // TODO(ogniK): Update keyboard states | ||
| 38 | |||
| 39 | std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); | ||
| 40 | } | ||
| 41 | |||
| 42 | void Controller_Keyboard::OnLoadInputDevices() {} | ||
| 43 | } // 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 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include "common/common_funcs.h" | ||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "common/swap.h" | ||
| 11 | #include "core/hle/service/hid/controllers/controller_base.h" | ||
| 12 | |||
| 13 | namespace Service::HID { | ||
| 14 | class Controller_Keyboard final : public ControllerBase { | ||
| 15 | public: | ||
| 16 | Controller_Keyboard(); | ||
| 17 | |||
| 18 | // Called when the controller is initialized | ||
| 19 | void OnInit() override; | ||
| 20 | |||
| 21 | // When the controller is released | ||
| 22 | void OnRelease() override; | ||
| 23 | |||
| 24 | // When the controller is requesting an update for the shared memory | ||
| 25 | void OnUpdate(u8* data, std::size_t size) override; | ||
| 26 | |||
| 27 | // Called when input devices should be loaded | ||
| 28 | void OnLoadInputDevices() override; | ||
| 29 | |||
| 30 | private: | ||
| 31 | struct KeyboardState { | ||
| 32 | s64_le sampling_number; | ||
| 33 | s64_le sampling_number2; | ||
| 34 | |||
| 35 | s32_le modifier; | ||
| 36 | s32_le attribute; | ||
| 37 | std::array<u8, 32> key; | ||
| 38 | }; | ||
| 39 | static_assert(sizeof(KeyboardState) == 0x38, "KeyboardState is an invalid size"); | ||
| 40 | |||
| 41 | struct SharedMemory { | ||
| 42 | CommonHeader header; | ||
| 43 | std::array<KeyboardState, 17> pad_states; | ||
| 44 | INSERT_PADDING_BYTES(0x28); | ||
| 45 | }; | ||
| 46 | static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size"); | ||
| 47 | SharedMemory shared_memory{}; | ||
| 48 | }; | ||
| 49 | } // 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 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cstring> | ||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "common/swap.h" | ||
| 8 | #include "core/core_timing.h" | ||
| 9 | #include "core/hle/service/hid/controllers/mouse.h" | ||
| 10 | |||
| 11 | namespace Service::HID { | ||
| 12 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400; | ||
| 13 | |||
| 14 | Controller_Mouse::Controller_Mouse() = default; | ||
| 15 | |||
| 16 | void Controller_Mouse::OnInit() {} | ||
| 17 | |||
| 18 | void Controller_Mouse::OnRelease() {} | ||
| 19 | |||
| 20 | void Controller_Mouse::OnUpdate(u8* data, std::size_t size) { | ||
| 21 | shared_memory.header.timestamp = CoreTiming::GetTicks(); | ||
| 22 | shared_memory.header.total_entry_count = 17; | ||
| 23 | |||
| 24 | if (!IsControllerActivated()) { | ||
| 25 | shared_memory.header.entry_count = 0; | ||
| 26 | shared_memory.header.last_entry_index = 0; | ||
| 27 | return; | ||
| 28 | } | ||
| 29 | shared_memory.header.entry_count = 16; | ||
| 30 | |||
| 31 | auto& last_entry = shared_memory.mouse_states[shared_memory.header.last_entry_index]; | ||
| 32 | shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; | ||
| 33 | auto& cur_entry = shared_memory.mouse_states[shared_memory.header.last_entry_index]; | ||
| 34 | |||
| 35 | cur_entry.sampling_number = last_entry.sampling_number + 1; | ||
| 36 | cur_entry.sampling_number2 = cur_entry.sampling_number; | ||
| 37 | // TODO(ogniK): Update mouse states | ||
| 38 | |||
| 39 | std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); | ||
| 40 | } | ||
| 41 | |||
| 42 | void Controller_Mouse::OnLoadInputDevices() {} | ||
| 43 | } // 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 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "common/swap.h" | ||
| 10 | #include "core/hle/service/hid/controllers/controller_base.h" | ||
| 11 | |||
| 12 | namespace Service::HID { | ||
| 13 | class Controller_Mouse final : public ControllerBase { | ||
| 14 | public: | ||
| 15 | Controller_Mouse(); | ||
| 16 | |||
| 17 | // Called when the controller is initialized | ||
| 18 | void OnInit() override; | ||
| 19 | |||
| 20 | // When the controller is released | ||
| 21 | void OnRelease() override; | ||
| 22 | |||
| 23 | // When the controller is requesting an update for the shared memory | ||
| 24 | void OnUpdate(u8* data, std::size_t size) override; | ||
| 25 | |||
| 26 | // Called when input devices should be loaded | ||
| 27 | void OnLoadInputDevices() override; | ||
| 28 | |||
| 29 | private: | ||
| 30 | struct MouseState { | ||
| 31 | s64_le sampling_number; | ||
| 32 | s64_le sampling_number2; | ||
| 33 | s32_le x; | ||
| 34 | s32_le y; | ||
| 35 | s32_le delta_x; | ||
| 36 | s32_le delta_y; | ||
| 37 | s32_le mouse_wheel; | ||
| 38 | s32_le button; | ||
| 39 | s32_le attribute; | ||
| 40 | }; | ||
| 41 | static_assert(sizeof(MouseState) == 0x30, "MouseState is an invalid size"); | ||
| 42 | |||
| 43 | struct SharedMemory { | ||
| 44 | CommonHeader header; | ||
| 45 | std::array<MouseState, 17> mouse_states; | ||
| 46 | }; | ||
| 47 | SharedMemory shared_memory{}; | ||
| 48 | }; | ||
| 49 | } // 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 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <algorithm> | ||
| 8 | #include <array> | ||
| 9 | #include <cstring> | ||
| 10 | #include "common/assert.h" | ||
| 11 | #include "common/bit_field.h" | ||
| 12 | #include "common/common_types.h" | ||
| 13 | #include "common/logging/log.h" | ||
| 14 | #include "common/swap.h" | ||
| 15 | #include "core/core.h" | ||
| 16 | #include "core/core_timing.h" | ||
| 17 | #include "core/frontend/input.h" | ||
| 18 | #include "core/hle/kernel/event.h" | ||
| 19 | #include "core/hle/service/hid/controllers/npad.h" | ||
| 20 | #include "core/settings.h" | ||
| 21 | |||
| 22 | namespace Service::HID { | ||
| 23 | constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28; | ||
| 24 | constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A; | ||
| 25 | constexpr u32 JOYCON_BODY_NEON_BLUE = 0x0AB9E6; | ||
| 26 | constexpr u32 JOYCON_BUTTONS_NEON_BLUE = 0x001E1E; | ||
| 27 | constexpr s32 HID_JOYSTICK_MAX = 0x7fff; | ||
| 28 | constexpr s32 HID_JOYSTICK_MIN = -0x7fff; | ||
| 29 | constexpr std::size_t NPAD_OFFSET = 0x9A00; | ||
| 30 | constexpr u32 BATTERY_FULL = 2; | ||
| 31 | enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right }; | ||
| 32 | |||
| 33 | Controller_NPad::Controller_NPad() = default; | ||
| 34 | |||
| 35 | void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) { | ||
| 36 | const auto controller_type = connected_controllers[controller_idx].type; | ||
| 37 | auto& controller = shared_memory_entries[controller_idx]; | ||
| 38 | if (controller_type == NPadControllerType::None) { | ||
| 39 | return; | ||
| 40 | } | ||
| 41 | controller.joy_styles.raw = 0; // Zero out | ||
| 42 | controller.device_type.raw = 0; | ||
| 43 | switch (controller_type) { | ||
| 44 | case NPadControllerType::Handheld: | ||
| 45 | controller.joy_styles.handheld.Assign(1); | ||
| 46 | controller.device_type.handheld.Assign(1); | ||
| 47 | controller.pad_assignment = NPadAssignments::Dual; | ||
| 48 | break; | ||
| 49 | case NPadControllerType::JoyDual: | ||
| 50 | controller.joy_styles.joycon_dual.Assign(1); | ||
| 51 | controller.device_type.joycon_left.Assign(1); | ||
| 52 | controller.device_type.joycon_right.Assign(1); | ||
| 53 | controller.pad_assignment = NPadAssignments::Dual; | ||
| 54 | break; | ||
| 55 | case NPadControllerType::JoyLeft: | ||
| 56 | controller.joy_styles.joycon_left.Assign(1); | ||
| 57 | controller.device_type.joycon_left.Assign(1); | ||
| 58 | controller.pad_assignment = NPadAssignments::Dual; | ||
| 59 | break; | ||
| 60 | case NPadControllerType::JoyRight: | ||
| 61 | controller.joy_styles.joycon_right.Assign(1); | ||
| 62 | controller.device_type.joycon_right.Assign(1); | ||
| 63 | controller.pad_assignment = NPadAssignments::Dual; | ||
| 64 | break; | ||
| 65 | case NPadControllerType::Pokeball: | ||
| 66 | controller.joy_styles.pokeball.Assign(1); | ||
| 67 | controller.device_type.pokeball.Assign(1); | ||
| 68 | controller.pad_assignment = NPadAssignments::Single; | ||
| 69 | break; | ||
| 70 | case NPadControllerType::ProController: | ||
| 71 | controller.joy_styles.pro_controller.Assign(1); | ||
| 72 | controller.device_type.pro_controller.Assign(1); | ||
| 73 | controller.pad_assignment = NPadAssignments::Single; | ||
| 74 | break; | ||
| 75 | } | ||
| 76 | |||
| 77 | controller.single_color_error = ColorReadError::ReadOk; | ||
| 78 | controller.single_color.body_color = 0; | ||
| 79 | controller.single_color.button_color = 0; | ||
| 80 | |||
| 81 | controller.dual_color_error = ColorReadError::ReadOk; | ||
| 82 | controller.left_color.body_color = JOYCON_BODY_NEON_BLUE; | ||
| 83 | controller.left_color.button_color = JOYCON_BUTTONS_NEON_BLUE; | ||
| 84 | controller.right_color.body_color = JOYCON_BODY_NEON_RED; | ||
| 85 | controller.right_color.button_color = JOYCON_BUTTONS_NEON_RED; | ||
| 86 | |||
| 87 | controller.properties.is_vertical.Assign(1); // TODO(ogniK): Swap joycons orientations | ||
| 88 | controller.properties.use_plus.Assign(1); | ||
| 89 | controller.properties.use_minus.Assign(1); | ||
| 90 | controller.battery_level[0] = BATTERY_FULL; | ||
| 91 | controller.battery_level[1] = BATTERY_FULL; | ||
| 92 | controller.battery_level[2] = BATTERY_FULL; | ||
| 93 | } | ||
| 94 | |||
| 95 | void Controller_NPad::OnInit() { | ||
| 96 | auto& kernel = Core::System::GetInstance().Kernel(); | ||
| 97 | styleset_changed_event = | ||
| 98 | Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "npad:NpadStyleSetChanged"); | ||
| 99 | |||
| 100 | if (!IsControllerActivated()) | ||
| 101 | return; | ||
| 102 | std::size_t controller{}; | ||
| 103 | if (style.raw == 0) { | ||
| 104 | // We want to support all controllers | ||
| 105 | style.handheld.Assign(1); | ||
| 106 | style.joycon_left.Assign(1); | ||
| 107 | style.joycon_right.Assign(1); | ||
| 108 | style.joycon_dual.Assign(1); | ||
| 109 | style.pro_controller.Assign(1); | ||
| 110 | style.pokeball.Assign(1); | ||
| 111 | } | ||
| 112 | if (std::none_of(connected_controllers.begin(), connected_controllers.end(), | ||
| 113 | [](const ControllerHolder& controller) { return controller.is_connected; })) { | ||
| 114 | supported_npad_id_types.resize(npad_id_list.size()); | ||
| 115 | std::memcpy(supported_npad_id_types.data(), npad_id_list.data(), | ||
| 116 | npad_id_list.size() * sizeof(u32)); | ||
| 117 | AddNewController(NPadControllerType::JoyDual); | ||
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 121 | void Controller_NPad::OnLoadInputDevices() { | ||
| 122 | std::transform(Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, | ||
| 123 | Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_END, | ||
| 124 | buttons.begin(), Input::CreateDevice<Input::ButtonDevice>); | ||
| 125 | std::transform(Settings::values.analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, | ||
| 126 | Settings::values.analogs.begin() + Settings::NativeAnalog::STICK_HID_END, | ||
| 127 | sticks.begin(), Input::CreateDevice<Input::AnalogDevice>); | ||
| 128 | } | ||
| 129 | |||
| 130 | void Controller_NPad::OnRelease() {} | ||
| 131 | |||
| 132 | void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) { | ||
| 133 | if (!IsControllerActivated()) | ||
| 134 | return; | ||
| 135 | for (std::size_t i = 0; i < shared_memory_entries.size(); i++) { | ||
| 136 | auto& npad = shared_memory_entries[i]; | ||
| 137 | const std::array<NPadGeneric*, 7> controller_npads{&npad.main_controller_states, | ||
| 138 | &npad.handheld_states, | ||
| 139 | &npad.dual_states, | ||
| 140 | &npad.left_joy_states, | ||
| 141 | &npad.right_joy_states, | ||
| 142 | &npad.pokeball_states, | ||
| 143 | &npad.libnx}; | ||
| 144 | |||
| 145 | for (auto* main_controller : controller_npads) { | ||
| 146 | main_controller->common.entry_count = 16; | ||
| 147 | main_controller->common.total_entry_count = 17; | ||
| 148 | |||
| 149 | const auto& last_entry = | ||
| 150 | main_controller->npad[main_controller->common.last_entry_index]; | ||
| 151 | |||
| 152 | main_controller->common.timestamp = CoreTiming::GetTicks(); | ||
| 153 | main_controller->common.last_entry_index = | ||
| 154 | (main_controller->common.last_entry_index + 1) % 17; | ||
| 155 | |||
| 156 | auto& cur_entry = main_controller->npad[main_controller->common.last_entry_index]; | ||
| 157 | |||
| 158 | cur_entry.timestamp = last_entry.timestamp + 1; | ||
| 159 | cur_entry.timestamp2 = cur_entry.timestamp; | ||
| 160 | } | ||
| 161 | |||
| 162 | const auto& controller_type = connected_controllers[i].type; | ||
| 163 | |||
| 164 | if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) { | ||
| 165 | continue; | ||
| 166 | } | ||
| 167 | |||
| 168 | // Pad states | ||
| 169 | ControllerPadState pad_state{}; | ||
| 170 | using namespace Settings::NativeButton; | ||
| 171 | pad_state.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 172 | pad_state.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 173 | pad_state.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 174 | pad_state.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 175 | pad_state.l_stick.Assign(buttons[LStick - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 176 | pad_state.r_stick.Assign(buttons[RStick - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 177 | pad_state.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 178 | pad_state.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 179 | pad_state.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 180 | pad_state.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 181 | pad_state.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 182 | pad_state.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 183 | |||
| 184 | pad_state.d_left.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 185 | pad_state.d_up.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 186 | pad_state.d_right.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 187 | pad_state.d_down.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 188 | |||
| 189 | pad_state.l_stick_left.Assign(buttons[LStick_Left - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 190 | pad_state.l_stick_up.Assign(buttons[LStick_Up - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 191 | pad_state.l_stick_right.Assign(buttons[LStick_Right - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 192 | pad_state.l_stick_down.Assign(buttons[LStick_Down - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 193 | |||
| 194 | pad_state.r_stick_left.Assign(buttons[RStick_Left - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 195 | pad_state.r_stick_up.Assign(buttons[RStick_Up - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 196 | pad_state.r_stick_right.Assign(buttons[RStick_Right - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 197 | pad_state.r_stick_down.Assign(buttons[RStick_Down - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 198 | |||
| 199 | pad_state.sl.Assign(buttons[SL - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 200 | pad_state.sr.Assign(buttons[SR - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 201 | |||
| 202 | AnalogPosition lstick_entry{}; | ||
| 203 | AnalogPosition rstick_entry{}; | ||
| 204 | |||
| 205 | const auto [stick_l_x_f, stick_l_y_f] = | ||
| 206 | sticks[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus(); | ||
| 207 | const auto [stick_r_x_f, stick_r_y_f] = | ||
| 208 | sticks[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus(); | ||
| 209 | lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX); | ||
| 210 | lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX); | ||
| 211 | rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX); | ||
| 212 | rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX); | ||
| 213 | |||
| 214 | auto& main_controller = | ||
| 215 | npad.main_controller_states.npad[npad.main_controller_states.common.last_entry_index]; | ||
| 216 | auto& handheld_entry = | ||
| 217 | npad.handheld_states.npad[npad.handheld_states.common.last_entry_index]; | ||
| 218 | auto& dual_entry = npad.dual_states.npad[npad.dual_states.common.last_entry_index]; | ||
| 219 | auto& left_entry = npad.left_joy_states.npad[npad.left_joy_states.common.last_entry_index]; | ||
| 220 | auto& right_entry = | ||
| 221 | npad.right_joy_states.npad[npad.right_joy_states.common.last_entry_index]; | ||
| 222 | auto& pokeball_entry = | ||
| 223 | npad.pokeball_states.npad[npad.pokeball_states.common.last_entry_index]; | ||
| 224 | auto& libnx_entry = npad.libnx.npad[npad.libnx.common.last_entry_index]; | ||
| 225 | |||
| 226 | if (hold_type == NpadHoldType::Horizontal) { | ||
| 227 | // TODO(ogniK): Remap buttons for different orientations | ||
| 228 | } | ||
| 229 | libnx_entry.connection_status.raw = 0; | ||
| 230 | |||
| 231 | switch (controller_type) { | ||
| 232 | case NPadControllerType::Handheld: | ||
| 233 | handheld_entry.connection_status.raw = 0; | ||
| 234 | handheld_entry.connection_status.IsConnected.Assign(1); | ||
| 235 | if (!Settings::values.use_docked_mode) { | ||
| 236 | handheld_entry.connection_status.IsWired.Assign(1); | ||
| 237 | } | ||
| 238 | handheld_entry.pad_states.raw = pad_state.raw; | ||
| 239 | handheld_entry.l_stick = lstick_entry; | ||
| 240 | handheld_entry.r_stick = rstick_entry; | ||
| 241 | break; | ||
| 242 | case NPadControllerType::JoyDual: | ||
| 243 | dual_entry.connection_status.raw = 0; | ||
| 244 | |||
| 245 | dual_entry.connection_status.IsLeftJoyConnected.Assign(1); | ||
| 246 | dual_entry.connection_status.IsRightJoyConnected.Assign(1); | ||
| 247 | dual_entry.connection_status.IsConnected.Assign(1); | ||
| 248 | |||
| 249 | libnx_entry.connection_status.IsLeftJoyConnected.Assign(1); | ||
| 250 | libnx_entry.connection_status.IsRightJoyConnected.Assign(1); | ||
| 251 | libnx_entry.connection_status.IsConnected.Assign(1); | ||
| 252 | |||
| 253 | dual_entry.pad_states.raw = pad_state.raw; | ||
| 254 | dual_entry.l_stick = lstick_entry; | ||
| 255 | dual_entry.r_stick = rstick_entry; | ||
| 256 | case NPadControllerType::JoyLeft: | ||
| 257 | left_entry.connection_status.raw = 0; | ||
| 258 | |||
| 259 | left_entry.connection_status.IsConnected.Assign(1); | ||
| 260 | left_entry.pad_states.raw = pad_state.raw; | ||
| 261 | left_entry.l_stick = lstick_entry; | ||
| 262 | left_entry.r_stick = rstick_entry; | ||
| 263 | break; | ||
| 264 | case NPadControllerType::JoyRight: | ||
| 265 | right_entry.connection_status.raw = 0; | ||
| 266 | |||
| 267 | right_entry.connection_status.IsConnected.Assign(1); | ||
| 268 | right_entry.pad_states.raw = pad_state.raw; | ||
| 269 | right_entry.l_stick = lstick_entry; | ||
| 270 | right_entry.r_stick = rstick_entry; | ||
| 271 | break; | ||
| 272 | case NPadControllerType::Pokeball: | ||
| 273 | pokeball_entry.connection_status.raw = 0; | ||
| 274 | |||
| 275 | pokeball_entry.connection_status.IsConnected.Assign(1); | ||
| 276 | pokeball_entry.connection_status.IsWired.Assign(1); | ||
| 277 | |||
| 278 | pokeball_entry.pad_states.raw = pad_state.raw; | ||
| 279 | pokeball_entry.l_stick = lstick_entry; | ||
| 280 | pokeball_entry.r_stick = rstick_entry; | ||
| 281 | break; | ||
| 282 | case NPadControllerType::ProController: | ||
| 283 | main_controller.connection_status.raw = 0; | ||
| 284 | |||
| 285 | main_controller.connection_status.IsConnected.Assign(1); | ||
| 286 | main_controller.connection_status.IsWired.Assign(1); | ||
| 287 | main_controller.pad_states.raw = pad_state.raw; | ||
| 288 | main_controller.l_stick = lstick_entry; | ||
| 289 | main_controller.r_stick = rstick_entry; | ||
| 290 | break; | ||
| 291 | } | ||
| 292 | |||
| 293 | // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate | ||
| 294 | // any controllers. | ||
| 295 | libnx_entry.pad_states.raw = pad_state.raw; | ||
| 296 | libnx_entry.l_stick = lstick_entry; | ||
| 297 | libnx_entry.r_stick = rstick_entry; | ||
| 298 | } | ||
| 299 | std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(), | ||
| 300 | shared_memory_entries.size() * sizeof(NPadEntry)); | ||
| 301 | } // namespace Service::HID | ||
| 302 | |||
| 303 | void Controller_NPad::SetSupportedStyleSet(NPadType style_set) { | ||
| 304 | style.raw = style_set.raw; | ||
| 305 | } | ||
| 306 | |||
| 307 | Controller_NPad::NPadType Controller_NPad::GetSupportedStyleSet() const { | ||
| 308 | return style; | ||
| 309 | } | ||
| 310 | |||
| 311 | void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) { | ||
| 312 | ASSERT(length > 0 && (length % sizeof(u32)) == 0); | ||
| 313 | supported_npad_id_types.clear(); | ||
| 314 | supported_npad_id_types.resize(length / sizeof(u32)); | ||
| 315 | std::memcpy(supported_npad_id_types.data(), data, length); | ||
| 316 | } | ||
| 317 | |||
| 318 | const void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) { | ||
| 319 | ASSERT(max_length < supported_npad_id_types.size()); | ||
| 320 | std::memcpy(data, supported_npad_id_types.data(), supported_npad_id_types.size()); | ||
| 321 | } | ||
| 322 | |||
| 323 | std::size_t Controller_NPad::GetSupportedNPadIdTypesSize() const { | ||
| 324 | return supported_npad_id_types.size(); | ||
| 325 | } | ||
| 326 | |||
| 327 | void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) { | ||
| 328 | hold_type = joy_hold_type; | ||
| 329 | } | ||
| 330 | Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const { | ||
| 331 | return hold_type; | ||
| 332 | } | ||
| 333 | |||
| 334 | void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) { | ||
| 335 | ASSERT(npad_id < shared_memory_entries.size()); | ||
| 336 | shared_memory_entries[npad_id].pad_assignment = assignment_mode; | ||
| 337 | } | ||
| 338 | |||
| 339 | void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids, | ||
| 340 | const std::vector<Vibration>& vibrations) { | ||
| 341 | if (!can_controllers_vibrate) { | ||
| 342 | return; | ||
| 343 | } | ||
| 344 | for (std::size_t i = 0; i < controller_ids.size(); i++) { | ||
| 345 | std::size_t controller_pos = i; | ||
| 346 | // Handheld controller conversion | ||
| 347 | if (controller_pos == 32) { | ||
| 348 | controller_pos = 8; | ||
| 349 | } | ||
| 350 | // Unknown controller conversion | ||
| 351 | if (controller_pos == 16) { | ||
| 352 | controller_pos = 9; | ||
| 353 | } | ||
| 354 | if (connected_controllers[controller_pos].is_connected) { | ||
| 355 | // TODO(ogniK): Vibrate the physical controller | ||
| 356 | } | ||
| 357 | } | ||
| 358 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 359 | last_processed_vibration = vibrations.back(); | ||
| 360 | } | ||
| 361 | |||
| 362 | Kernel::SharedPtr<Kernel::Event> Controller_NPad::GetStyleSetChangedEvent() const { | ||
| 363 | return styleset_changed_event; | ||
| 364 | } | ||
| 365 | |||
| 366 | Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { | ||
| 367 | return last_processed_vibration; | ||
| 368 | } | ||
| 369 | void Controller_NPad::AddNewController(NPadControllerType controller) { | ||
| 370 | if (controller == NPadControllerType::Handheld) { | ||
| 371 | connected_controllers[8] = {controller, true}; | ||
| 372 | InitNewlyAddedControler(8); | ||
| 373 | return; | ||
| 374 | } | ||
| 375 | const auto pos = | ||
| 376 | std::find_if(connected_controllers.begin(), connected_controllers.end() - 2, | ||
| 377 | [](const ControllerHolder& holder) { return !holder.is_connected; }); | ||
| 378 | if (pos == connected_controllers.end() - 2) { | ||
| 379 | LOG_ERROR(Service_HID, "Cannot connect any more controllers!"); | ||
| 380 | return; | ||
| 381 | } | ||
| 382 | const auto controller_id = std::distance(connected_controllers.begin(), pos); | ||
| 383 | connected_controllers[controller_id] = {controller, true}; | ||
| 384 | InitNewlyAddedControler(controller_id); | ||
| 385 | } | ||
| 386 | |||
| 387 | void Controller_NPad::ConnectNPad(u32 npad_id) { | ||
| 388 | if (npad_id >= connected_controllers.size()) | ||
| 389 | return; | ||
| 390 | connected_controllers[npad_id].is_connected = true; | ||
| 391 | } | ||
| 392 | |||
| 393 | void Controller_NPad::DisconnectNPad(u32 npad_id) { | ||
| 394 | if (npad_id >= connected_controllers.size()) | ||
| 395 | return; | ||
| 396 | connected_controllers[npad_id].is_connected = false; | ||
| 397 | } | ||
| 398 | |||
| 399 | Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) { | ||
| 400 | if (npad_id == npad_id_list.back() || npad_id == npad_id_list[npad_id_list.size() - 2]) { | ||
| 401 | // These are controllers without led patterns | ||
| 402 | return LedPattern{0, 0, 0, 0}; | ||
| 403 | } | ||
| 404 | switch (npad_id) { | ||
| 405 | case 0: | ||
| 406 | return LedPattern{1, 0, 0, 0}; | ||
| 407 | case 1: | ||
| 408 | return LedPattern{0, 1, 0, 0}; | ||
| 409 | case 2: | ||
| 410 | return LedPattern{0, 0, 1, 0}; | ||
| 411 | case 3: | ||
| 412 | return LedPattern{0, 0, 0, 1}; | ||
| 413 | case 4: | ||
| 414 | return LedPattern{1, 0, 0, 1}; | ||
| 415 | case 5: | ||
| 416 | return LedPattern{1, 0, 1, 0}; | ||
| 417 | case 6: | ||
| 418 | return LedPattern{1, 0, 1, 1}; | ||
| 419 | case 7: | ||
| 420 | return LedPattern{0, 1, 1, 0}; | ||
| 421 | default: | ||
| 422 | UNIMPLEMENTED_MSG("Unhandled npad_id {}", npad_id); | ||
| 423 | return LedPattern{0, 0, 0, 0}; | ||
| 424 | }; | ||
| 425 | } | ||
| 426 | void Controller_NPad::SetVibrationEnabled(bool can_vibrate) { | ||
| 427 | can_controllers_vibrate = can_vibrate; | ||
| 428 | } | ||
| 429 | } // 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 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "core/frontend/input.h" | ||
| 10 | #include "core/hle/service/hid/controllers/controller_base.h" | ||
| 11 | #include "core/settings.h" | ||
| 12 | |||
| 13 | namespace Service::HID { | ||
| 14 | |||
| 15 | class Controller_NPad final : public ControllerBase { | ||
| 16 | public: | ||
| 17 | Controller_NPad(); | ||
| 18 | |||
| 19 | // Called when the controller is initialized | ||
| 20 | void OnInit() override; | ||
| 21 | |||
| 22 | // When the controller is released | ||
| 23 | void OnRelease() override; | ||
| 24 | |||
| 25 | // When the controller is requesting an update for the shared memory | ||
| 26 | void OnUpdate(u8* data, std::size_t size) override; | ||
| 27 | |||
| 28 | // Called when input devices should be loaded | ||
| 29 | void OnLoadInputDevices() override; | ||
| 30 | |||
| 31 | struct NPadType { | ||
| 32 | union { | ||
| 33 | u32_le raw{}; | ||
| 34 | |||
| 35 | BitField<0, 1, u32_le> pro_controller; | ||
| 36 | BitField<1, 1, u32_le> handheld; | ||
| 37 | BitField<2, 1, u32_le> joycon_dual; | ||
| 38 | BitField<3, 1, u32_le> joycon_left; | ||
| 39 | BitField<4, 1, u32_le> joycon_right; | ||
| 40 | |||
| 41 | BitField<6, 1, u32_le> pokeball; // TODO(ogniK): Confirm when possible | ||
| 42 | }; | ||
| 43 | }; | ||
| 44 | static_assert(sizeof(NPadType) == 4, "NPadType is an invalid size"); | ||
| 45 | |||
| 46 | struct Vibration { | ||
| 47 | f32 amp_low; | ||
| 48 | f32 freq_low; | ||
| 49 | f32 amp_high; | ||
| 50 | f32 freq_high; | ||
| 51 | }; | ||
| 52 | static_assert(sizeof(Vibration) == 0x10, "Vibration is an invalid size"); | ||
| 53 | |||
| 54 | enum class NpadHoldType : u64 { | ||
| 55 | Vertical = 0, | ||
| 56 | Horizontal = 1, | ||
| 57 | }; | ||
| 58 | |||
| 59 | enum class NPadAssignments : u32_le { | ||
| 60 | Dual = 0, | ||
| 61 | Single = 1, | ||
| 62 | }; | ||
| 63 | |||
| 64 | enum class NPadControllerType { | ||
| 65 | None, | ||
| 66 | ProController, | ||
| 67 | Handheld, | ||
| 68 | JoyDual, | ||
| 69 | JoyLeft, | ||
| 70 | JoyRight, | ||
| 71 | Pokeball, | ||
| 72 | }; | ||
| 73 | |||
| 74 | struct LedPattern { | ||
| 75 | explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) { | ||
| 76 | position1.Assign(light1); | ||
| 77 | position1.Assign(light2); | ||
| 78 | position1.Assign(light3); | ||
| 79 | position1.Assign(light4); | ||
| 80 | }; | ||
| 81 | union { | ||
| 82 | u64 raw{}; | ||
| 83 | BitField<0, 1, u64> position1; | ||
| 84 | BitField<1, 1, u64> position2; | ||
| 85 | BitField<2, 1, u64> position3; | ||
| 86 | BitField<3, 1, u64> position4; | ||
| 87 | }; | ||
| 88 | }; | ||
| 89 | |||
| 90 | void SetSupportedStyleSet(NPadType style_set); | ||
| 91 | NPadType GetSupportedStyleSet() const; | ||
| 92 | |||
| 93 | void SetSupportedNPadIdTypes(u8* data, std::size_t length); | ||
| 94 | const void GetSupportedNpadIdTypes(u32* data, std::size_t max_length); | ||
| 95 | std::size_t GetSupportedNPadIdTypesSize() const; | ||
| 96 | |||
| 97 | void SetHoldType(NpadHoldType joy_hold_type); | ||
| 98 | NpadHoldType GetHoldType() const; | ||
| 99 | |||
| 100 | void SetNpadMode(u32 npad_id, NPadAssignments assignment_mode); | ||
| 101 | |||
| 102 | void VibrateController(const std::vector<u32>& controller_ids, | ||
| 103 | const std::vector<Vibration>& vibrations); | ||
| 104 | |||
| 105 | Kernel::SharedPtr<Kernel::Event> GetStyleSetChangedEvent() const; | ||
| 106 | Vibration GetLastVibration() const; | ||
| 107 | |||
| 108 | void AddNewController(NPadControllerType controller); | ||
| 109 | |||
| 110 | void ConnectNPad(u32 npad_id); | ||
| 111 | void DisconnectNPad(u32 npad_id); | ||
| 112 | LedPattern GetLedPattern(u32 npad_id); | ||
| 113 | void SetVibrationEnabled(bool can_vibrate); | ||
| 114 | |||
| 115 | private: | ||
| 116 | struct CommonHeader { | ||
| 117 | s64_le timestamp; | ||
| 118 | s64_le total_entry_count; | ||
| 119 | s64_le last_entry_index; | ||
| 120 | s64_le entry_count; | ||
| 121 | }; | ||
| 122 | static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); | ||
| 123 | |||
| 124 | struct ControllerColor { | ||
| 125 | u32_le body_color; | ||
| 126 | u32_le button_color; | ||
| 127 | }; | ||
| 128 | static_assert(sizeof(ControllerColor) == 8, "ControllerColor is an invalid size"); | ||
| 129 | |||
| 130 | struct ControllerPadState { | ||
| 131 | union { | ||
| 132 | u64_le raw{}; | ||
| 133 | // Button states | ||
| 134 | BitField<0, 1, u64_le> a; | ||
| 135 | BitField<1, 1, u64_le> b; | ||
| 136 | BitField<2, 1, u64_le> x; | ||
| 137 | BitField<3, 1, u64_le> y; | ||
| 138 | BitField<4, 1, u64_le> l_stick; | ||
| 139 | BitField<5, 1, u64_le> r_stick; | ||
| 140 | BitField<6, 1, u64_le> l; | ||
| 141 | BitField<7, 1, u64_le> r; | ||
| 142 | BitField<8, 1, u64_le> zl; | ||
| 143 | BitField<9, 1, u64_le> zr; | ||
| 144 | BitField<10, 1, u64_le> plus; | ||
| 145 | BitField<11, 1, u64_le> minus; | ||
| 146 | |||
| 147 | // D-Pad | ||
| 148 | BitField<12, 1, u64_le> d_left; | ||
| 149 | BitField<13, 1, u64_le> d_up; | ||
| 150 | BitField<14, 1, u64_le> d_right; | ||
| 151 | BitField<15, 1, u64_le> d_down; | ||
| 152 | |||
| 153 | // Left JoyStick | ||
| 154 | BitField<16, 1, u64_le> l_stick_left; | ||
| 155 | BitField<17, 1, u64_le> l_stick_up; | ||
| 156 | BitField<18, 1, u64_le> l_stick_right; | ||
| 157 | BitField<19, 1, u64_le> l_stick_down; | ||
| 158 | |||
| 159 | // Right JoyStick | ||
| 160 | BitField<20, 1, u64_le> r_stick_left; | ||
| 161 | BitField<21, 1, u64_le> r_stick_up; | ||
| 162 | BitField<22, 1, u64_le> r_stick_right; | ||
| 163 | BitField<23, 1, u64_le> r_stick_down; | ||
| 164 | |||
| 165 | // Not always active? | ||
| 166 | BitField<24, 1, u64_le> sl; | ||
| 167 | BitField<25, 1, u64_le> sr; | ||
| 168 | }; | ||
| 169 | }; | ||
| 170 | static_assert(sizeof(ControllerPadState) == 8, "ControllerPadState is an invalid size"); | ||
| 171 | |||
| 172 | struct AnalogPosition { | ||
| 173 | s32_le x; | ||
| 174 | s32_le y; | ||
| 175 | }; | ||
| 176 | static_assert(sizeof(AnalogPosition) == 8, "AnalogPosition is an invalid size"); | ||
| 177 | |||
| 178 | struct ConnectionState { | ||
| 179 | union { | ||
| 180 | u32_le raw{}; | ||
| 181 | BitField<0, 1, u32_le> IsConnected; | ||
| 182 | BitField<1, 1, u32_le> IsWired; | ||
| 183 | BitField<2, 1, u32_le> IsLeftJoyConnected; | ||
| 184 | BitField<3, 1, u32_le> IsLeftJoyWired; | ||
| 185 | BitField<4, 1, u32_le> IsRightJoyConnected; | ||
| 186 | BitField<5, 1, u32_le> IsRightJoyWired; | ||
| 187 | }; | ||
| 188 | }; | ||
| 189 | static_assert(sizeof(ConnectionState) == 4, "ConnectionState is an invalid size"); | ||
| 190 | |||
| 191 | struct GenericStates { | ||
| 192 | s64_le timestamp; | ||
| 193 | s64_le timestamp2; | ||
| 194 | ControllerPadState pad_states; | ||
| 195 | AnalogPosition l_stick; | ||
| 196 | AnalogPosition r_stick; | ||
| 197 | ConnectionState connection_status; | ||
| 198 | }; | ||
| 199 | static_assert(sizeof(GenericStates) == 0x30, "NPadGenericStates is an invalid size"); | ||
| 200 | |||
| 201 | struct NPadGeneric { | ||
| 202 | CommonHeader common; | ||
| 203 | std::array<GenericStates, 17> npad; | ||
| 204 | }; | ||
| 205 | static_assert(sizeof(NPadGeneric) == 0x350, "NPadGeneric is an invalid size"); | ||
| 206 | |||
| 207 | enum class ColorReadError : u32_le { | ||
| 208 | ReadOk = 0, | ||
| 209 | ColorDoesntExist = 1, | ||
| 210 | NoController = 2, | ||
| 211 | }; | ||
| 212 | |||
| 213 | struct NPadProperties { | ||
| 214 | union { | ||
| 215 | s64_le raw{}; | ||
| 216 | BitField<11, 1, s64_le> is_vertical; | ||
| 217 | BitField<12, 1, s64_le> is_horizontal; | ||
| 218 | BitField<13, 1, s64_le> use_plus; | ||
| 219 | BitField<14, 1, s64_le> use_minus; | ||
| 220 | }; | ||
| 221 | }; | ||
| 222 | |||
| 223 | struct NPadDevice { | ||
| 224 | union { | ||
| 225 | u32_le raw{}; | ||
| 226 | BitField<0, 1, s32_le> pro_controller; | ||
| 227 | BitField<1, 1, s32_le> handheld; | ||
| 228 | BitField<2, 1, s32_le> handheld_left; | ||
| 229 | BitField<3, 1, s32_le> handheld_right; | ||
| 230 | BitField<4, 1, s32_le> joycon_left; | ||
| 231 | BitField<5, 1, s32_le> joycon_right; | ||
| 232 | BitField<6, 1, s32_le> pokeball; | ||
| 233 | }; | ||
| 234 | }; | ||
| 235 | |||
| 236 | struct NPadEntry { | ||
| 237 | NPadType joy_styles; | ||
| 238 | NPadAssignments pad_assignment; | ||
| 239 | |||
| 240 | ColorReadError single_color_error; | ||
| 241 | ControllerColor single_color; | ||
| 242 | |||
| 243 | ColorReadError dual_color_error; | ||
| 244 | ControllerColor left_color; | ||
| 245 | ControllerColor right_color; | ||
| 246 | |||
| 247 | NPadGeneric main_controller_states; | ||
| 248 | NPadGeneric handheld_states; | ||
| 249 | NPadGeneric dual_states; | ||
| 250 | NPadGeneric left_joy_states; | ||
| 251 | NPadGeneric right_joy_states; | ||
| 252 | NPadGeneric pokeball_states; | ||
| 253 | NPadGeneric libnx; // TODO(ogniK): Find out what this actually is, libnx seems to only be | ||
| 254 | // relying on this for the time being | ||
| 255 | INSERT_PADDING_BYTES( | ||
| 256 | 0x708 * | ||
| 257 | 6); // TODO(ogniK): SixAxis states, require more information before implementation | ||
| 258 | NPadDevice device_type; | ||
| 259 | NPadProperties properties; | ||
| 260 | INSERT_PADDING_WORDS(1); | ||
| 261 | std::array<u32, 3> battery_level; | ||
| 262 | INSERT_PADDING_BYTES(0x5c); | ||
| 263 | INSERT_PADDING_BYTES(0xdf8); | ||
| 264 | }; | ||
| 265 | static_assert(sizeof(NPadEntry) == 0x5000, "NPadEntry is an invalid size"); | ||
| 266 | |||
| 267 | struct ControllerHolder { | ||
| 268 | Controller_NPad::NPadControllerType type; | ||
| 269 | bool is_connected; | ||
| 270 | }; | ||
| 271 | |||
| 272 | NPadType style{}; | ||
| 273 | std::array<NPadEntry, 10> shared_memory_entries{}; | ||
| 274 | std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID> | ||
| 275 | buttons; | ||
| 276 | std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID> sticks; | ||
| 277 | std::vector<u32> supported_npad_id_types{}; | ||
| 278 | NpadHoldType hold_type{NpadHoldType::Vertical}; | ||
| 279 | Kernel::SharedPtr<Kernel::Event> styleset_changed_event; | ||
| 280 | std::size_t dump_idx{}; | ||
| 281 | Vibration last_processed_vibration{}; | ||
| 282 | static constexpr std::array<u32, 10> npad_id_list{0, 1, 2, 3, 4, 5, 6, 7, 32, 16}; | ||
| 283 | std::array<ControllerHolder, 10> connected_controllers{}; | ||
| 284 | bool can_controllers_vibrate{true}; | ||
| 285 | |||
| 286 | void InitNewlyAddedControler(std::size_t controller_idx); | ||
| 287 | }; | ||
| 288 | } // 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 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cstring> | ||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "common/swap.h" | ||
| 8 | #include "core/core_timing.h" | ||
| 9 | #include "core/hle/service/hid/controllers/stubbed.h" | ||
| 10 | |||
| 11 | namespace Service::HID { | ||
| 12 | |||
| 13 | Controller_Stubbed::Controller_Stubbed() = default; | ||
| 14 | |||
| 15 | void Controller_Stubbed::OnInit() {} | ||
| 16 | |||
| 17 | void Controller_Stubbed::OnRelease() {} | ||
| 18 | |||
| 19 | void Controller_Stubbed::OnUpdate(u8* data, std::size_t size) { | ||
| 20 | if (!smart_update) { | ||
| 21 | return; | ||
| 22 | } | ||
| 23 | |||
| 24 | CommonHeader header{}; | ||
| 25 | header.timestamp = CoreTiming::GetTicks(); | ||
| 26 | header.total_entry_count = 17; | ||
| 27 | header.entry_count = 0; | ||
| 28 | header.last_entry_index = 0; | ||
| 29 | |||
| 30 | std::memcpy(data + common_offset, &header, sizeof(CommonHeader)); | ||
| 31 | } | ||
| 32 | |||
| 33 | void Controller_Stubbed::OnLoadInputDevices() {} | ||
| 34 | |||
| 35 | void Controller_Stubbed::SetCommonHeaderOffset(std::size_t off) { | ||
| 36 | common_offset = off; | ||
| 37 | smart_update = true; | ||
| 38 | } | ||
| 39 | } // 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 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "core/hle/service/hid/controllers/controller_base.h" | ||
| 9 | |||
| 10 | namespace Service::HID { | ||
| 11 | class Controller_Stubbed final : public ControllerBase { | ||
| 12 | public: | ||
| 13 | Controller_Stubbed(); | ||
| 14 | |||
| 15 | // Called when the controller is initialized | ||
| 16 | void OnInit() override; | ||
| 17 | |||
| 18 | // When the controller is released | ||
| 19 | void OnRelease() override; | ||
| 20 | |||
| 21 | // When the controller is requesting an update for the shared memory | ||
| 22 | void OnUpdate(u8* data, std::size_t size) override; | ||
| 23 | |||
| 24 | // Called when input devices should be loaded | ||
| 25 | void OnLoadInputDevices() override; | ||
| 26 | |||
| 27 | void SetCommonHeaderOffset(std::size_t off); | ||
| 28 | |||
| 29 | private: | ||
| 30 | bool smart_update{}; | ||
| 31 | std::size_t common_offset{}; | ||
| 32 | }; | ||
| 33 | } // 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 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cstring> | ||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "common/swap.h" | ||
| 8 | #include "core/core_timing.h" | ||
| 9 | #include "core/frontend/emu_window.h" | ||
| 10 | #include "core/frontend/input.h" | ||
| 11 | #include "core/hle/service/hid/controllers/touchscreen.h" | ||
| 12 | #include "core/settings.h" | ||
| 13 | |||
| 14 | namespace Service::HID { | ||
| 15 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; | ||
| 16 | |||
| 17 | Controller_Touchscreen::Controller_Touchscreen() = default; | ||
| 18 | |||
| 19 | void Controller_Touchscreen::OnInit() {} | ||
| 20 | |||
| 21 | void Controller_Touchscreen::OnRelease() {} | ||
| 22 | |||
| 23 | void Controller_Touchscreen::OnUpdate(u8* data, std::size_t size) { | ||
| 24 | shared_memory.header.timestamp = CoreTiming::GetTicks(); | ||
| 25 | shared_memory.header.total_entry_count = 17; | ||
| 26 | |||
| 27 | if (!IsControllerActivated()) { | ||
| 28 | shared_memory.header.entry_count = 0; | ||
| 29 | shared_memory.header.last_entry_index = 0; | ||
| 30 | return; | ||
| 31 | } | ||
| 32 | shared_memory.header.entry_count = 16; | ||
| 33 | |||
| 34 | const auto& last_entry = | ||
| 35 | shared_memory.shared_memory_entries[shared_memory.header.last_entry_index]; | ||
| 36 | shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; | ||
| 37 | auto& cur_entry = shared_memory.shared_memory_entries[shared_memory.header.last_entry_index]; | ||
| 38 | |||
| 39 | cur_entry.sampling_number = last_entry.sampling_number + 1; | ||
| 40 | cur_entry.sampling_number2 = cur_entry.sampling_number; | ||
| 41 | |||
| 42 | const auto [x, y, pressed] = touch_device->GetStatus(); | ||
| 43 | auto& touch_entry = cur_entry.states[0]; | ||
| 44 | if (pressed) { | ||
| 45 | touch_entry.x = static_cast<u16>(x * Layout::ScreenUndocked::Width); | ||
| 46 | touch_entry.y = static_cast<u16>(y * Layout::ScreenUndocked::Height); | ||
| 47 | touch_entry.diameter_x = 15; | ||
| 48 | touch_entry.diameter_y = 15; | ||
| 49 | touch_entry.rotation_angle = 0; | ||
| 50 | const u64 tick = CoreTiming::GetTicks(); | ||
| 51 | touch_entry.delta_time = tick - last_touch; | ||
| 52 | last_touch = tick; | ||
| 53 | touch_entry.finger = 0; | ||
| 54 | cur_entry.entry_count = 1; | ||
| 55 | } else { | ||
| 56 | cur_entry.entry_count = 0; | ||
| 57 | } | ||
| 58 | |||
| 59 | std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(TouchScreenSharedMemory)); | ||
| 60 | } | ||
| 61 | |||
| 62 | void Controller_Touchscreen::OnLoadInputDevices() { | ||
| 63 | touch_device = Input::CreateDevice<Input::TouchDevice>(Settings::values.touch_device); | ||
| 64 | } | ||
| 65 | } // 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 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_funcs.h" | ||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "common/swap.h" | ||
| 10 | #include "core/frontend/input.h" | ||
| 11 | #include "core/hle/service/hid/controllers/controller_base.h" | ||
| 12 | |||
| 13 | namespace Service::HID { | ||
| 14 | class Controller_Touchscreen final : public ControllerBase { | ||
| 15 | public: | ||
| 16 | Controller_Touchscreen(); | ||
| 17 | |||
| 18 | // Called when the controller is initialized | ||
| 19 | void OnInit() override; | ||
| 20 | |||
| 21 | // When the controller is released | ||
| 22 | void OnRelease() override; | ||
| 23 | |||
| 24 | // When the controller is requesting an update for the shared memory | ||
| 25 | void OnUpdate(u8* data, std::size_t size) override; | ||
| 26 | |||
| 27 | // Called when input devices should be loaded | ||
| 28 | void OnLoadInputDevices() override; | ||
| 29 | |||
| 30 | private: | ||
| 31 | struct TouchState { | ||
| 32 | u64_le delta_time; | ||
| 33 | u32_le attribute; | ||
| 34 | u32_le finger; | ||
| 35 | u32_le x; | ||
| 36 | u32_le y; | ||
| 37 | u32_le diameter_x; | ||
| 38 | u32_le diameter_y; | ||
| 39 | u32_le rotation_angle; | ||
| 40 | }; | ||
| 41 | static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size"); | ||
| 42 | |||
| 43 | struct TouchScreenEntry { | ||
| 44 | s64_le sampling_number; | ||
| 45 | s64_le sampling_number2; | ||
| 46 | s32_le entry_count; | ||
| 47 | std::array<TouchState, 16> states; | ||
| 48 | }; | ||
| 49 | static_assert(sizeof(TouchScreenEntry) == 0x298, "TouchScreenEntry is an invalid size"); | ||
| 50 | |||
| 51 | struct TouchScreenSharedMemory { | ||
| 52 | CommonHeader header; | ||
| 53 | std::array<TouchScreenEntry, 17> shared_memory_entries{}; | ||
| 54 | INSERT_PADDING_BYTES(0x3c8); | ||
| 55 | }; | ||
| 56 | static_assert(sizeof(TouchScreenSharedMemory) == 0x3000, | ||
| 57 | "TouchScreenSharedMemory is an invalid size"); | ||
| 58 | TouchScreenSharedMemory shared_memory{}; | ||
| 59 | std::unique_ptr<Input::TouchDevice> touch_device; | ||
| 60 | s64_le last_touch{}; | ||
| 61 | }; | ||
| 62 | } // 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 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cstring> | ||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "common/swap.h" | ||
| 8 | #include "core/core_timing.h" | ||
| 9 | #include "core/hle/service/hid/controllers/xpad.h" | ||
| 10 | |||
| 11 | namespace Service::HID { | ||
| 12 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00; | ||
| 13 | |||
| 14 | Controller_XPad::Controller_XPad() = default; | ||
| 15 | |||
| 16 | void Controller_XPad::OnInit() {} | ||
| 17 | |||
| 18 | void Controller_XPad::OnRelease() {} | ||
| 19 | |||
| 20 | void Controller_XPad::OnUpdate(u8* data, std::size_t size) { | ||
| 21 | for (auto& xpad_entry : shared_memory.shared_memory_entries) { | ||
| 22 | xpad_entry.header.timestamp = CoreTiming::GetTicks(); | ||
| 23 | xpad_entry.header.total_entry_count = 17; | ||
| 24 | |||
| 25 | if (!IsControllerActivated()) { | ||
| 26 | xpad_entry.header.entry_count = 0; | ||
| 27 | xpad_entry.header.last_entry_index = 0; | ||
| 28 | return; | ||
| 29 | } | ||
| 30 | xpad_entry.header.entry_count = 16; | ||
| 31 | |||
| 32 | const auto& last_entry = xpad_entry.pad_states[xpad_entry.header.last_entry_index]; | ||
| 33 | xpad_entry.header.last_entry_index = (xpad_entry.header.last_entry_index + 1) % 17; | ||
| 34 | auto& cur_entry = xpad_entry.pad_states[xpad_entry.header.last_entry_index]; | ||
| 35 | |||
| 36 | cur_entry.sampling_number = last_entry.sampling_number + 1; | ||
| 37 | cur_entry.sampling_number2 = cur_entry.sampling_number; | ||
| 38 | } | ||
| 39 | // TODO(ogniK): Update xpad states | ||
| 40 | |||
| 41 | std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); | ||
| 42 | } | ||
| 43 | |||
| 44 | void Controller_XPad::OnLoadInputDevices() {} | ||
| 45 | } // 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 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_funcs.h" | ||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "common/swap.h" | ||
| 10 | #include "core/frontend/input.h" | ||
| 11 | #include "core/hle/service/hid/controllers/controller_base.h" | ||
| 12 | |||
| 13 | namespace Service::HID { | ||
| 14 | class Controller_XPad final : public ControllerBase { | ||
| 15 | public: | ||
| 16 | Controller_XPad(); | ||
| 17 | |||
| 18 | // Called when the controller is initialized | ||
| 19 | void OnInit() override; | ||
| 20 | |||
| 21 | // When the controller is released | ||
| 22 | void OnRelease() override; | ||
| 23 | |||
| 24 | // When the controller is requesting an update for the shared memory | ||
| 25 | void OnUpdate(u8* data, std::size_t size) override; | ||
| 26 | |||
| 27 | // Called when input devices should be loaded | ||
| 28 | void OnLoadInputDevices() override; | ||
| 29 | |||
| 30 | private: | ||
| 31 | struct AnalogStick { | ||
| 32 | s32_le x; | ||
| 33 | s32_le y; | ||
| 34 | }; | ||
| 35 | static_assert(sizeof(AnalogStick) == 0x8, "AnalogStick is an invalid size"); | ||
| 36 | |||
| 37 | struct XPadState { | ||
| 38 | s64_le sampling_number; | ||
| 39 | s64_le sampling_number2; | ||
| 40 | s32_le attributes; | ||
| 41 | u32_le pad_states; | ||
| 42 | AnalogStick x_stick; | ||
| 43 | AnalogStick y_stick; | ||
| 44 | }; | ||
| 45 | static_assert(sizeof(XPadState) == 0x28, "XPadState is an invalid size"); | ||
| 46 | |||
| 47 | struct XPadEntry { | ||
| 48 | CommonHeader header; | ||
| 49 | std::array<XPadState, 17> pad_states{}; | ||
| 50 | INSERT_PADDING_BYTES(0x138); | ||
| 51 | }; | ||
| 52 | static_assert(sizeof(XPadEntry) == 0x400, "XPadEntry is an invalid size"); | ||
| 53 | |||
| 54 | struct SharedMemory { | ||
| 55 | std::array<XPadEntry, 4> shared_memory_entries{}; | ||
| 56 | }; | ||
| 57 | static_assert(sizeof(SharedMemory) == 0x1000, "SharedMemory is an invalid size"); | ||
| 58 | SharedMemory shared_memory{}; | ||
| 59 | }; | ||
| 60 | } // 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 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <array> | ||
| 6 | #include "common/common_types.h" | ||
| 5 | #include "common/logging/log.h" | 7 | #include "common/logging/log.h" |
| 6 | #include "core/core.h" | 8 | #include "core/core.h" |
| 7 | #include "core/core_timing.h" | 9 | #include "core/core_timing.h" |
| @@ -19,6 +21,16 @@ | |||
| 19 | #include "core/hle/service/service.h" | 21 | #include "core/hle/service/service.h" |
| 20 | #include "core/settings.h" | 22 | #include "core/settings.h" |
| 21 | 23 | ||
| 24 | #include "core/hle/service/hid/controllers/controller_base.h" | ||
| 25 | #include "core/hle/service/hid/controllers/debug_pad.h" | ||
| 26 | #include "core/hle/service/hid/controllers/gesture.h" | ||
| 27 | #include "core/hle/service/hid/controllers/keyboard.h" | ||
| 28 | #include "core/hle/service/hid/controllers/mouse.h" | ||
| 29 | #include "core/hle/service/hid/controllers/npad.h" | ||
| 30 | #include "core/hle/service/hid/controllers/stubbed.h" | ||
| 31 | #include "core/hle/service/hid/controllers/touchscreen.h" | ||
| 32 | #include "core/hle/service/hid/controllers/xpad.h" | ||
| 33 | |||
| 22 | namespace Service::HID { | 34 | namespace Service::HID { |
| 23 | 35 | ||
| 24 | // Updating period for each HID device. | 36 | // Updating period for each HID device. |
| @@ -26,6 +38,22 @@ namespace Service::HID { | |||
| 26 | constexpr u64 pad_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; | 38 | constexpr u64 pad_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; |
| 27 | constexpr u64 accelerometer_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; | 39 | constexpr u64 accelerometer_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; |
| 28 | constexpr u64 gyroscope_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; | 40 | constexpr u64 gyroscope_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; |
| 41 | constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; | ||
| 42 | enum class HidController : std::size_t { | ||
| 43 | DebugPad, | ||
| 44 | Touchscreen, | ||
| 45 | Mouse, | ||
| 46 | Keyboard, | ||
| 47 | XPad, | ||
| 48 | Unknown1, | ||
| 49 | Unknown2, | ||
| 50 | Unknown3, | ||
| 51 | SixAxisSensor, | ||
| 52 | NPad, | ||
| 53 | Gesture, | ||
| 54 | |||
| 55 | MaxControllers, | ||
| 56 | }; | ||
| 29 | 57 | ||
| 30 | class IAppletResource final : public ServiceFramework<IAppletResource> { | 58 | class IAppletResource final : public ServiceFramework<IAppletResource> { |
| 31 | public: | 59 | public: |
| @@ -37,19 +65,57 @@ public: | |||
| 37 | 65 | ||
| 38 | auto& kernel = Core::System::GetInstance().Kernel(); | 66 | auto& kernel = Core::System::GetInstance().Kernel(); |
| 39 | shared_mem = Kernel::SharedMemory::Create( | 67 | shared_mem = Kernel::SharedMemory::Create( |
| 40 | kernel, nullptr, 0x40000, Kernel::MemoryPermission::ReadWrite, | 68 | kernel, nullptr, SHARED_MEMORY_SIZE, Kernel::MemoryPermission::ReadWrite, |
| 41 | Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "HID:SharedMemory"); | 69 | Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "HID:SharedMemory"); |
| 42 | 70 | ||
| 71 | MakeController<Controller_DebugPad>(HidController::DebugPad); | ||
| 72 | MakeController<Controller_Touchscreen>(HidController::Touchscreen); | ||
| 73 | MakeController<Controller_Mouse>(HidController::Mouse); | ||
| 74 | MakeController<Controller_Keyboard>(HidController::Keyboard); | ||
| 75 | MakeController<Controller_XPad>(HidController::XPad); | ||
| 76 | MakeController<Controller_Stubbed>(HidController::Unknown1); | ||
| 77 | MakeController<Controller_Stubbed>(HidController::Unknown2); | ||
| 78 | MakeController<Controller_Stubbed>(HidController::Unknown3); | ||
| 79 | MakeController<Controller_Stubbed>(HidController::SixAxisSensor); | ||
| 80 | MakeController<Controller_NPad>(HidController::NPad); | ||
| 81 | MakeController<Controller_Gesture>(HidController::Gesture); | ||
| 82 | |||
| 83 | // Homebrew doesn't try to activate some controllers, so we activate them by default | ||
| 84 | GetController<Controller_NPad>(HidController::NPad).ActivateController(); | ||
| 85 | GetController<Controller_Touchscreen>(HidController::Touchscreen).ActivateController(); | ||
| 86 | |||
| 87 | GetController<Controller_Stubbed>(HidController::Unknown1).SetCommonHeaderOffset(0x4c00); | ||
| 88 | GetController<Controller_Stubbed>(HidController::Unknown2).SetCommonHeaderOffset(0x4e00); | ||
| 89 | GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000); | ||
| 90 | |||
| 43 | // Register update callbacks | 91 | // Register update callbacks |
| 44 | pad_update_event = CoreTiming::RegisterEvent( | 92 | pad_update_event = CoreTiming::RegisterEvent( |
| 45 | "HID::UpdatePadCallback", | 93 | "HID::UpdatePadCallback", |
| 46 | [this](u64 userdata, int cycles_late) { UpdatePadCallback(userdata, cycles_late); }); | 94 | [this](u64 userdata, int cycles_late) { UpdateControllers(userdata, cycles_late); }); |
| 47 | 95 | ||
| 48 | // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?) | 96 | // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?) |
| 49 | 97 | ||
| 50 | CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event); | 98 | CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event); |
| 51 | } | 99 | } |
| 52 | 100 | ||
| 101 | void ActivateController(HidController controller) { | ||
| 102 | controllers[static_cast<size_t>(controller)]->ActivateController(); | ||
| 103 | } | ||
| 104 | |||
| 105 | void DeactivateController(HidController controller) { | ||
| 106 | controllers[static_cast<size_t>(controller)]->DeactivateController(); | ||
| 107 | } | ||
| 108 | |||
| 109 | template <typename T> | ||
| 110 | void MakeController(HidController controller) { | ||
| 111 | controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(); | ||
| 112 | } | ||
| 113 | |||
| 114 | template <typename T> | ||
| 115 | T& GetController(HidController controller) { | ||
| 116 | return static_cast<T&>(*controllers[static_cast<size_t>(controller)]); | ||
| 117 | } | ||
| 118 | |||
| 53 | ~IAppletResource() { | 119 | ~IAppletResource() { |
| 54 | CoreTiming::UnscheduleEvent(pad_update_event, 0); | 120 | CoreTiming::UnscheduleEvent(pad_update_event, 0); |
| 55 | } | 121 | } |
| @@ -62,200 +128,15 @@ private: | |||
| 62 | LOG_DEBUG(Service_HID, "called"); | 128 | LOG_DEBUG(Service_HID, "called"); |
| 63 | } | 129 | } |
| 64 | 130 | ||
| 65 | void LoadInputDevices() { | 131 | void UpdateControllers(u64 userdata, int cycles_late) { |
| 66 | std::transform(Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, | 132 | const bool should_reload = Settings::values.is_device_reload_pending.exchange(false); |
| 67 | Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_END, | 133 | for (const auto& controller : controllers) { |
| 68 | buttons.begin(), Input::CreateDevice<Input::ButtonDevice>); | 134 | if (should_reload) { |
| 69 | std::transform(Settings::values.analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, | 135 | controller->OnLoadInputDevices(); |
| 70 | Settings::values.analogs.begin() + Settings::NativeAnalog::STICK_HID_END, | ||
| 71 | sticks.begin(), Input::CreateDevice<Input::AnalogDevice>); | ||
| 72 | touch_device = Input::CreateDevice<Input::TouchDevice>(Settings::values.touch_device); | ||
| 73 | // TODO(shinyquagsire23): gyro, mouse, keyboard | ||
| 74 | } | ||
| 75 | |||
| 76 | void UpdatePadCallback(u64 userdata, int cycles_late) { | ||
| 77 | SharedMemory mem{}; | ||
| 78 | std::memcpy(&mem, shared_mem->GetPointer(), sizeof(SharedMemory)); | ||
| 79 | |||
| 80 | if (Settings::values.is_device_reload_pending.exchange(false)) | ||
| 81 | LoadInputDevices(); | ||
| 82 | |||
| 83 | // Set up controllers as neon red+blue Joy-Con attached to console | ||
| 84 | ControllerHeader& controller_header = mem.controllers[Controller_Handheld].header; | ||
| 85 | controller_header.type = ControllerType_Handheld; | ||
| 86 | controller_header.single_colors_descriptor = ColorDesc_ColorsNonexistent; | ||
| 87 | controller_header.right_color_body = JOYCON_BODY_NEON_RED; | ||
| 88 | controller_header.right_color_buttons = JOYCON_BUTTONS_NEON_RED; | ||
| 89 | controller_header.left_color_body = JOYCON_BODY_NEON_BLUE; | ||
| 90 | controller_header.left_color_buttons = JOYCON_BUTTONS_NEON_BLUE; | ||
| 91 | |||
| 92 | for (std::size_t controller = 0; controller < mem.controllers.size(); controller++) { | ||
| 93 | for (auto& layout : mem.controllers[controller].layouts) { | ||
| 94 | layout.header.num_entries = HID_NUM_ENTRIES; | ||
| 95 | layout.header.max_entry_index = HID_NUM_ENTRIES - 1; | ||
| 96 | |||
| 97 | // HID shared memory stores the state of the past 17 samples in a circlular buffer, | ||
| 98 | // each with a timestamp in number of samples since boot. | ||
| 99 | const ControllerInputEntry& last_entry = layout.entries[layout.header.latest_entry]; | ||
| 100 | |||
| 101 | layout.header.timestamp_ticks = CoreTiming::GetTicks(); | ||
| 102 | layout.header.latest_entry = (layout.header.latest_entry + 1) % HID_NUM_ENTRIES; | ||
| 103 | |||
| 104 | ControllerInputEntry& entry = layout.entries[layout.header.latest_entry]; | ||
| 105 | entry.timestamp = last_entry.timestamp + 1; | ||
| 106 | // TODO(shinyquagsire23): Is this always identical to timestamp? | ||
| 107 | entry.timestamp_2 = entry.timestamp; | ||
| 108 | |||
| 109 | // TODO(shinyquagsire23): More than just handheld input | ||
| 110 | if (controller != Controller_Handheld) | ||
| 111 | continue; | ||
| 112 | |||
| 113 | entry.connection_state = ConnectionState_Connected | ConnectionState_Wired; | ||
| 114 | |||
| 115 | // TODO(shinyquagsire23): Set up some LUTs for each layout mapping in the future? | ||
| 116 | // For now everything is just the default handheld layout, but split Joy-Con will | ||
| 117 | // rotate the face buttons and directions for certain layouts. | ||
| 118 | ControllerPadState& state = entry.buttons; | ||
| 119 | using namespace Settings::NativeButton; | ||
| 120 | state.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 121 | state.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 122 | state.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 123 | state.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 124 | state.lstick.Assign(buttons[LStick - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 125 | state.rstick.Assign(buttons[RStick - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 126 | state.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 127 | state.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 128 | state.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 129 | state.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 130 | state.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 131 | state.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 132 | |||
| 133 | state.dleft.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 134 | state.dup.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 135 | state.dright.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 136 | state.ddown.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 137 | |||
| 138 | state.lstick_left.Assign(buttons[LStick_Left - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 139 | state.lstick_up.Assign(buttons[LStick_Up - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 140 | state.lstick_right.Assign(buttons[LStick_Right - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 141 | state.lstick_down.Assign(buttons[LStick_Down - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 142 | |||
| 143 | state.rstick_left.Assign(buttons[RStick_Left - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 144 | state.rstick_up.Assign(buttons[RStick_Up - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 145 | state.rstick_right.Assign(buttons[RStick_Right - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 146 | state.rstick_down.Assign(buttons[RStick_Down - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 147 | |||
| 148 | state.sl.Assign(buttons[SL - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 149 | state.sr.Assign(buttons[SR - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 150 | |||
| 151 | const auto [stick_l_x_f, stick_l_y_f] = sticks[Joystick_Left]->GetStatus(); | ||
| 152 | const auto [stick_r_x_f, stick_r_y_f] = sticks[Joystick_Right]->GetStatus(); | ||
| 153 | entry.joystick_left_x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX); | ||
| 154 | entry.joystick_left_y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX); | ||
| 155 | entry.joystick_right_x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX); | ||
| 156 | entry.joystick_right_y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX); | ||
| 157 | } | 136 | } |
| 137 | controller->OnUpdate(shared_mem->GetPointer(), SHARED_MEMORY_SIZE); | ||
| 158 | } | 138 | } |
| 159 | 139 | ||
| 160 | TouchScreen& touchscreen = mem.touchscreen; | ||
| 161 | const u64 last_entry = touchscreen.header.latest_entry; | ||
| 162 | const u64 curr_entry = (last_entry + 1) % touchscreen.entries.size(); | ||
| 163 | const u64 timestamp = CoreTiming::GetTicks(); | ||
| 164 | const u64 sample_counter = touchscreen.entries[last_entry].header.timestamp + 1; | ||
| 165 | touchscreen.header.timestamp_ticks = timestamp; | ||
| 166 | touchscreen.header.num_entries = touchscreen.entries.size(); | ||
| 167 | touchscreen.header.latest_entry = curr_entry; | ||
| 168 | touchscreen.header.max_entry_index = touchscreen.entries.size(); | ||
| 169 | touchscreen.header.timestamp = timestamp; | ||
| 170 | touchscreen.entries[curr_entry].header.timestamp = sample_counter; | ||
| 171 | |||
| 172 | TouchScreenEntryTouch touch_entry{}; | ||
| 173 | auto [x, y, pressed] = touch_device->GetStatus(); | ||
| 174 | touch_entry.timestamp = timestamp; | ||
| 175 | touch_entry.x = static_cast<u16>(x * Layout::ScreenUndocked::Width); | ||
| 176 | touch_entry.y = static_cast<u16>(y * Layout::ScreenUndocked::Height); | ||
| 177 | touch_entry.touch_index = 0; | ||
| 178 | |||
| 179 | // TODO(DarkLordZach): Maybe try to derive these from EmuWindow? | ||
| 180 | touch_entry.diameter_x = 15; | ||
| 181 | touch_entry.diameter_y = 15; | ||
| 182 | touch_entry.angle = 0; | ||
| 183 | |||
| 184 | // TODO(DarkLordZach): Implement multi-touch support | ||
| 185 | if (pressed) { | ||
| 186 | touchscreen.entries[curr_entry].header.num_touches = 1; | ||
| 187 | touchscreen.entries[curr_entry].touches[0] = touch_entry; | ||
| 188 | } else { | ||
| 189 | touchscreen.entries[curr_entry].header.num_touches = 0; | ||
| 190 | } | ||
| 191 | |||
| 192 | // TODO(shinyquagsire23): Properly implement mouse | ||
| 193 | Mouse& mouse = mem.mouse; | ||
| 194 | const u64 last_mouse_entry = mouse.header.latest_entry; | ||
| 195 | const u64 curr_mouse_entry = (mouse.header.latest_entry + 1) % mouse.entries.size(); | ||
| 196 | const u64 mouse_sample_counter = mouse.entries[last_mouse_entry].timestamp + 1; | ||
| 197 | mouse.header.timestamp_ticks = timestamp; | ||
| 198 | mouse.header.num_entries = mouse.entries.size(); | ||
| 199 | mouse.header.max_entry_index = mouse.entries.size(); | ||
| 200 | mouse.header.latest_entry = curr_mouse_entry; | ||
| 201 | |||
| 202 | mouse.entries[curr_mouse_entry].timestamp = mouse_sample_counter; | ||
| 203 | mouse.entries[curr_mouse_entry].timestamp_2 = mouse_sample_counter; | ||
| 204 | |||
| 205 | // TODO(shinyquagsire23): Properly implement keyboard | ||
| 206 | Keyboard& keyboard = mem.keyboard; | ||
| 207 | const u64 last_keyboard_entry = keyboard.header.latest_entry; | ||
| 208 | const u64 curr_keyboard_entry = | ||
| 209 | (keyboard.header.latest_entry + 1) % keyboard.entries.size(); | ||
| 210 | const u64 keyboard_sample_counter = keyboard.entries[last_keyboard_entry].timestamp + 1; | ||
| 211 | keyboard.header.timestamp_ticks = timestamp; | ||
| 212 | keyboard.header.num_entries = keyboard.entries.size(); | ||
| 213 | keyboard.header.latest_entry = last_keyboard_entry; | ||
| 214 | keyboard.header.max_entry_index = keyboard.entries.size(); | ||
| 215 | |||
| 216 | keyboard.entries[curr_keyboard_entry].timestamp = keyboard_sample_counter; | ||
| 217 | keyboard.entries[curr_keyboard_entry].timestamp_2 = keyboard_sample_counter; | ||
| 218 | |||
| 219 | // TODO(shinyquagsire23): Figure out what any of these are | ||
| 220 | for (auto& input : mem.unk_input_1) { | ||
| 221 | const u64 last_input_entry = input.header.latest_entry; | ||
| 222 | const u64 curr_input_entry = (input.header.latest_entry + 1) % input.entries.size(); | ||
| 223 | const u64 input_sample_counter = input.entries[last_input_entry].timestamp + 1; | ||
| 224 | |||
| 225 | input.header.timestamp_ticks = timestamp; | ||
| 226 | input.header.num_entries = input.entries.size(); | ||
| 227 | input.header.latest_entry = last_input_entry; | ||
| 228 | input.header.max_entry_index = input.entries.size(); | ||
| 229 | |||
| 230 | input.entries[curr_input_entry].timestamp = input_sample_counter; | ||
| 231 | input.entries[curr_input_entry].timestamp_2 = input_sample_counter; | ||
| 232 | } | ||
| 233 | |||
| 234 | for (auto& input : mem.unk_input_2) { | ||
| 235 | input.header.timestamp_ticks = timestamp; | ||
| 236 | input.header.num_entries = 17; | ||
| 237 | input.header.latest_entry = 0; | ||
| 238 | input.header.max_entry_index = 0; | ||
| 239 | } | ||
| 240 | |||
| 241 | UnkInput3& input = mem.unk_input_3; | ||
| 242 | const u64 last_input_entry = input.header.latest_entry; | ||
| 243 | const u64 curr_input_entry = (input.header.latest_entry + 1) % input.entries.size(); | ||
| 244 | const u64 input_sample_counter = input.entries[last_input_entry].timestamp + 1; | ||
| 245 | |||
| 246 | input.header.timestamp_ticks = timestamp; | ||
| 247 | input.header.num_entries = input.entries.size(); | ||
| 248 | input.header.latest_entry = last_input_entry; | ||
| 249 | input.header.max_entry_index = input.entries.size(); | ||
| 250 | |||
| 251 | input.entries[curr_input_entry].timestamp = input_sample_counter; | ||
| 252 | input.entries[curr_input_entry].timestamp_2 = input_sample_counter; | ||
| 253 | |||
| 254 | // TODO(shinyquagsire23): Signal events | ||
| 255 | |||
| 256 | std::memcpy(shared_mem->GetPointer(), &mem, sizeof(SharedMemory)); | ||
| 257 | |||
| 258 | // Reschedule recurrent event | ||
| 259 | CoreTiming::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event); | 140 | CoreTiming::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event); |
| 260 | } | 141 | } |
| 261 | 142 | ||
| @@ -265,11 +146,8 @@ private: | |||
| 265 | // CoreTiming update events | 146 | // CoreTiming update events |
| 266 | CoreTiming::EventType* pad_update_event; | 147 | CoreTiming::EventType* pad_update_event; |
| 267 | 148 | ||
| 268 | // Stored input state info | 149 | std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)> |
| 269 | std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID> | 150 | controllers{}; |
| 270 | buttons; | ||
| 271 | std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID> sticks; | ||
| 272 | std::unique_ptr<Input::TouchDevice> touch_device; | ||
| 273 | }; | 151 | }; |
| 274 | 152 | ||
| 275 | class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> { | 153 | class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> { |
| @@ -301,7 +179,7 @@ public: | |||
| 301 | {31, &Hid::ActivateKeyboard, "ActivateKeyboard"}, | 179 | {31, &Hid::ActivateKeyboard, "ActivateKeyboard"}, |
| 302 | {40, nullptr, "AcquireXpadIdEventHandle"}, | 180 | {40, nullptr, "AcquireXpadIdEventHandle"}, |
| 303 | {41, nullptr, "ReleaseXpadIdEventHandle"}, | 181 | {41, nullptr, "ReleaseXpadIdEventHandle"}, |
| 304 | {51, nullptr, "ActivateXpad"}, | 182 | {51, &Hid::ActivateXpad, "ActivateXpad"}, |
| 305 | {55, nullptr, "GetXpadIds"}, | 183 | {55, nullptr, "GetXpadIds"}, |
| 306 | {56, nullptr, "ActivateJoyXpad"}, | 184 | {56, nullptr, "ActivateJoyXpad"}, |
| 307 | {58, nullptr, "GetJoyXpadLifoHandle"}, | 185 | {58, nullptr, "GetJoyXpadLifoHandle"}, |
| @@ -362,8 +240,8 @@ public: | |||
| 362 | {206, &Hid::SendVibrationValues, "SendVibrationValues"}, | 240 | {206, &Hid::SendVibrationValues, "SendVibrationValues"}, |
| 363 | {207, nullptr, "SendVibrationGcErmCommand"}, | 241 | {207, nullptr, "SendVibrationGcErmCommand"}, |
| 364 | {208, nullptr, "GetActualVibrationGcErmCommand"}, | 242 | {208, nullptr, "GetActualVibrationGcErmCommand"}, |
| 365 | {209, nullptr, "BeginPermitVibrationSession"}, | 243 | {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"}, |
| 366 | {210, nullptr, "EndPermitVibrationSession"}, | 244 | {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"}, |
| 367 | {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"}, | 245 | {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"}, |
| 368 | {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"}, | 246 | {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"}, |
| 369 | {302, nullptr, "StopConsoleSixAxisSensor"}, | 247 | {302, nullptr, "StopConsoleSixAxisSensor"}, |
| @@ -401,16 +279,11 @@ public: | |||
| 401 | // clang-format on | 279 | // clang-format on |
| 402 | 280 | ||
| 403 | RegisterHandlers(functions); | 281 | RegisterHandlers(functions); |
| 404 | |||
| 405 | auto& kernel = Core::System::GetInstance().Kernel(); | ||
| 406 | event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "hid:EventHandle"); | ||
| 407 | } | 282 | } |
| 408 | ~Hid() = default; | 283 | ~Hid() = default; |
| 409 | 284 | ||
| 410 | private: | 285 | private: |
| 411 | std::shared_ptr<IAppletResource> applet_resource; | 286 | std::shared_ptr<IAppletResource> applet_resource; |
| 412 | u32 joy_hold_type{0}; | ||
| 413 | Kernel::SharedPtr<Kernel::Event> event; | ||
| 414 | 287 | ||
| 415 | void CreateAppletResource(Kernel::HLERequestContext& ctx) { | 288 | void CreateAppletResource(Kernel::HLERequestContext& ctx) { |
| 416 | if (applet_resource == nullptr) { | 289 | if (applet_resource == nullptr) { |
| @@ -423,31 +296,59 @@ private: | |||
| 423 | LOG_DEBUG(Service_HID, "called"); | 296 | LOG_DEBUG(Service_HID, "called"); |
| 424 | } | 297 | } |
| 425 | 298 | ||
| 299 | void ActivateXpad(Kernel::HLERequestContext& ctx) { | ||
| 300 | applet_resource->ActivateController(HidController::XPad); | ||
| 301 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 302 | rb.Push(RESULT_SUCCESS); | ||
| 303 | LOG_DEBUG(Service_HID, "called"); | ||
| 304 | } | ||
| 305 | |||
| 426 | void ActivateDebugPad(Kernel::HLERequestContext& ctx) { | 306 | void ActivateDebugPad(Kernel::HLERequestContext& ctx) { |
| 307 | applet_resource->ActivateController(HidController::DebugPad); | ||
| 427 | IPC::ResponseBuilder rb{ctx, 2}; | 308 | IPC::ResponseBuilder rb{ctx, 2}; |
| 428 | rb.Push(RESULT_SUCCESS); | 309 | rb.Push(RESULT_SUCCESS); |
| 429 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 310 | LOG_DEBUG(Service_HID, "called"); |
| 430 | } | 311 | } |
| 431 | 312 | ||
| 432 | void ActivateTouchScreen(Kernel::HLERequestContext& ctx) { | 313 | void ActivateTouchScreen(Kernel::HLERequestContext& ctx) { |
| 314 | applet_resource->ActivateController(HidController::Touchscreen); | ||
| 433 | IPC::ResponseBuilder rb{ctx, 2}; | 315 | IPC::ResponseBuilder rb{ctx, 2}; |
| 434 | rb.Push(RESULT_SUCCESS); | 316 | rb.Push(RESULT_SUCCESS); |
| 435 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 317 | LOG_DEBUG(Service_HID, "called"); |
| 436 | } | 318 | } |
| 437 | 319 | ||
| 438 | void ActivateMouse(Kernel::HLERequestContext& ctx) { | 320 | void ActivateMouse(Kernel::HLERequestContext& ctx) { |
| 321 | applet_resource->ActivateController(HidController::Mouse); | ||
| 439 | IPC::ResponseBuilder rb{ctx, 2}; | 322 | IPC::ResponseBuilder rb{ctx, 2}; |
| 440 | rb.Push(RESULT_SUCCESS); | 323 | rb.Push(RESULT_SUCCESS); |
| 441 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 324 | LOG_DEBUG(Service_HID, "called"); |
| 442 | } | 325 | } |
| 443 | 326 | ||
| 444 | void ActivateKeyboard(Kernel::HLERequestContext& ctx) { | 327 | void ActivateKeyboard(Kernel::HLERequestContext& ctx) { |
| 328 | applet_resource->ActivateController(HidController::Keyboard); | ||
| 445 | IPC::ResponseBuilder rb{ctx, 2}; | 329 | IPC::ResponseBuilder rb{ctx, 2}; |
| 446 | rb.Push(RESULT_SUCCESS); | 330 | rb.Push(RESULT_SUCCESS); |
| 447 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 331 | LOG_DEBUG(Service_HID, "called"); |
| 332 | } | ||
| 333 | |||
| 334 | void ActivateGesture(Kernel::HLERequestContext& ctx) { | ||
| 335 | applet_resource->ActivateController(HidController::Gesture); | ||
| 336 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 337 | rb.Push(RESULT_SUCCESS); | ||
| 338 | LOG_DEBUG(Service_HID, "called"); | ||
| 339 | } | ||
| 340 | |||
| 341 | void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { | ||
| 342 | // Should have no effect with how our npad sets up the data | ||
| 343 | applet_resource->ActivateController(HidController::NPad); | ||
| 344 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 345 | rb.Push(RESULT_SUCCESS); | ||
| 346 | LOG_DEBUG(Service_HID, "called"); | ||
| 448 | } | 347 | } |
| 449 | 348 | ||
| 450 | void StartSixAxisSensor(Kernel::HLERequestContext& ctx) { | 349 | void StartSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 350 | IPC::RequestParser rp{ctx}; | ||
| 351 | auto handle = rp.PopRaw<u32>(); | ||
| 451 | IPC::ResponseBuilder rb{ctx, 2}; | 352 | IPC::ResponseBuilder rb{ctx, 2}; |
| 452 | rb.Push(RESULT_SUCCESS); | 353 | rb.Push(RESULT_SUCCESS); |
| 453 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 354 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| @@ -468,84 +369,168 @@ private: | |||
| 468 | } | 369 | } |
| 469 | 370 | ||
| 470 | void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { | 371 | void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { |
| 372 | IPC::RequestParser rp{ctx}; | ||
| 373 | auto supported_styleset = rp.PopRaw<u32>(); | ||
| 374 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||
| 375 | .SetSupportedStyleSet({supported_styleset}); | ||
| 376 | |||
| 471 | IPC::ResponseBuilder rb{ctx, 2}; | 377 | IPC::ResponseBuilder rb{ctx, 2}; |
| 472 | rb.Push(RESULT_SUCCESS); | 378 | rb.Push(RESULT_SUCCESS); |
| 473 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 379 | |
| 380 | LOG_DEBUG(Service_HID, "called"); | ||
| 474 | } | 381 | } |
| 475 | 382 | ||
| 476 | void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { | 383 | void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { |
| 384 | auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); | ||
| 385 | |||
| 477 | IPC::ResponseBuilder rb{ctx, 3}; | 386 | IPC::ResponseBuilder rb{ctx, 3}; |
| 478 | rb.Push(RESULT_SUCCESS); | 387 | rb.Push(RESULT_SUCCESS); |
| 479 | rb.Push<u32>(0); | 388 | rb.Push<u32>(controller.GetSupportedStyleSet().raw); |
| 480 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 389 | LOG_DEBUG(Service_HID, "called"); |
| 481 | } | 390 | } |
| 482 | 391 | ||
| 483 | void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { | 392 | void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { |
| 393 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||
| 394 | .SetSupportedNPadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize()); | ||
| 484 | IPC::ResponseBuilder rb{ctx, 2}; | 395 | IPC::ResponseBuilder rb{ctx, 2}; |
| 485 | rb.Push(RESULT_SUCCESS); | 396 | rb.Push(RESULT_SUCCESS); |
| 486 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 397 | LOG_DEBUG(Service_HID, "called"); |
| 487 | } | 398 | } |
| 488 | 399 | ||
| 489 | void ActivateNpad(Kernel::HLERequestContext& ctx) { | 400 | void ActivateNpad(Kernel::HLERequestContext& ctx) { |
| 490 | IPC::ResponseBuilder rb{ctx, 2}; | 401 | IPC::ResponseBuilder rb{ctx, 2}; |
| 491 | rb.Push(RESULT_SUCCESS); | 402 | rb.Push(RESULT_SUCCESS); |
| 492 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 403 | applet_resource->ActivateController(HidController::NPad); |
| 404 | LOG_DEBUG(Service_HID, "called"); | ||
| 493 | } | 405 | } |
| 494 | 406 | ||
| 495 | void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { | 407 | void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { |
| 408 | IPC::RequestParser rp{ctx}; | ||
| 409 | auto npad_id = rp.PopRaw<u32>(); | ||
| 496 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 410 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 497 | rb.Push(RESULT_SUCCESS); | 411 | rb.Push(RESULT_SUCCESS); |
| 498 | rb.PushCopyObjects(event); | 412 | rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 499 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 413 | .GetStyleSetChangedEvent()); |
| 414 | LOG_DEBUG(Service_HID, "called"); | ||
| 500 | } | 415 | } |
| 501 | 416 | ||
| 502 | void DisconnectNpad(Kernel::HLERequestContext& ctx) { | 417 | void DisconnectNpad(Kernel::HLERequestContext& ctx) { |
| 418 | IPC::RequestParser rp{ctx}; | ||
| 419 | auto npad_id = rp.PopRaw<u32>(); | ||
| 420 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||
| 421 | .DisconnectNPad(npad_id); | ||
| 503 | IPC::ResponseBuilder rb{ctx, 2}; | 422 | IPC::ResponseBuilder rb{ctx, 2}; |
| 504 | rb.Push(RESULT_SUCCESS); | 423 | rb.Push(RESULT_SUCCESS); |
| 505 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 424 | LOG_DEBUG(Service_HID, "called"); |
| 506 | } | 425 | } |
| 507 | 426 | ||
| 508 | void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { | 427 | void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { |
| 509 | IPC::ResponseBuilder rb{ctx, 2}; | 428 | IPC::RequestParser rp{ctx}; |
| 429 | auto npad_id = rp.PopRaw<u32>(); | ||
| 430 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 510 | rb.Push(RESULT_SUCCESS); | 431 | rb.Push(RESULT_SUCCESS); |
| 511 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 432 | rb.PushRaw<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 433 | .GetLedPattern(npad_id) | ||
| 434 | .raw); | ||
| 435 | LOG_DEBUG(Service_HID, "called"); | ||
| 512 | } | 436 | } |
| 513 | 437 | ||
| 514 | void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { | 438 | void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { |
| 439 | auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); | ||
| 440 | IPC::RequestParser rp{ctx}; | ||
| 441 | const auto hold_type = rp.PopRaw<u64>(); | ||
| 442 | controller.SetHoldType(Controller_NPad::NpadHoldType{hold_type}); | ||
| 443 | |||
| 515 | IPC::ResponseBuilder rb{ctx, 2}; | 444 | IPC::ResponseBuilder rb{ctx, 2}; |
| 516 | rb.Push(RESULT_SUCCESS); | 445 | rb.Push(RESULT_SUCCESS); |
| 517 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 446 | LOG_DEBUG(Service_HID, "called"); |
| 518 | } | 447 | } |
| 519 | 448 | ||
| 520 | void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { | 449 | void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { |
| 521 | IPC::ResponseBuilder rb{ctx, 3}; | 450 | const auto& controller = |
| 451 | applet_resource->GetController<Controller_NPad>(HidController::NPad); | ||
| 452 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 522 | rb.Push(RESULT_SUCCESS); | 453 | rb.Push(RESULT_SUCCESS); |
| 523 | rb.Push(joy_hold_type); | 454 | rb.Push<u64>(static_cast<u64>(controller.GetHoldType())); |
| 524 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 455 | LOG_DEBUG(Service_HID, "called"); |
| 525 | } | 456 | } |
| 526 | 457 | ||
| 527 | void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { | 458 | void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { |
| 459 | IPC::RequestParser rp{ctx}; | ||
| 460 | auto npad_id = rp.PopRaw<u32>(); | ||
| 528 | IPC::ResponseBuilder rb{ctx, 2}; | 461 | IPC::ResponseBuilder rb{ctx, 2}; |
| 529 | rb.Push(RESULT_SUCCESS); | 462 | rb.Push(RESULT_SUCCESS); |
| 530 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 463 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 531 | } | 464 | } |
| 532 | 465 | ||
| 466 | void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) { | ||
| 467 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||
| 468 | .SetVibrationEnabled(true); | ||
| 469 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 470 | rb.Push(RESULT_SUCCESS); | ||
| 471 | LOG_DEBUG(Service_HID, "called"); | ||
| 472 | } | ||
| 473 | |||
| 474 | void EndPermitVibrationSession(Kernel::HLERequestContext& ctx) { | ||
| 475 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||
| 476 | .SetVibrationEnabled(false); | ||
| 477 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 478 | rb.Push(RESULT_SUCCESS); | ||
| 479 | LOG_DEBUG(Service_HID, "called"); | ||
| 480 | } | ||
| 481 | |||
| 533 | void SendVibrationValue(Kernel::HLERequestContext& ctx) { | 482 | void SendVibrationValue(Kernel::HLERequestContext& ctx) { |
| 483 | IPC::RequestParser rp{ctx}; | ||
| 484 | const auto controller_id = rp.PopRaw<u32>(); | ||
| 485 | const auto vibration_values = rp.PopRaw<Controller_NPad::Vibration>(); | ||
| 486 | |||
| 534 | IPC::ResponseBuilder rb{ctx, 2}; | 487 | IPC::ResponseBuilder rb{ctx, 2}; |
| 535 | rb.Push(RESULT_SUCCESS); | 488 | rb.Push(RESULT_SUCCESS); |
| 536 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 489 | |
| 490 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||
| 491 | .VibrateController({controller_id}, {vibration_values}); | ||
| 492 | LOG_DEBUG(Service_HID, "called"); | ||
| 537 | } | 493 | } |
| 538 | 494 | ||
| 539 | void GetActualVibrationValue(Kernel::HLERequestContext& ctx) { | 495 | void SendVibrationValues(Kernel::HLERequestContext& ctx) { |
| 496 | const auto controllers = ctx.ReadBuffer(0); | ||
| 497 | const auto vibrations = ctx.ReadBuffer(1); | ||
| 498 | |||
| 499 | std::vector<u32> controller_list(controllers.size() / sizeof(u32)); | ||
| 500 | std::vector<Controller_NPad::Vibration> vibration_list(vibrations.size() / | ||
| 501 | sizeof(Controller_NPad::Vibration)); | ||
| 502 | |||
| 503 | std::memcpy(controller_list.data(), controllers.data(), controllers.size()); | ||
| 504 | std::memcpy(vibration_list.data(), vibrations.data(), vibrations.size()); | ||
| 505 | std::transform(controller_list.begin(), controller_list.end(), controller_list.begin(), | ||
| 506 | [](u32 controller_id) { return controller_id - 3; }); | ||
| 507 | |||
| 508 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||
| 509 | .VibrateController(controller_list, vibration_list); | ||
| 510 | |||
| 540 | IPC::ResponseBuilder rb{ctx, 2}; | 511 | IPC::ResponseBuilder rb{ctx, 2}; |
| 541 | rb.Push(RESULT_SUCCESS); | 512 | rb.Push(RESULT_SUCCESS); |
| 542 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 513 | LOG_DEBUG(Service_HID, "called"); |
| 514 | } | ||
| 515 | |||
| 516 | void GetActualVibrationValue(Kernel::HLERequestContext& ctx) { | ||
| 517 | IPC::ResponseBuilder rb{ctx, 6}; | ||
| 518 | rb.Push(RESULT_SUCCESS); | ||
| 519 | rb.PushRaw<Controller_NPad::Vibration>( | ||
| 520 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||
| 521 | .GetLastVibration()); | ||
| 522 | LOG_DEBUG(Service_HID, "called"); | ||
| 543 | } | 523 | } |
| 544 | 524 | ||
| 545 | void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { | 525 | void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { |
| 526 | IPC::RequestParser rp{ctx}; | ||
| 527 | const auto npad_id = rp.PopRaw<u32>(); | ||
| 528 | auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); | ||
| 529 | controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual); | ||
| 530 | |||
| 546 | IPC::ResponseBuilder rb{ctx, 2}; | 531 | IPC::ResponseBuilder rb{ctx, 2}; |
| 547 | rb.Push(RESULT_SUCCESS); | 532 | rb.Push(RESULT_SUCCESS); |
| 548 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 533 | LOG_DEBUG(Service_HID, "called"); |
| 549 | } | 534 | } |
| 550 | 535 | ||
| 551 | void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { | 536 | void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { |
| @@ -555,6 +540,8 @@ private: | |||
| 555 | } | 540 | } |
| 556 | 541 | ||
| 557 | void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { | 542 | void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { |
| 543 | IPC::RequestParser rp{ctx}; | ||
| 544 | auto mode = rp.PopRaw<u32>(); | ||
| 558 | IPC::ResponseBuilder rb{ctx, 2}; | 545 | IPC::ResponseBuilder rb{ctx, 2}; |
| 559 | rb.Push(RESULT_SUCCESS); | 546 | rb.Push(RESULT_SUCCESS); |
| 560 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 547 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| @@ -563,8 +550,9 @@ private: | |||
| 563 | void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { | 550 | void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { |
| 564 | IPC::ResponseBuilder rb{ctx, 4}; | 551 | IPC::ResponseBuilder rb{ctx, 4}; |
| 565 | rb.Push(RESULT_SUCCESS); | 552 | rb.Push(RESULT_SUCCESS); |
| 566 | rb.Push<u64>(0); | 553 | rb.Push<u32>(1); |
| 567 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 554 | rb.Push<u32>(0); |
| 555 | LOG_DEBUG(Service_HID, "called"); | ||
| 568 | } | 556 | } |
| 569 | 557 | ||
| 570 | void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) { | 558 | void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) { |
| @@ -574,12 +562,6 @@ private: | |||
| 574 | LOG_DEBUG(Service_HID, "called"); | 562 | LOG_DEBUG(Service_HID, "called"); |
| 575 | } | 563 | } |
| 576 | 564 | ||
| 577 | void SendVibrationValues(Kernel::HLERequestContext& ctx) { | ||
| 578 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 579 | rb.Push(RESULT_SUCCESS); | ||
| 580 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 581 | } | ||
| 582 | |||
| 583 | void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { | 565 | void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 584 | IPC::ResponseBuilder rb{ctx, 2}; | 566 | IPC::ResponseBuilder rb{ctx, 2}; |
| 585 | rb.Push(RESULT_SUCCESS); | 567 | rb.Push(RESULT_SUCCESS); |
| @@ -597,18 +579,6 @@ private: | |||
| 597 | rb.Push(RESULT_SUCCESS); | 579 | rb.Push(RESULT_SUCCESS); |
| 598 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 580 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 599 | } | 581 | } |
| 600 | |||
| 601 | void ActivateGesture(Kernel::HLERequestContext& ctx) { | ||
| 602 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 603 | rb.Push(RESULT_SUCCESS); | ||
| 604 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 605 | } | ||
| 606 | |||
| 607 | void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { | ||
| 608 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 609 | rb.Push(RESULT_SUCCESS); | ||
| 610 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 611 | } | ||
| 612 | }; | 582 | }; |
| 613 | 583 | ||
| 614 | class HidDbg final : public ServiceFramework<HidDbg> { | 584 | 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 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | 7 | namespace SM { |
| 8 | #include "common/bit_field.h" | 8 | class ServiceManager; |
| 9 | #include "common/common_types.h" | 9 | } |
| 10 | #include "core/hle/service/service.h" | ||
| 11 | 10 | ||
| 12 | namespace Service::HID { | 11 | namespace Service::HID { |
| 13 | 12 | ||
| 14 | // Begin enums and output structs | ||
| 15 | |||
| 16 | constexpr u32 HID_NUM_ENTRIES = 17; | ||
| 17 | constexpr u32 HID_NUM_LAYOUTS = 7; | ||
| 18 | constexpr s32 HID_JOYSTICK_MAX = 0x8000; | ||
| 19 | constexpr s32 HID_JOYSTICK_MIN = -0x8000; | ||
| 20 | |||
| 21 | constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28; | ||
| 22 | constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A; | ||
| 23 | constexpr u32 JOYCON_BODY_NEON_BLUE = 0x0AB9E6; | ||
| 24 | constexpr u32 JOYCON_BUTTONS_NEON_BLUE = 0x001E1E; | ||
| 25 | |||
| 26 | enum ControllerType : u32 { | ||
| 27 | ControllerType_ProController = 1 << 0, | ||
| 28 | ControllerType_Handheld = 1 << 1, | ||
| 29 | ControllerType_JoyconPair = 1 << 2, | ||
| 30 | ControllerType_JoyconLeft = 1 << 3, | ||
| 31 | ControllerType_JoyconRight = 1 << 4, | ||
| 32 | }; | ||
| 33 | |||
| 34 | enum ControllerLayoutType : u32 { | ||
| 35 | Layout_ProController = 0, // Pro Controller or HID gamepad | ||
| 36 | Layout_Handheld = 1, // Two Joy-Con docked to rails | ||
| 37 | Layout_Single = 2, // Horizontal single Joy-Con or pair of Joy-Con, adjusted for orientation | ||
| 38 | Layout_Left = 3, // Only raw left Joy-Con state, no orientation adjustment | ||
| 39 | Layout_Right = 4, // Only raw right Joy-Con state, no orientation adjustment | ||
| 40 | Layout_DefaultDigital = 5, // Same as next, but sticks have 8-direction values only | ||
| 41 | Layout_Default = 6, // Safe default, single Joy-Con have buttons/sticks rotated for orientation | ||
| 42 | }; | ||
| 43 | |||
| 44 | enum ControllerColorDescription { | ||
| 45 | ColorDesc_ColorsNonexistent = 1 << 1, | ||
| 46 | }; | ||
| 47 | |||
| 48 | enum ControllerConnectionState { | ||
| 49 | ConnectionState_Connected = 1 << 0, | ||
| 50 | ConnectionState_Wired = 1 << 1, | ||
| 51 | }; | ||
| 52 | |||
| 53 | enum ControllerJoystick { | ||
| 54 | Joystick_Left = 0, | ||
| 55 | Joystick_Right = 1, | ||
| 56 | }; | ||
| 57 | |||
| 58 | enum ControllerID { | ||
| 59 | Controller_Player1 = 0, | ||
| 60 | Controller_Player2 = 1, | ||
| 61 | Controller_Player3 = 2, | ||
| 62 | Controller_Player4 = 3, | ||
| 63 | Controller_Player5 = 4, | ||
| 64 | Controller_Player6 = 5, | ||
| 65 | Controller_Player7 = 6, | ||
| 66 | Controller_Player8 = 7, | ||
| 67 | Controller_Handheld = 8, | ||
| 68 | Controller_Unknown = 9, | ||
| 69 | }; | ||
| 70 | |||
| 71 | // End enums and output structs | ||
| 72 | |||
| 73 | // Begin UnkInput3 | ||
| 74 | |||
| 75 | struct UnkInput3Header { | ||
| 76 | u64 timestamp_ticks; | ||
| 77 | u64 num_entries; | ||
| 78 | u64 latest_entry; | ||
| 79 | u64 max_entry_index; | ||
| 80 | }; | ||
| 81 | static_assert(sizeof(UnkInput3Header) == 0x20, "HID UnkInput3 header structure has incorrect size"); | ||
| 82 | |||
| 83 | struct UnkInput3Entry { | ||
| 84 | u64 timestamp; | ||
| 85 | u64 timestamp_2; | ||
| 86 | u64 unk_8; | ||
| 87 | u64 unk_10; | ||
| 88 | u64 unk_18; | ||
| 89 | }; | ||
| 90 | static_assert(sizeof(UnkInput3Entry) == 0x28, "HID UnkInput3 entry structure has incorrect size"); | ||
| 91 | |||
| 92 | struct UnkInput3 { | ||
| 93 | UnkInput3Header header; | ||
| 94 | std::array<UnkInput3Entry, 17> entries; | ||
| 95 | std::array<u8, 0x138> padding; | ||
| 96 | }; | ||
| 97 | static_assert(sizeof(UnkInput3) == 0x400, "HID UnkInput3 structure has incorrect size"); | ||
| 98 | |||
| 99 | // End UnkInput3 | ||
| 100 | |||
| 101 | // Begin TouchScreen | ||
| 102 | |||
| 103 | struct TouchScreenHeader { | ||
| 104 | u64 timestamp_ticks; | ||
| 105 | u64 num_entries; | ||
| 106 | u64 latest_entry; | ||
| 107 | u64 max_entry_index; | ||
| 108 | u64 timestamp; | ||
| 109 | }; | ||
| 110 | static_assert(sizeof(TouchScreenHeader) == 0x28, | ||
| 111 | "HID touch screen header structure has incorrect size"); | ||
| 112 | |||
| 113 | struct TouchScreenEntryHeader { | ||
| 114 | u64 timestamp; | ||
| 115 | u64 num_touches; | ||
| 116 | }; | ||
| 117 | static_assert(sizeof(TouchScreenEntryHeader) == 0x10, | ||
| 118 | "HID touch screen entry header structure has incorrect size"); | ||
| 119 | |||
| 120 | struct TouchScreenEntryTouch { | ||
| 121 | u64 timestamp; | ||
| 122 | u32 padding; | ||
| 123 | u32 touch_index; | ||
| 124 | u32 x; | ||
| 125 | u32 y; | ||
| 126 | u32 diameter_x; | ||
| 127 | u32 diameter_y; | ||
| 128 | u32 angle; | ||
| 129 | u32 padding_2; | ||
| 130 | }; | ||
| 131 | static_assert(sizeof(TouchScreenEntryTouch) == 0x28, | ||
| 132 | "HID touch screen touch structure has incorrect size"); | ||
| 133 | |||
| 134 | struct TouchScreenEntry { | ||
| 135 | TouchScreenEntryHeader header; | ||
| 136 | std::array<TouchScreenEntryTouch, 16> touches; | ||
| 137 | u64 unk; | ||
| 138 | }; | ||
| 139 | static_assert(sizeof(TouchScreenEntry) == 0x298, | ||
| 140 | "HID touch screen entry structure has incorrect size"); | ||
| 141 | |||
| 142 | struct TouchScreen { | ||
| 143 | TouchScreenHeader header; | ||
| 144 | std::array<TouchScreenEntry, 17> entries; | ||
| 145 | std::array<u8, 0x3c0> padding; | ||
| 146 | }; | ||
| 147 | static_assert(sizeof(TouchScreen) == 0x3000, "HID touch screen structure has incorrect size"); | ||
| 148 | |||
| 149 | // End TouchScreen | ||
| 150 | |||
| 151 | // Begin Mouse | ||
| 152 | |||
| 153 | struct MouseHeader { | ||
| 154 | u64 timestamp_ticks; | ||
| 155 | u64 num_entries; | ||
| 156 | u64 latest_entry; | ||
| 157 | u64 max_entry_index; | ||
| 158 | }; | ||
| 159 | static_assert(sizeof(MouseHeader) == 0x20, "HID mouse header structure has incorrect size"); | ||
| 160 | |||
| 161 | struct MouseButtonState { | ||
| 162 | union { | ||
| 163 | u64 hex{}; | ||
| 164 | |||
| 165 | // Buttons | ||
| 166 | BitField<0, 1, u64> left; | ||
| 167 | BitField<1, 1, u64> right; | ||
| 168 | BitField<2, 1, u64> middle; | ||
| 169 | BitField<3, 1, u64> forward; | ||
| 170 | BitField<4, 1, u64> back; | ||
| 171 | }; | ||
| 172 | }; | ||
| 173 | |||
| 174 | struct MouseEntry { | ||
| 175 | u64 timestamp; | ||
| 176 | u64 timestamp_2; | ||
| 177 | u32 x; | ||
| 178 | u32 y; | ||
| 179 | u32 velocity_x; | ||
| 180 | u32 velocity_y; | ||
| 181 | u32 scroll_velocity_x; | ||
| 182 | u32 scroll_velocity_y; | ||
| 183 | MouseButtonState buttons; | ||
| 184 | }; | ||
| 185 | static_assert(sizeof(MouseEntry) == 0x30, "HID mouse entry structure has incorrect size"); | ||
| 186 | |||
| 187 | struct Mouse { | ||
| 188 | MouseHeader header; | ||
| 189 | std::array<MouseEntry, 17> entries; | ||
| 190 | std::array<u8, 0xB0> padding; | ||
| 191 | }; | ||
| 192 | static_assert(sizeof(Mouse) == 0x400, "HID mouse structure has incorrect size"); | ||
| 193 | |||
| 194 | // End Mouse | ||
| 195 | |||
| 196 | // Begin Keyboard | ||
| 197 | |||
| 198 | struct KeyboardHeader { | ||
| 199 | u64 timestamp_ticks; | ||
| 200 | u64 num_entries; | ||
| 201 | u64 latest_entry; | ||
| 202 | u64 max_entry_index; | ||
| 203 | }; | ||
| 204 | static_assert(sizeof(KeyboardHeader) == 0x20, "HID keyboard header structure has incorrect size"); | ||
| 205 | |||
| 206 | struct KeyboardModifierKeyState { | ||
| 207 | union { | ||
| 208 | u64 hex{}; | ||
| 209 | |||
| 210 | // Buttons | ||
| 211 | BitField<0, 1, u64> lctrl; | ||
| 212 | BitField<1, 1, u64> lshift; | ||
| 213 | BitField<2, 1, u64> lalt; | ||
| 214 | BitField<3, 1, u64> lmeta; | ||
| 215 | BitField<4, 1, u64> rctrl; | ||
| 216 | BitField<5, 1, u64> rshift; | ||
| 217 | BitField<6, 1, u64> ralt; | ||
| 218 | BitField<7, 1, u64> rmeta; | ||
| 219 | BitField<8, 1, u64> capslock; | ||
| 220 | BitField<9, 1, u64> scrolllock; | ||
| 221 | BitField<10, 1, u64> numlock; | ||
| 222 | }; | ||
| 223 | }; | ||
| 224 | |||
| 225 | struct KeyboardEntry { | ||
| 226 | u64 timestamp; | ||
| 227 | u64 timestamp_2; | ||
| 228 | KeyboardModifierKeyState modifier; | ||
| 229 | u32 keys[8]; | ||
| 230 | }; | ||
| 231 | static_assert(sizeof(KeyboardEntry) == 0x38, "HID keyboard entry structure has incorrect size"); | ||
| 232 | |||
| 233 | struct Keyboard { | ||
| 234 | KeyboardHeader header; | ||
| 235 | std::array<KeyboardEntry, 17> entries; | ||
| 236 | std::array<u8, 0x28> padding; | ||
| 237 | }; | ||
| 238 | static_assert(sizeof(Keyboard) == 0x400, "HID keyboard structure has incorrect size"); | ||
| 239 | |||
| 240 | // End Keyboard | ||
| 241 | |||
| 242 | // Begin UnkInput1 | ||
| 243 | |||
| 244 | struct UnkInput1Header { | ||
| 245 | u64 timestamp_ticks; | ||
| 246 | u64 num_entries; | ||
| 247 | u64 latest_entry; | ||
| 248 | u64 max_entry_index; | ||
| 249 | }; | ||
| 250 | static_assert(sizeof(UnkInput1Header) == 0x20, "HID UnkInput1 header structure has incorrect size"); | ||
| 251 | |||
| 252 | struct UnkInput1Entry { | ||
| 253 | u64 timestamp; | ||
| 254 | u64 timestamp_2; | ||
| 255 | u64 unk_8; | ||
| 256 | u64 unk_10; | ||
| 257 | u64 unk_18; | ||
| 258 | }; | ||
| 259 | static_assert(sizeof(UnkInput1Entry) == 0x28, "HID UnkInput1 entry structure has incorrect size"); | ||
| 260 | |||
| 261 | struct UnkInput1 { | ||
| 262 | UnkInput1Header header; | ||
| 263 | std::array<UnkInput1Entry, 17> entries; | ||
| 264 | std::array<u8, 0x138> padding; | ||
| 265 | }; | ||
| 266 | static_assert(sizeof(UnkInput1) == 0x400, "HID UnkInput1 structure has incorrect size"); | ||
| 267 | |||
| 268 | // End UnkInput1 | ||
| 269 | |||
| 270 | // Begin UnkInput2 | ||
| 271 | |||
| 272 | struct UnkInput2Header { | ||
| 273 | u64 timestamp_ticks; | ||
| 274 | u64 num_entries; | ||
| 275 | u64 latest_entry; | ||
| 276 | u64 max_entry_index; | ||
| 277 | }; | ||
| 278 | static_assert(sizeof(UnkInput2Header) == 0x20, "HID UnkInput2 header structure has incorrect size"); | ||
| 279 | |||
| 280 | struct UnkInput2 { | ||
| 281 | UnkInput2Header header; | ||
| 282 | std::array<u8, 0x1E0> padding; | ||
| 283 | }; | ||
| 284 | static_assert(sizeof(UnkInput2) == 0x200, "HID UnkInput2 structure has incorrect size"); | ||
| 285 | |||
| 286 | // End UnkInput2 | ||
| 287 | |||
| 288 | // Begin Controller | ||
| 289 | |||
| 290 | struct ControllerMAC { | ||
| 291 | u64 timestamp; | ||
| 292 | std::array<u8, 0x8> mac; | ||
| 293 | u64 unk; | ||
| 294 | u64 timestamp_2; | ||
| 295 | }; | ||
| 296 | static_assert(sizeof(ControllerMAC) == 0x20, "HID controller MAC structure has incorrect size"); | ||
| 297 | |||
| 298 | struct ControllerHeader { | ||
| 299 | u32 type; | ||
| 300 | u32 is_half; | ||
| 301 | u32 single_colors_descriptor; | ||
| 302 | u32 single_color_body; | ||
| 303 | u32 single_color_buttons; | ||
| 304 | u32 split_colors_descriptor; | ||
| 305 | u32 left_color_body; | ||
| 306 | u32 left_color_buttons; | ||
| 307 | u32 right_color_body; | ||
| 308 | u32 right_color_buttons; | ||
| 309 | }; | ||
| 310 | static_assert(sizeof(ControllerHeader) == 0x28, | ||
| 311 | "HID controller header structure has incorrect size"); | ||
| 312 | |||
| 313 | struct ControllerLayoutHeader { | ||
| 314 | u64 timestamp_ticks; | ||
| 315 | u64 num_entries; | ||
| 316 | u64 latest_entry; | ||
| 317 | u64 max_entry_index; | ||
| 318 | }; | ||
| 319 | static_assert(sizeof(ControllerLayoutHeader) == 0x20, | ||
| 320 | "HID controller layout header structure has incorrect size"); | ||
| 321 | |||
| 322 | struct ControllerPadState { | ||
| 323 | union { | ||
| 324 | u64 hex{}; | ||
| 325 | |||
| 326 | // Buttons | ||
| 327 | BitField<0, 1, u64> a; | ||
| 328 | BitField<1, 1, u64> b; | ||
| 329 | BitField<2, 1, u64> x; | ||
| 330 | BitField<3, 1, u64> y; | ||
| 331 | BitField<4, 1, u64> lstick; | ||
| 332 | BitField<5, 1, u64> rstick; | ||
| 333 | BitField<6, 1, u64> l; | ||
| 334 | BitField<7, 1, u64> r; | ||
| 335 | BitField<8, 1, u64> zl; | ||
| 336 | BitField<9, 1, u64> zr; | ||
| 337 | BitField<10, 1, u64> plus; | ||
| 338 | BitField<11, 1, u64> minus; | ||
| 339 | |||
| 340 | // D-pad buttons | ||
| 341 | BitField<12, 1, u64> dleft; | ||
| 342 | BitField<13, 1, u64> dup; | ||
| 343 | BitField<14, 1, u64> dright; | ||
| 344 | BitField<15, 1, u64> ddown; | ||
| 345 | |||
| 346 | // Left stick directions | ||
| 347 | BitField<16, 1, u64> lstick_left; | ||
| 348 | BitField<17, 1, u64> lstick_up; | ||
| 349 | BitField<18, 1, u64> lstick_right; | ||
| 350 | BitField<19, 1, u64> lstick_down; | ||
| 351 | |||
| 352 | // Right stick directions | ||
| 353 | BitField<20, 1, u64> rstick_left; | ||
| 354 | BitField<21, 1, u64> rstick_up; | ||
| 355 | BitField<22, 1, u64> rstick_right; | ||
| 356 | BitField<23, 1, u64> rstick_down; | ||
| 357 | |||
| 358 | BitField<24, 1, u64> sl; | ||
| 359 | BitField<25, 1, u64> sr; | ||
| 360 | }; | ||
| 361 | }; | ||
| 362 | |||
| 363 | struct ControllerInputEntry { | ||
| 364 | u64 timestamp; | ||
| 365 | u64 timestamp_2; | ||
| 366 | ControllerPadState buttons; | ||
| 367 | s32 joystick_left_x; | ||
| 368 | s32 joystick_left_y; | ||
| 369 | s32 joystick_right_x; | ||
| 370 | s32 joystick_right_y; | ||
| 371 | u64 connection_state; | ||
| 372 | }; | ||
| 373 | static_assert(sizeof(ControllerInputEntry) == 0x30, | ||
| 374 | "HID controller input entry structure has incorrect size"); | ||
| 375 | |||
| 376 | struct ControllerLayout { | ||
| 377 | ControllerLayoutHeader header; | ||
| 378 | std::array<ControllerInputEntry, 17> entries; | ||
| 379 | }; | ||
| 380 | static_assert(sizeof(ControllerLayout) == 0x350, | ||
| 381 | "HID controller layout structure has incorrect size"); | ||
| 382 | |||
| 383 | struct Controller { | ||
| 384 | ControllerHeader header; | ||
| 385 | std::array<ControllerLayout, HID_NUM_LAYOUTS> layouts; | ||
| 386 | std::array<u8, 0x2a70> unk_1; | ||
| 387 | ControllerMAC mac_left; | ||
| 388 | ControllerMAC mac_right; | ||
| 389 | std::array<u8, 0xdf8> unk_2; | ||
| 390 | }; | ||
| 391 | static_assert(sizeof(Controller) == 0x5000, "HID controller structure has incorrect size"); | ||
| 392 | |||
| 393 | // End Controller | ||
| 394 | |||
| 395 | struct SharedMemory { | ||
| 396 | UnkInput3 unk_input_3; | ||
| 397 | TouchScreen touchscreen; | ||
| 398 | Mouse mouse; | ||
| 399 | Keyboard keyboard; | ||
| 400 | std::array<UnkInput1, 4> unk_input_1; | ||
| 401 | std::array<UnkInput2, 3> unk_input_2; | ||
| 402 | std::array<u8, 0x800> unk_section_8; | ||
| 403 | std::array<u8, 0x4000> controller_serials; | ||
| 404 | std::array<Controller, 10> controllers; | ||
| 405 | std::array<u8, 0x4600> unk_section_9; | ||
| 406 | }; | ||
| 407 | static_assert(sizeof(SharedMemory) == 0x40000, "HID Shared Memory structure has incorrect size"); | ||
| 408 | |||
| 409 | /// Reload input devices. Used when input configuration changed | 13 | /// Reload input devices. Used when input configuration changed |
| 410 | void ReloadInputDevices(); | 14 | void ReloadInputDevices(); |
| 411 | 15 | ||
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: | |||
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | const u64 device_handle{0xDEAD}; | 146 | const u64 device_handle{0xDEAD}; |
| 147 | const HID::ControllerID npad_id{HID::Controller_Player1}; | 147 | const u32 npad_id{0}; // This is the first player controller id |
| 148 | State state{State::NonInitialized}; | 148 | State state{State::NonInitialized}; |
| 149 | DeviceState device_state{DeviceState::Initialized}; | 149 | DeviceState device_state{DeviceState::Initialized}; |
| 150 | Kernel::SharedPtr<Kernel::Event> activate_event; | 150 | Kernel::SharedPtr<Kernel::Event> activate_event; |