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
-
439src/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