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