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