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