hid_core: Move hid to it's own subproject
This commit is contained in:
parent
92a331af76
commit
ee847f8ff0
141 changed files with 479 additions and 436 deletions
|
@ -13,7 +13,6 @@
|
|||
#include "core/file_sys/patch_manager.h"
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "core/file_sys/savedata_factory.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_transfer_memory.h"
|
||||
#include "core/hle/result.h"
|
||||
|
@ -37,7 +36,6 @@
|
|||
#include "core/hle/service/caps/caps_su.h"
|
||||
#include "core/hle/service/caps/caps_types.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/hle/service/hid/controllers/npad.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/ns/ns.h"
|
||||
#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
|
||||
|
@ -48,6 +46,8 @@
|
|||
#include "core/hle/service/vi/vi.h"
|
||||
#include "core/hle/service/vi/vi_results.h"
|
||||
#include "core/memory.h"
|
||||
#include "hid_core/hid_types.h"
|
||||
#include "hid_core/resources/npad/npad.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
|
|
|
@ -5,13 +5,13 @@
|
|||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/frontend/applets/cabinet.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/applet_cabinet.h"
|
||||
#include "core/hle/service/mii/mii_manager.h"
|
||||
#include "core/hle/service/nfc/common/device.h"
|
||||
#include "hid_core/hid_core.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
|
||||
|
|
|
@ -9,13 +9,13 @@
|
|||
#include "common/string_util.h"
|
||||
#include "core/core.h"
|
||||
#include "core/frontend/applets/controller.h"
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/applet_controller.h"
|
||||
#include "core/hle/service/hid/controllers/npad.h"
|
||||
#include "hid_core/frontend/emulated_controller.h"
|
||||
#include "hid_core/hid_core.h"
|
||||
#include "hid_core/hid_types.h"
|
||||
#include "hid_core/resources/npad/npad.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
|
||||
|
|
|
@ -1,329 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/k_shared_memory.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
#include "core/hle/service/hid/errors.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
AppletResource::AppletResource(Core::System& system_) : system{system_} {}
|
||||
|
||||
AppletResource::~AppletResource() = default;
|
||||
|
||||
Result AppletResource::CreateAppletResource(u64 aruid) {
|
||||
const u64 index = GetIndexFromAruid(aruid);
|
||||
|
||||
if (index >= AruidIndexMax) {
|
||||
return ResultAruidNotRegistered;
|
||||
}
|
||||
|
||||
if (data[index].flag.is_assigned) {
|
||||
return ResultAruidAlreadyRegistered;
|
||||
}
|
||||
|
||||
auto& shared_memory = shared_memory_holder[index];
|
||||
if (!shared_memory.IsMapped()) {
|
||||
const Result result = shared_memory.Initialize(system);
|
||||
if (result.IsError()) {
|
||||
return result;
|
||||
}
|
||||
if (shared_memory.GetAddress() == nullptr) {
|
||||
shared_memory.Finalize();
|
||||
return ResultSharedMemoryNotInitialized;
|
||||
}
|
||||
}
|
||||
|
||||
auto* shared_memory_format = shared_memory.GetAddress();
|
||||
if (shared_memory_format != nullptr) {
|
||||
shared_memory_format->Initialize();
|
||||
}
|
||||
|
||||
data[index].shared_memory_format = shared_memory_format;
|
||||
data[index].flag.is_assigned.Assign(true);
|
||||
// TODO: InitializeSixAxisControllerConfig(false);
|
||||
active_aruid = aruid;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result AppletResource::RegisterAppletResourceUserId(u64 aruid, bool enable_input) {
|
||||
const u64 index = GetIndexFromAruid(aruid);
|
||||
|
||||
if (index < AruidIndexMax) {
|
||||
return ResultAruidAlreadyRegistered;
|
||||
}
|
||||
|
||||
std::size_t data_index = AruidIndexMax;
|
||||
for (std::size_t i = 0; i < AruidIndexMax; i++) {
|
||||
if (!data[i].flag.is_initialized) {
|
||||
data_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (data_index == AruidIndexMax) {
|
||||
return ResultAruidNoAvailableEntries;
|
||||
}
|
||||
|
||||
AruidData& aruid_data = data[data_index];
|
||||
|
||||
aruid_data.aruid = aruid;
|
||||
aruid_data.flag.is_initialized.Assign(true);
|
||||
if (enable_input) {
|
||||
aruid_data.flag.enable_pad_input.Assign(true);
|
||||
aruid_data.flag.enable_six_axis_sensor.Assign(true);
|
||||
aruid_data.flag.bit_18.Assign(true);
|
||||
aruid_data.flag.enable_touchscreen.Assign(true);
|
||||
}
|
||||
|
||||
data_index = AruidIndexMax;
|
||||
for (std::size_t i = 0; i < AruidIndexMax; i++) {
|
||||
if (registration_list.flag[i] == RegistrationStatus::Initialized) {
|
||||
if (registration_list.aruid[i] != aruid) {
|
||||
continue;
|
||||
}
|
||||
data_index = i;
|
||||
break;
|
||||
}
|
||||
if (registration_list.flag[i] == RegistrationStatus::None) {
|
||||
data_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (data_index == AruidIndexMax) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
registration_list.flag[data_index] = RegistrationStatus::Initialized;
|
||||
registration_list.aruid[data_index] = aruid;
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
void AppletResource::UnregisterAppletResourceUserId(u64 aruid) {
|
||||
u64 index = GetIndexFromAruid(aruid);
|
||||
|
||||
if (index < AruidIndexMax) {
|
||||
if (data[index].flag.is_assigned) {
|
||||
data[index].shared_memory_format = nullptr;
|
||||
data[index].flag.is_assigned.Assign(false);
|
||||
}
|
||||
}
|
||||
|
||||
index = GetIndexFromAruid(aruid);
|
||||
if (index < AruidIndexMax) {
|
||||
DestroySevenSixAxisTransferMemory();
|
||||
data[index].flag.raw = 0;
|
||||
data[index].aruid = 0;
|
||||
|
||||
index = GetIndexFromAruid(aruid);
|
||||
if (index < AruidIndexMax) {
|
||||
registration_list.flag[index] = RegistrationStatus::PendingDelete;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AppletResource::FreeAppletResourceId(u64 aruid) {
|
||||
u64 index = GetIndexFromAruid(aruid);
|
||||
if (index >= AruidIndexMax) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& aruid_data = data[index];
|
||||
if (aruid_data.flag.is_assigned) {
|
||||
aruid_data.shared_memory_format = nullptr;
|
||||
aruid_data.flag.is_assigned.Assign(false);
|
||||
}
|
||||
}
|
||||
|
||||
u64 AppletResource::GetActiveAruid() {
|
||||
return active_aruid;
|
||||
}
|
||||
|
||||
Result AppletResource::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid) {
|
||||
u64 index = GetIndexFromAruid(aruid);
|
||||
if (index >= AruidIndexMax) {
|
||||
return ResultAruidNotRegistered;
|
||||
}
|
||||
|
||||
*out_handle = shared_memory_holder[index].GetHandle();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result AppletResource::GetSharedMemoryFormat(SharedMemoryFormat** out_shared_memory_format,
|
||||
u64 aruid) {
|
||||
u64 index = GetIndexFromAruid(aruid);
|
||||
if (index >= AruidIndexMax) {
|
||||
return ResultAruidNotRegistered;
|
||||
}
|
||||
|
||||
*out_shared_memory_format = data[index].shared_memory_format;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
AruidData* AppletResource::GetAruidData(u64 aruid) {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index == AruidIndexMax) {
|
||||
return nullptr;
|
||||
}
|
||||
return &data[aruid_index];
|
||||
}
|
||||
|
||||
AruidData* AppletResource::GetAruidDataByIndex(std::size_t aruid_index) {
|
||||
return &data[aruid_index];
|
||||
}
|
||||
|
||||
bool AppletResource::IsVibrationAruidActive(u64 aruid) const {
|
||||
return aruid == 0 || aruid == active_vibration_aruid;
|
||||
}
|
||||
|
||||
u64 AppletResource::GetIndexFromAruid(u64 aruid) {
|
||||
for (std::size_t i = 0; i < AruidIndexMax; i++) {
|
||||
if (registration_list.flag[i] == RegistrationStatus::Initialized &&
|
||||
registration_list.aruid[i] == aruid) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return AruidIndexMax;
|
||||
}
|
||||
|
||||
Result AppletResource::DestroySevenSixAxisTransferMemory() {
|
||||
// TODO
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
void AppletResource::EnableInput(u64 aruid, bool is_enabled) {
|
||||
const u64 index = GetIndexFromAruid(aruid);
|
||||
if (index >= AruidIndexMax) {
|
||||
return;
|
||||
}
|
||||
|
||||
data[index].flag.enable_pad_input.Assign(is_enabled);
|
||||
data[index].flag.enable_touchscreen.Assign(is_enabled);
|
||||
}
|
||||
|
||||
void AppletResource::EnableSixAxisSensor(u64 aruid, bool is_enabled) {
|
||||
const u64 index = GetIndexFromAruid(aruid);
|
||||
if (index >= AruidIndexMax) {
|
||||
return;
|
||||
}
|
||||
|
||||
data[index].flag.enable_six_axis_sensor.Assign(is_enabled);
|
||||
}
|
||||
|
||||
void AppletResource::EnablePadInput(u64 aruid, bool is_enabled) {
|
||||
const u64 index = GetIndexFromAruid(aruid);
|
||||
if (index >= AruidIndexMax) {
|
||||
return;
|
||||
}
|
||||
|
||||
data[index].flag.enable_pad_input.Assign(is_enabled);
|
||||
}
|
||||
|
||||
void AppletResource::EnableTouchScreen(u64 aruid, bool is_enabled) {
|
||||
const u64 index = GetIndexFromAruid(aruid);
|
||||
if (index >= AruidIndexMax) {
|
||||
return;
|
||||
}
|
||||
|
||||
data[index].flag.enable_touchscreen.Assign(is_enabled);
|
||||
}
|
||||
|
||||
void AppletResource::SetIsPalmaConnectable(u64 aruid, bool is_connectable) {
|
||||
const u64 index = GetIndexFromAruid(aruid);
|
||||
if (index >= AruidIndexMax) {
|
||||
return;
|
||||
}
|
||||
|
||||
data[index].flag.is_palma_connectable.Assign(is_connectable);
|
||||
}
|
||||
|
||||
void AppletResource::EnablePalmaBoostMode(u64 aruid, bool is_enabled) {
|
||||
const u64 index = GetIndexFromAruid(aruid);
|
||||
if (index >= AruidIndexMax) {
|
||||
return;
|
||||
}
|
||||
|
||||
data[index].flag.enable_palma_boost_mode.Assign(is_enabled);
|
||||
}
|
||||
|
||||
Result AppletResource::RegisterCoreAppletResource() {
|
||||
if (ref_counter == std::numeric_limits<s32>::max() - 1) {
|
||||
return ResultAppletResourceOverflow;
|
||||
}
|
||||
if (ref_counter == 0) {
|
||||
const u64 index = GetIndexFromAruid(0);
|
||||
if (index < AruidIndexMax) {
|
||||
return ResultAruidAlreadyRegistered;
|
||||
}
|
||||
|
||||
std::size_t data_index = AruidIndexMax;
|
||||
for (std::size_t i = 0; i < AruidIndexMax; i++) {
|
||||
if (!data[i].flag.is_initialized) {
|
||||
data_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (data_index == AruidIndexMax) {
|
||||
return ResultAruidNoAvailableEntries;
|
||||
}
|
||||
|
||||
AruidData& aruid_data = data[data_index];
|
||||
|
||||
aruid_data.aruid = 0;
|
||||
aruid_data.flag.is_initialized.Assign(true);
|
||||
aruid_data.flag.enable_pad_input.Assign(true);
|
||||
aruid_data.flag.enable_six_axis_sensor.Assign(true);
|
||||
aruid_data.flag.bit_18.Assign(true);
|
||||
aruid_data.flag.enable_touchscreen.Assign(true);
|
||||
|
||||
data_index = AruidIndexMax;
|
||||
for (std::size_t i = 0; i < AruidIndexMax; i++) {
|
||||
if (registration_list.flag[i] == RegistrationStatus::Initialized) {
|
||||
if (registration_list.aruid[i] != 0) {
|
||||
continue;
|
||||
}
|
||||
data_index = i;
|
||||
break;
|
||||
}
|
||||
if (registration_list.flag[i] == RegistrationStatus::None) {
|
||||
data_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Result result = ResultSuccess;
|
||||
|
||||
if (data_index == AruidIndexMax) {
|
||||
result = CreateAppletResource(0);
|
||||
} else {
|
||||
registration_list.flag[data_index] = RegistrationStatus::Initialized;
|
||||
registration_list.aruid[data_index] = 0;
|
||||
}
|
||||
|
||||
if (result.IsError()) {
|
||||
UnregisterAppletResourceUserId(0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
ref_counter++;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result AppletResource::UnregisterCoreAppletResource() {
|
||||
if (ref_counter == 0) {
|
||||
return ResultAppletResourceNotInitialized;
|
||||
}
|
||||
|
||||
if (--ref_counter == 0) {
|
||||
UnregisterAppletResourceUserId(0);
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,123 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <mutex>
|
||||
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/hid/controllers/shared_memory_holder.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
class KSharedMemory;
|
||||
}
|
||||
|
||||
namespace Service::HID {
|
||||
struct SharedMemoryFormat;
|
||||
class AppletResource;
|
||||
class NPadResource;
|
||||
|
||||
static constexpr std::size_t AruidIndexMax = 0x20;
|
||||
static constexpr u64 SystemAruid = 0;
|
||||
|
||||
enum class RegistrationStatus : u32 {
|
||||
None,
|
||||
Initialized,
|
||||
PendingDelete,
|
||||
};
|
||||
|
||||
struct DataStatusFlag {
|
||||
union {
|
||||
u32 raw{};
|
||||
|
||||
BitField<0, 1, u32> is_initialized;
|
||||
BitField<1, 1, u32> is_assigned;
|
||||
BitField<16, 1, u32> enable_pad_input;
|
||||
BitField<17, 1, u32> enable_six_axis_sensor;
|
||||
BitField<18, 1, u32> bit_18;
|
||||
BitField<19, 1, u32> is_palma_connectable;
|
||||
BitField<20, 1, u32> enable_palma_boost_mode;
|
||||
BitField<21, 1, u32> enable_touchscreen;
|
||||
};
|
||||
};
|
||||
|
||||
struct AruidRegisterList {
|
||||
std::array<RegistrationStatus, AruidIndexMax> flag{};
|
||||
std::array<u64, AruidIndexMax> aruid{};
|
||||
};
|
||||
static_assert(sizeof(AruidRegisterList) == 0x180, "AruidRegisterList is an invalid size");
|
||||
|
||||
struct AruidData {
|
||||
DataStatusFlag flag{};
|
||||
u64 aruid{};
|
||||
SharedMemoryFormat* shared_memory_format{nullptr};
|
||||
};
|
||||
|
||||
struct HandheldConfig {
|
||||
bool is_handheld_hid_enabled;
|
||||
bool is_force_handheld;
|
||||
bool is_joycon_rail_enabled;
|
||||
bool is_force_handheld_style_vibration;
|
||||
};
|
||||
static_assert(sizeof(HandheldConfig) == 0x4, "HandheldConfig is an invalid size");
|
||||
|
||||
struct AppletResourceHolder {
|
||||
std::shared_ptr<AppletResource> applet_resource{nullptr};
|
||||
std::recursive_mutex* shared_mutex{nullptr};
|
||||
NPadResource* shared_npad_resource{nullptr};
|
||||
std::shared_ptr<HandheldConfig> handheld_config{nullptr};
|
||||
long* handle_1;
|
||||
};
|
||||
|
||||
class AppletResource {
|
||||
public:
|
||||
explicit AppletResource(Core::System& system_);
|
||||
~AppletResource();
|
||||
|
||||
Result CreateAppletResource(u64 aruid);
|
||||
|
||||
Result RegisterAppletResourceUserId(u64 aruid, bool enable_input);
|
||||
void UnregisterAppletResourceUserId(u64 aruid);
|
||||
|
||||
void FreeAppletResourceId(u64 aruid);
|
||||
|
||||
u64 GetActiveAruid();
|
||||
Result GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid);
|
||||
Result GetSharedMemoryFormat(SharedMemoryFormat** out_shared_memory_format, u64 aruid);
|
||||
AruidData* GetAruidData(u64 aruid);
|
||||
AruidData* GetAruidDataByIndex(std::size_t aruid_index);
|
||||
|
||||
bool IsVibrationAruidActive(u64 aruid) const;
|
||||
|
||||
u64 GetIndexFromAruid(u64 aruid);
|
||||
|
||||
Result DestroySevenSixAxisTransferMemory();
|
||||
|
||||
void EnableInput(u64 aruid, bool is_enabled);
|
||||
void EnableSixAxisSensor(u64 aruid, bool is_enabled);
|
||||
void EnablePadInput(u64 aruid, bool is_enabled);
|
||||
void EnableTouchScreen(u64 aruid, bool is_enabled);
|
||||
void SetIsPalmaConnectable(u64 aruid, bool is_connectable);
|
||||
void EnablePalmaBoostMode(u64 aruid, bool is_enabled);
|
||||
|
||||
Result RegisterCoreAppletResource();
|
||||
Result UnregisterCoreAppletResource();
|
||||
|
||||
private:
|
||||
u64 active_aruid{};
|
||||
AruidRegisterList registration_list{};
|
||||
std::array<AruidData, AruidIndexMax> data{};
|
||||
std::array<SharedMemoryHolder, AruidIndexMax> shared_memory_holder{};
|
||||
s32 ref_counter{};
|
||||
u64 active_vibration_aruid;
|
||||
|
||||
Core::System& system;
|
||||
};
|
||||
} // namespace Service::HID
|
|
@ -1,39 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/capture_button.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
CaptureButton::CaptureButton(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {}
|
||||
|
||||
CaptureButton::~CaptureButton() = default;
|
||||
|
||||
void CaptureButton::OnInit() {}
|
||||
|
||||
void CaptureButton::OnRelease() {}
|
||||
|
||||
void CaptureButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
if (!smart_update) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::scoped_lock shared_lock{*shared_mutex};
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr || !data->flag.is_assigned) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& header = data->shared_memory_format->capture_button.header;
|
||||
header.timestamp = core_timing.GetGlobalTimeNs().count();
|
||||
header.total_entry_count = 17;
|
||||
header.entry_count = 0;
|
||||
header.last_entry_index = 0;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,27 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
class CaptureButton final : public ControllerBase {
|
||||
public:
|
||||
explicit CaptureButton(Core::HID::HIDCore& hid_core_);
|
||||
~CaptureButton() override;
|
||||
|
||||
// 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(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
private:
|
||||
bool smart_update{};
|
||||
};
|
||||
} // namespace Service::HID
|
|
@ -1,45 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hid/emulated_console.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/service/hid/controllers/console_six_axis.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
ConsoleSixAxis::ConsoleSixAxis(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {
|
||||
console = hid_core.GetEmulatedConsole();
|
||||
}
|
||||
|
||||
ConsoleSixAxis::~ConsoleSixAxis() = default;
|
||||
|
||||
void ConsoleSixAxis::OnInit() {}
|
||||
|
||||
void ConsoleSixAxis::OnRelease() {}
|
||||
|
||||
void ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
std::scoped_lock shared_lock{*shared_mutex};
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr || !data->flag.is_assigned) {
|
||||
return;
|
||||
}
|
||||
|
||||
ConsoleSixAxisSensorSharedMemoryFormat& shared_memory = data->shared_memory_format->console;
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto motion_status = console->GetMotion();
|
||||
|
||||
shared_memory.sampling_number++;
|
||||
shared_memory.is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest;
|
||||
shared_memory.verticalization_error = motion_status.verticalization_error;
|
||||
shared_memory.gyro_bias = motion_status.gyro_bias;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,30 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
|
||||
namespace Core::HID {
|
||||
class EmulatedConsole;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Service::HID {
|
||||
class ConsoleSixAxis final : public ControllerBase {
|
||||
public:
|
||||
explicit ConsoleSixAxis(Core::HID::HIDCore& hid_core_);
|
||||
~ConsoleSixAxis() override;
|
||||
|
||||
// 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(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
private:
|
||||
Core::HID::EmulatedConsole* console = nullptr;
|
||||
};
|
||||
} // namespace Service::HID
|
|
@ -1,41 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
ControllerBase::ControllerBase(Core::HID::HIDCore& hid_core_) : hid_core(hid_core_) {}
|
||||
ControllerBase::~ControllerBase() = default;
|
||||
|
||||
Result ControllerBase::Activate() {
|
||||
if (is_activated) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
is_activated = true;
|
||||
OnInit();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result ControllerBase::Activate(u64 aruid) {
|
||||
return Activate();
|
||||
}
|
||||
|
||||
void ControllerBase::DeactivateController() {
|
||||
if (is_activated) {
|
||||
OnRelease();
|
||||
}
|
||||
is_activated = false;
|
||||
}
|
||||
|
||||
bool ControllerBase::IsControllerActivated() const {
|
||||
return is_activated;
|
||||
}
|
||||
|
||||
void ControllerBase::SetAppletResource(std::shared_ptr<AppletResource> resource,
|
||||
std::recursive_mutex* resource_mutex) {
|
||||
applet_resource = resource;
|
||||
shared_mutex = resource_mutex;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,55 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
|
||||
namespace Core::Timing {
|
||||
class CoreTiming;
|
||||
}
|
||||
|
||||
namespace Core::HID {
|
||||
class HIDCore;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Service::HID {
|
||||
class ControllerBase {
|
||||
public:
|
||||
explicit ControllerBase(Core::HID::HIDCore& hid_core_);
|
||||
virtual ~ControllerBase();
|
||||
|
||||
// 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(const Core::Timing::CoreTiming& core_timing) = 0;
|
||||
|
||||
// When the controller is requesting a motion update for the shared memory
|
||||
virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) {}
|
||||
|
||||
Result Activate();
|
||||
Result Activate(u64 aruid);
|
||||
|
||||
void DeactivateController();
|
||||
|
||||
bool IsControllerActivated() const;
|
||||
|
||||
void SetAppletResource(std::shared_ptr<AppletResource> resource,
|
||||
std::recursive_mutex* resource_mutex);
|
||||
|
||||
protected:
|
||||
bool is_activated{false};
|
||||
std::shared_ptr<AppletResource> applet_resource{nullptr};
|
||||
std::recursive_mutex* shared_mutex{nullptr};
|
||||
|
||||
Core::HID::HIDCore& hid_core;
|
||||
};
|
||||
} // namespace Service::HID
|
|
@ -1,64 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core_timing.h"
|
||||
#include "core/frontend/emu_window.h"
|
||||
#include "core/hid/emulated_devices.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/debug_mouse.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
DebugMouse::DebugMouse(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {
|
||||
emulated_devices = hid_core.GetEmulatedDevices();
|
||||
}
|
||||
|
||||
DebugMouse::~DebugMouse() = default;
|
||||
|
||||
void DebugMouse::OnInit() {}
|
||||
void DebugMouse::OnRelease() {}
|
||||
|
||||
void DebugMouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
std::scoped_lock shared_lock{*shared_mutex};
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr || !data->flag.is_assigned) {
|
||||
return;
|
||||
}
|
||||
|
||||
MouseSharedMemoryFormat& shared_memory = data->shared_memory_format->debug_mouse;
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
shared_memory.mouse_lifo.buffer_count = 0;
|
||||
shared_memory.mouse_lifo.buffer_tail = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
next_state = {};
|
||||
|
||||
const auto& last_entry = shared_memory.mouse_lifo.ReadCurrentEntry().state;
|
||||
next_state.sampling_number = last_entry.sampling_number + 1;
|
||||
|
||||
if (Settings::values.mouse_enabled) {
|
||||
const auto& mouse_button_state = emulated_devices->GetMouseButtons();
|
||||
const auto& mouse_position_state = emulated_devices->GetMousePosition();
|
||||
const auto& mouse_wheel_state = emulated_devices->GetMouseWheel();
|
||||
next_state.attribute.is_connected.Assign(1);
|
||||
next_state.x = static_cast<s32>(mouse_position_state.x * Layout::ScreenUndocked::Width);
|
||||
next_state.y = static_cast<s32>(mouse_position_state.y * Layout::ScreenUndocked::Height);
|
||||
next_state.delta_x = next_state.x - last_entry.x;
|
||||
next_state.delta_y = next_state.y - last_entry.y;
|
||||
next_state.delta_wheel_x = mouse_wheel_state.x - last_mouse_wheel_state.x;
|
||||
next_state.delta_wheel_y = mouse_wheel_state.y - last_mouse_wheel_state.y;
|
||||
|
||||
last_mouse_wheel_state = mouse_wheel_state;
|
||||
next_state.button = mouse_button_state;
|
||||
}
|
||||
|
||||
shared_memory.mouse_lifo.WriteNextEntry(next_state);
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,34 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
|
||||
namespace Core::HID {
|
||||
class EmulatedDevices;
|
||||
struct MouseState;
|
||||
struct AnalogStickState;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Service::HID {
|
||||
class DebugMouse final : public ControllerBase {
|
||||
public:
|
||||
explicit DebugMouse(Core::HID::HIDCore& hid_core_);
|
||||
~DebugMouse() override;
|
||||
|
||||
// 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(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
private:
|
||||
Core::HID::MouseState next_state{};
|
||||
Core::HID::AnalogStickState last_mouse_wheel_state{};
|
||||
Core::HID::EmulatedDevices* emulated_devices = nullptr;
|
||||
};
|
||||
} // namespace Service::HID
|
|
@ -1,59 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/settings.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/debug_pad.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
DebugPad::DebugPad(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {
|
||||
controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other);
|
||||
}
|
||||
|
||||
DebugPad::~DebugPad() = default;
|
||||
|
||||
void DebugPad::OnInit() {}
|
||||
|
||||
void DebugPad::OnRelease() {}
|
||||
|
||||
void DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
std::scoped_lock shared_lock{*shared_mutex};
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr || !data->flag.is_assigned) {
|
||||
return;
|
||||
}
|
||||
|
||||
DebugPadSharedMemoryFormat& shared_memory = data->shared_memory_format->debug_pad;
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
shared_memory.debug_pad_lifo.buffer_count = 0;
|
||||
shared_memory.debug_pad_lifo.buffer_tail = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& last_entry = shared_memory.debug_pad_lifo.ReadCurrentEntry().state;
|
||||
next_state.sampling_number = last_entry.sampling_number + 1;
|
||||
|
||||
if (Settings::values.debug_pad_enabled) {
|
||||
next_state.attribute.connected.Assign(1);
|
||||
|
||||
const auto& button_state = controller->GetDebugPadButtons();
|
||||
const auto& stick_state = controller->GetSticks();
|
||||
|
||||
next_state.pad_state = button_state;
|
||||
next_state.l_stick = stick_state.left;
|
||||
next_state.r_stick = stick_state.right;
|
||||
}
|
||||
|
||||
shared_memory.debug_pad_lifo.WriteNextEntry(next_state);
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,36 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
#include "core/hle/service/hid/controllers/types/debug_pad_types.h"
|
||||
|
||||
namespace Core::HID {
|
||||
class HIDCore;
|
||||
}
|
||||
|
||||
namespace Core::Timing {
|
||||
class CoreTiming;
|
||||
}
|
||||
|
||||
namespace Service::HID {
|
||||
class DebugPad final : public ControllerBase {
|
||||
public:
|
||||
explicit DebugPad(Core::HID::HIDCore& hid_core_);
|
||||
~DebugPad() override;
|
||||
|
||||
// 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(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
private:
|
||||
DebugPadState next_state{};
|
||||
Core::HID::EmulatedController* controller = nullptr;
|
||||
};
|
||||
} // namespace Service::HID
|
|
@ -1,39 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/digitizer.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
Digitizer::Digitizer(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {}
|
||||
|
||||
Digitizer::~Digitizer() = default;
|
||||
|
||||
void Digitizer::OnInit() {}
|
||||
|
||||
void Digitizer::OnRelease() {}
|
||||
|
||||
void Digitizer::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
if (!smart_update) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::scoped_lock shared_lock{*shared_mutex};
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr || !data->flag.is_assigned) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& header = data->shared_memory_format->digitizer.header;
|
||||
header.timestamp = core_timing.GetGlobalTimeNs().count();
|
||||
header.total_entry_count = 17;
|
||||
header.entry_count = 0;
|
||||
header.last_entry_index = 0;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,27 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
class Digitizer final : public ControllerBase {
|
||||
public:
|
||||
explicit Digitizer(Core::HID::HIDCore& hid_core_);
|
||||
~Digitizer() override;
|
||||
|
||||
// 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(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
private:
|
||||
bool smart_update{};
|
||||
};
|
||||
} // namespace Service::HID
|
|
@ -1,366 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/math_util.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/frontend/emu_window.h"
|
||||
#include "core/hid/emulated_console.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/gesture.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
|
||||
namespace Service::HID {
|
||||
// HW is around 700, value is set to 400 to make it easier to trigger with mouse
|
||||
constexpr f32 swipe_threshold = 400.0f; // Threshold in pixels/s
|
||||
constexpr f32 angle_threshold = 0.015f; // Threshold in radians
|
||||
constexpr f32 pinch_threshold = 0.5f; // Threshold in pixels
|
||||
constexpr f32 press_delay = 0.5f; // Time in seconds
|
||||
constexpr f32 double_tap_delay = 0.35f; // Time in seconds
|
||||
|
||||
constexpr f32 Square(s32 num) {
|
||||
return static_cast<f32>(num * num);
|
||||
}
|
||||
|
||||
Gesture::Gesture(Core::HID::HIDCore& hid_core_) : ControllerBase(hid_core_) {
|
||||
console = hid_core.GetEmulatedConsole();
|
||||
}
|
||||
Gesture::~Gesture() = default;
|
||||
|
||||
void Gesture::OnInit() {
|
||||
std::scoped_lock shared_lock{*shared_mutex};
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr || !data->flag.is_assigned) {
|
||||
return;
|
||||
}
|
||||
|
||||
shared_memory = &data->shared_memory_format->gesture;
|
||||
shared_memory->gesture_lifo.buffer_count = 0;
|
||||
shared_memory->gesture_lifo.buffer_tail = 0;
|
||||
force_update = true;
|
||||
}
|
||||
|
||||
void Gesture::OnRelease() {}
|
||||
|
||||
void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
std::scoped_lock shared_lock{*shared_mutex};
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr || !data->flag.is_assigned) {
|
||||
return;
|
||||
}
|
||||
|
||||
shared_memory = &data->shared_memory_format->gesture;
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
shared_memory->gesture_lifo.buffer_count = 0;
|
||||
shared_memory->gesture_lifo.buffer_tail = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
ReadTouchInput();
|
||||
|
||||
GestureProperties gesture = GetGestureProperties();
|
||||
f32 time_difference =
|
||||
static_cast<f32>(shared_memory->gesture_lifo.timestamp - last_update_timestamp) /
|
||||
(1000 * 1000 * 1000);
|
||||
|
||||
// Only update if necessary
|
||||
if (!ShouldUpdateGesture(gesture, time_difference)) {
|
||||
return;
|
||||
}
|
||||
|
||||
last_update_timestamp = shared_memory->gesture_lifo.timestamp;
|
||||
UpdateGestureSharedMemory(gesture, time_difference);
|
||||
}
|
||||
|
||||
void Gesture::ReadTouchInput() {
|
||||
if (!Settings::values.touchscreen.enabled) {
|
||||
fingers = {};
|
||||
return;
|
||||
}
|
||||
|
||||
const auto touch_status = console->GetTouch();
|
||||
for (std::size_t id = 0; id < fingers.size(); ++id) {
|
||||
fingers[id] = touch_status[id];
|
||||
}
|
||||
}
|
||||
|
||||
bool Gesture::ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference) {
|
||||
const auto& last_entry = GetLastGestureEntry();
|
||||
if (force_update) {
|
||||
force_update = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Update if coordinates change
|
||||
for (size_t id = 0; id < MAX_POINTS; id++) {
|
||||
if (gesture.points[id] != last_gesture.points[id]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Update on press and hold event after 0.5 seconds
|
||||
if (last_entry.type == GestureType::Touch && last_entry.point_count == 1 &&
|
||||
time_difference > press_delay) {
|
||||
return enable_press_and_tap;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Gesture::UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_difference) {
|
||||
GestureType type = GestureType::Idle;
|
||||
GestureAttribute attributes{};
|
||||
|
||||
const auto& last_entry = shared_memory->gesture_lifo.ReadCurrentEntry().state;
|
||||
|
||||
// Reset next state to default
|
||||
next_state.sampling_number = last_entry.sampling_number + 1;
|
||||
next_state.delta = {};
|
||||
next_state.vel_x = 0;
|
||||
next_state.vel_y = 0;
|
||||
next_state.direction = GestureDirection::None;
|
||||
next_state.rotation_angle = 0;
|
||||
next_state.scale = 0;
|
||||
|
||||
if (gesture.active_points > 0) {
|
||||
if (last_gesture.active_points == 0) {
|
||||
NewGesture(gesture, type, attributes);
|
||||
} else {
|
||||
UpdateExistingGesture(gesture, type, time_difference);
|
||||
}
|
||||
} else {
|
||||
EndGesture(gesture, last_gesture, type, attributes, time_difference);
|
||||
}
|
||||
|
||||
// Apply attributes
|
||||
next_state.detection_count = gesture.detection_count;
|
||||
next_state.type = type;
|
||||
next_state.attributes = attributes;
|
||||
next_state.pos = gesture.mid_point;
|
||||
next_state.point_count = static_cast<s32>(gesture.active_points);
|
||||
next_state.points = gesture.points;
|
||||
last_gesture = gesture;
|
||||
|
||||
shared_memory->gesture_lifo.WriteNextEntry(next_state);
|
||||
}
|
||||
|
||||
void Gesture::NewGesture(GestureProperties& gesture, GestureType& type,
|
||||
GestureAttribute& attributes) {
|
||||
const auto& last_entry = GetLastGestureEntry();
|
||||
|
||||
gesture.detection_count++;
|
||||
type = GestureType::Touch;
|
||||
|
||||
// New touch after cancel is not considered new
|
||||
if (last_entry.type != GestureType::Cancel) {
|
||||
attributes.is_new_touch.Assign(1);
|
||||
enable_press_and_tap = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Gesture::UpdateExistingGesture(GestureProperties& gesture, GestureType& type,
|
||||
f32 time_difference) {
|
||||
const auto& last_entry = GetLastGestureEntry();
|
||||
|
||||
// Promote to pan type if touch moved
|
||||
for (size_t id = 0; id < MAX_POINTS; id++) {
|
||||
if (gesture.points[id] != last_gesture.points[id]) {
|
||||
type = GestureType::Pan;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Number of fingers changed cancel the last event and clear data
|
||||
if (gesture.active_points != last_gesture.active_points) {
|
||||
type = GestureType::Cancel;
|
||||
enable_press_and_tap = false;
|
||||
gesture.active_points = 0;
|
||||
gesture.mid_point = {};
|
||||
gesture.points.fill({});
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate extra parameters of panning
|
||||
if (type == GestureType::Pan) {
|
||||
UpdatePanEvent(gesture, last_gesture, type, time_difference);
|
||||
return;
|
||||
}
|
||||
|
||||
// Promote to press type
|
||||
if (last_entry.type == GestureType::Touch) {
|
||||
type = GestureType::Press;
|
||||
}
|
||||
}
|
||||
|
||||
void Gesture::EndGesture(GestureProperties& gesture, GestureProperties& last_gesture_props,
|
||||
GestureType& type, GestureAttribute& attributes, f32 time_difference) {
|
||||
const auto& last_entry = GetLastGestureEntry();
|
||||
|
||||
if (last_gesture_props.active_points != 0) {
|
||||
switch (last_entry.type) {
|
||||
case GestureType::Touch:
|
||||
if (enable_press_and_tap) {
|
||||
SetTapEvent(gesture, last_gesture_props, type, attributes);
|
||||
return;
|
||||
}
|
||||
type = GestureType::Cancel;
|
||||
force_update = true;
|
||||
break;
|
||||
case GestureType::Press:
|
||||
case GestureType::Tap:
|
||||
case GestureType::Swipe:
|
||||
case GestureType::Pinch:
|
||||
case GestureType::Rotate:
|
||||
type = GestureType::Complete;
|
||||
force_update = true;
|
||||
break;
|
||||
case GestureType::Pan:
|
||||
EndPanEvent(gesture, last_gesture_props, type, time_difference);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (last_entry.type == GestureType::Complete || last_entry.type == GestureType::Cancel) {
|
||||
gesture.detection_count++;
|
||||
}
|
||||
}
|
||||
|
||||
void Gesture::SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
|
||||
GestureType& type, GestureAttribute& attributes) {
|
||||
type = GestureType::Tap;
|
||||
gesture = last_gesture_props;
|
||||
force_update = true;
|
||||
f32 tap_time_difference =
|
||||
static_cast<f32>(last_update_timestamp - last_tap_timestamp) / (1000 * 1000 * 1000);
|
||||
last_tap_timestamp = last_update_timestamp;
|
||||
if (tap_time_difference < double_tap_delay) {
|
||||
attributes.is_double_tap.Assign(1);
|
||||
}
|
||||
}
|
||||
|
||||
void Gesture::UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
|
||||
GestureType& type, f32 time_difference) {
|
||||
const auto& last_entry = GetLastGestureEntry();
|
||||
|
||||
next_state.delta = gesture.mid_point - last_entry.pos;
|
||||
next_state.vel_x = static_cast<f32>(next_state.delta.x) / time_difference;
|
||||
next_state.vel_y = static_cast<f32>(next_state.delta.y) / time_difference;
|
||||
last_pan_time_difference = time_difference;
|
||||
|
||||
// Promote to pinch type
|
||||
if (std::abs(gesture.average_distance - last_gesture_props.average_distance) >
|
||||
pinch_threshold) {
|
||||
type = GestureType::Pinch;
|
||||
next_state.scale = gesture.average_distance / last_gesture_props.average_distance;
|
||||
}
|
||||
|
||||
const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture_props.angle) /
|
||||
(1 + (gesture.angle * last_gesture_props.angle)));
|
||||
// Promote to rotate type
|
||||
if (std::abs(angle_between_two_lines) > angle_threshold) {
|
||||
type = GestureType::Rotate;
|
||||
next_state.scale = 0;
|
||||
next_state.rotation_angle = angle_between_two_lines * 180.0f / Common::PI;
|
||||
}
|
||||
}
|
||||
|
||||
void Gesture::EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
|
||||
GestureType& type, f32 time_difference) {
|
||||
const auto& last_entry = GetLastGestureEntry();
|
||||
next_state.vel_x =
|
||||
static_cast<f32>(last_entry.delta.x) / (last_pan_time_difference + time_difference);
|
||||
next_state.vel_y =
|
||||
static_cast<f32>(last_entry.delta.y) / (last_pan_time_difference + time_difference);
|
||||
const f32 curr_vel =
|
||||
std::sqrt((next_state.vel_x * next_state.vel_x) + (next_state.vel_y * next_state.vel_y));
|
||||
|
||||
// Set swipe event with parameters
|
||||
if (curr_vel > swipe_threshold) {
|
||||
SetSwipeEvent(gesture, last_gesture_props, type);
|
||||
return;
|
||||
}
|
||||
|
||||
// End panning without swipe
|
||||
type = GestureType::Complete;
|
||||
next_state.vel_x = 0;
|
||||
next_state.vel_y = 0;
|
||||
force_update = true;
|
||||
}
|
||||
|
||||
void Gesture::SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
|
||||
GestureType& type) {
|
||||
const auto& last_entry = GetLastGestureEntry();
|
||||
|
||||
type = GestureType::Swipe;
|
||||
gesture = last_gesture_props;
|
||||
force_update = true;
|
||||
next_state.delta = last_entry.delta;
|
||||
|
||||
if (std::abs(next_state.delta.x) > std::abs(next_state.delta.y)) {
|
||||
if (next_state.delta.x > 0) {
|
||||
next_state.direction = GestureDirection::Right;
|
||||
return;
|
||||
}
|
||||
next_state.direction = GestureDirection::Left;
|
||||
return;
|
||||
}
|
||||
if (next_state.delta.y > 0) {
|
||||
next_state.direction = GestureDirection::Down;
|
||||
return;
|
||||
}
|
||||
next_state.direction = GestureDirection::Up;
|
||||
}
|
||||
|
||||
const GestureState& Gesture::GetLastGestureEntry() const {
|
||||
return shared_memory->gesture_lifo.ReadCurrentEntry().state;
|
||||
}
|
||||
|
||||
GestureProperties Gesture::GetGestureProperties() {
|
||||
GestureProperties gesture;
|
||||
std::array<Core::HID::TouchFinger, MAX_POINTS> active_fingers;
|
||||
const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(),
|
||||
[](const auto& finger) { return finger.pressed; });
|
||||
gesture.active_points =
|
||||
static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter));
|
||||
|
||||
for (size_t id = 0; id < gesture.active_points; ++id) {
|
||||
const auto& [active_x, active_y] = active_fingers[id].position;
|
||||
gesture.points[id] = {
|
||||
.x = static_cast<s32>(active_x * Layout::ScreenUndocked::Width),
|
||||
.y = static_cast<s32>(active_y * Layout::ScreenUndocked::Height),
|
||||
};
|
||||
|
||||
// Hack: There is no touch in docked but games still allow it
|
||||
if (Settings::IsDockedMode()) {
|
||||
gesture.points[id] = {
|
||||
.x = static_cast<s32>(active_x * Layout::ScreenDocked::Width),
|
||||
.y = static_cast<s32>(active_y * Layout::ScreenDocked::Height),
|
||||
};
|
||||
}
|
||||
|
||||
gesture.mid_point.x += static_cast<s32>(gesture.points[id].x / gesture.active_points);
|
||||
gesture.mid_point.y += static_cast<s32>(gesture.points[id].y / gesture.active_points);
|
||||
}
|
||||
|
||||
for (size_t id = 0; id < gesture.active_points; ++id) {
|
||||
const f32 distance = std::sqrt(Square(gesture.mid_point.x - gesture.points[id].x) +
|
||||
Square(gesture.mid_point.y - gesture.points[id].y));
|
||||
gesture.average_distance += distance / static_cast<f32>(gesture.active_points);
|
||||
}
|
||||
|
||||
gesture.angle = std::atan2(static_cast<f32>(gesture.mid_point.y - gesture.points[0].y),
|
||||
static_cast<f32>(gesture.mid_point.x - gesture.points[0].x));
|
||||
|
||||
gesture.detection_count = last_gesture.detection_count;
|
||||
|
||||
return gesture;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,87 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
#include "core/hle/service/hid/controllers/types/touch_types.h"
|
||||
|
||||
namespace Core::HID {
|
||||
class EmulatedConsole;
|
||||
}
|
||||
|
||||
namespace Service::HID {
|
||||
struct GestureSharedMemoryFormat;
|
||||
|
||||
class Gesture final : public ControllerBase {
|
||||
public:
|
||||
explicit Gesture(Core::HID::HIDCore& hid_core_);
|
||||
~Gesture() override;
|
||||
|
||||
// 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(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
private:
|
||||
// Reads input from all available input engines
|
||||
void ReadTouchInput();
|
||||
|
||||
// Returns true if gesture state needs to be updated
|
||||
bool ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference);
|
||||
|
||||
// Updates the shared memory to the next state
|
||||
void UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_difference);
|
||||
|
||||
// Initializes new gesture
|
||||
void NewGesture(GestureProperties& gesture, GestureType& type, GestureAttribute& attributes);
|
||||
|
||||
// Updates existing gesture state
|
||||
void UpdateExistingGesture(GestureProperties& gesture, GestureType& type, f32 time_difference);
|
||||
|
||||
// Terminates exiting gesture
|
||||
void EndGesture(GestureProperties& gesture, GestureProperties& last_gesture_props,
|
||||
GestureType& type, GestureAttribute& attributes, f32 time_difference);
|
||||
|
||||
// Set current event to a tap event
|
||||
void SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
|
||||
GestureType& type, GestureAttribute& attributes);
|
||||
|
||||
// Calculates and set the extra parameters related to a pan event
|
||||
void UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
|
||||
GestureType& type, f32 time_difference);
|
||||
|
||||
// Terminates the pan event
|
||||
void EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
|
||||
GestureType& type, f32 time_difference);
|
||||
|
||||
// Set current event to a swipe event
|
||||
void SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
|
||||
GestureType& type);
|
||||
|
||||
// Retrieves the last gesture entry, as indicated by shared memory indices.
|
||||
[[nodiscard]] const GestureState& GetLastGestureEntry() const;
|
||||
|
||||
// Returns the average distance, angle and middle point of the active fingers
|
||||
GestureProperties GetGestureProperties();
|
||||
|
||||
GestureState next_state{};
|
||||
GestureSharedMemoryFormat* shared_memory;
|
||||
Core::HID::EmulatedConsole* console = nullptr;
|
||||
|
||||
std::array<Core::HID::TouchFinger, MAX_POINTS> fingers{};
|
||||
GestureProperties last_gesture{};
|
||||
s64 last_update_timestamp{};
|
||||
s64 last_tap_timestamp{};
|
||||
f32 last_pan_time_difference{};
|
||||
bool force_update{false};
|
||||
bool enable_press_and_tap{false};
|
||||
};
|
||||
} // namespace Service::HID
|
|
@ -1,39 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/home_button.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
HomeButton::HomeButton(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {}
|
||||
|
||||
HomeButton::~HomeButton() = default;
|
||||
|
||||
void HomeButton::OnInit() {}
|
||||
|
||||
void HomeButton::OnRelease() {}
|
||||
|
||||
void HomeButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
if (!smart_update) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::scoped_lock shared_lock{*shared_mutex};
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr || !data->flag.is_assigned) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& header = data->shared_memory_format->home_button.header;
|
||||
header.timestamp = core_timing.GetGlobalTimeNs().count();
|
||||
header.total_entry_count = 17;
|
||||
header.entry_count = 0;
|
||||
header.last_entry_index = 0;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,27 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
class HomeButton final : public ControllerBase {
|
||||
public:
|
||||
explicit HomeButton(Core::HID::HIDCore& hid_core_);
|
||||
~HomeButton() override;
|
||||
|
||||
// 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(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
private:
|
||||
bool smart_update{};
|
||||
};
|
||||
} // namespace Service::HID
|
|
@ -1,56 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/settings.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hid/emulated_devices.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/keyboard.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
Keyboard::Keyboard(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {
|
||||
emulated_devices = hid_core.GetEmulatedDevices();
|
||||
}
|
||||
|
||||
Keyboard::~Keyboard() = default;
|
||||
|
||||
void Keyboard::OnInit() {}
|
||||
|
||||
void Keyboard::OnRelease() {}
|
||||
|
||||
void Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
std::scoped_lock shared_lock{*shared_mutex};
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr || !data->flag.is_assigned) {
|
||||
return;
|
||||
}
|
||||
|
||||
KeyboardSharedMemoryFormat& shared_memory = data->shared_memory_format->keyboard;
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
shared_memory.keyboard_lifo.buffer_count = 0;
|
||||
shared_memory.keyboard_lifo.buffer_tail = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& last_entry = shared_memory.keyboard_lifo.ReadCurrentEntry().state;
|
||||
next_state.sampling_number = last_entry.sampling_number + 1;
|
||||
|
||||
if (Settings::values.keyboard_enabled) {
|
||||
const auto& keyboard_state = emulated_devices->GetKeyboard();
|
||||
const auto& keyboard_modifier_state = emulated_devices->GetKeyboardModifier();
|
||||
|
||||
next_state.key = keyboard_state;
|
||||
next_state.modifier = keyboard_modifier_state;
|
||||
next_state.attribute.is_connected.Assign(1);
|
||||
}
|
||||
|
||||
shared_memory.keyboard_lifo.WriteNextEntry(next_state);
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,28 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
#include "core/hle/service/hid/controllers/types/keyboard_types.h"
|
||||
|
||||
namespace Service::HID {
|
||||
class Keyboard final : public ControllerBase {
|
||||
public:
|
||||
explicit Keyboard(Core::HID::HIDCore& hid_core_);
|
||||
~Keyboard() override;
|
||||
|
||||
// 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(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
private:
|
||||
KeyboardState next_state{};
|
||||
Core::HID::EmulatedDevices* emulated_devices = nullptr;
|
||||
};
|
||||
} // namespace Service::HID
|
|
@ -1,64 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core_timing.h"
|
||||
#include "core/frontend/emu_window.h"
|
||||
#include "core/hid/emulated_devices.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/mouse.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
Mouse::Mouse(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {
|
||||
emulated_devices = hid_core.GetEmulatedDevices();
|
||||
}
|
||||
|
||||
Mouse::~Mouse() = default;
|
||||
|
||||
void Mouse::OnInit() {}
|
||||
void Mouse::OnRelease() {}
|
||||
|
||||
void Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
std::scoped_lock shared_lock{*shared_mutex};
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr || !data->flag.is_assigned) {
|
||||
return;
|
||||
}
|
||||
|
||||
MouseSharedMemoryFormat& shared_memory = data->shared_memory_format->mouse;
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
shared_memory.mouse_lifo.buffer_count = 0;
|
||||
shared_memory.mouse_lifo.buffer_tail = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
next_state = {};
|
||||
|
||||
const auto& last_entry = shared_memory.mouse_lifo.ReadCurrentEntry().state;
|
||||
next_state.sampling_number = last_entry.sampling_number + 1;
|
||||
|
||||
if (Settings::values.mouse_enabled) {
|
||||
const auto& mouse_button_state = emulated_devices->GetMouseButtons();
|
||||
const auto& mouse_position_state = emulated_devices->GetMousePosition();
|
||||
const auto& mouse_wheel_state = emulated_devices->GetMouseWheel();
|
||||
next_state.attribute.is_connected.Assign(1);
|
||||
next_state.x = static_cast<s32>(mouse_position_state.x * Layout::ScreenUndocked::Width);
|
||||
next_state.y = static_cast<s32>(mouse_position_state.y * Layout::ScreenUndocked::Height);
|
||||
next_state.delta_x = next_state.x - last_entry.x;
|
||||
next_state.delta_y = next_state.y - last_entry.y;
|
||||
next_state.delta_wheel_x = mouse_wheel_state.x - last_mouse_wheel_state.x;
|
||||
next_state.delta_wheel_y = mouse_wheel_state.y - last_mouse_wheel_state.y;
|
||||
|
||||
last_mouse_wheel_state = mouse_wheel_state;
|
||||
next_state.button = mouse_button_state;
|
||||
}
|
||||
|
||||
shared_memory.mouse_lifo.WriteNextEntry(next_state);
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,34 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
|
||||
namespace Core::HID {
|
||||
class EmulatedDevices;
|
||||
struct MouseState;
|
||||
struct AnalogStickState;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Service::HID {
|
||||
class Mouse final : public ControllerBase {
|
||||
public:
|
||||
explicit Mouse(Core::HID::HIDCore& hid_core_);
|
||||
~Mouse() override;
|
||||
|
||||
// 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(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
private:
|
||||
Core::HID::MouseState next_state{};
|
||||
Core::HID::AnalogStickState last_mouse_wheel_state{};
|
||||
Core::HID::EmulatedDevices* emulated_devices = nullptr;
|
||||
};
|
||||
} // namespace Service::HID
|
File diff suppressed because it is too large
Load diff
|
@ -1,214 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <span>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
#include "core/hle/service/hid/controllers/npad/npad_resource.h"
|
||||
#include "core/hle/service/hid/controllers/types/npad_types.h"
|
||||
|
||||
namespace Core::HID {
|
||||
class EmulatedController;
|
||||
enum class ControllerTriggerType;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Kernel {
|
||||
class KEvent;
|
||||
class KReadableEvent;
|
||||
} // namespace Kernel
|
||||
|
||||
namespace Service::KernelHelpers {
|
||||
class ServiceContext;
|
||||
} // namespace Service::KernelHelpers
|
||||
|
||||
union Result;
|
||||
|
||||
namespace Service::HID {
|
||||
class AppletResource;
|
||||
struct NpadInternalState;
|
||||
struct NpadSixAxisSensorLifo;
|
||||
struct NpadSharedMemoryFormat;
|
||||
|
||||
class NPad final {
|
||||
public:
|
||||
explicit NPad(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_);
|
||||
~NPad();
|
||||
|
||||
Result Activate();
|
||||
Result Activate(u64 aruid);
|
||||
|
||||
Result ActivateNpadResource();
|
||||
Result ActivateNpadResource(u64 aruid);
|
||||
|
||||
// When the controller is requesting an update for the shared memory
|
||||
void OnUpdate(const Core::Timing::CoreTiming& core_timing);
|
||||
|
||||
Result SetSupportedNpadStyleSet(u64 aruid, Core::HID::NpadStyleSet supported_style_set);
|
||||
Result GetSupportedNpadStyleSet(u64 aruid,
|
||||
Core::HID::NpadStyleSet& out_supported_style_set) const;
|
||||
Result GetMaskedSupportedNpadStyleSet(u64 aruid,
|
||||
Core::HID::NpadStyleSet& out_supported_style_set) const;
|
||||
|
||||
Result SetSupportedNpadIdType(u64 aruid,
|
||||
std::span<const Core::HID::NpadIdType> supported_npad_list);
|
||||
|
||||
Result SetNpadJoyHoldType(u64 aruid, NpadJoyHoldType hold_type);
|
||||
Result GetNpadJoyHoldType(u64 aruid, NpadJoyHoldType& out_hold_type) const;
|
||||
|
||||
Result SetNpadHandheldActivationMode(u64 aruid, NpadHandheldActivationMode mode);
|
||||
Result GetNpadHandheldActivationMode(u64 aruid, NpadHandheldActivationMode& out_mode) const;
|
||||
|
||||
bool SetNpadMode(u64 aruid, Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType npad_id,
|
||||
NpadJoyDeviceType npad_device_type, NpadJoyAssignmentMode assignment_mode);
|
||||
|
||||
bool VibrateControllerAtIndex(u64 aruid, Core::HID::NpadIdType npad_id,
|
||||
std::size_t device_index,
|
||||
const Core::HID::VibrationValue& vibration_value);
|
||||
|
||||
void VibrateController(u64 aruid,
|
||||
const Core::HID::VibrationDeviceHandle& vibration_device_handle,
|
||||
const Core::HID::VibrationValue& vibration_value);
|
||||
|
||||
void VibrateControllers(
|
||||
u64 aruid, std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles,
|
||||
std::span<const Core::HID::VibrationValue> vibration_values);
|
||||
|
||||
Core::HID::VibrationValue GetLastVibration(
|
||||
u64 aruid, const Core::HID::VibrationDeviceHandle& vibration_device_handle) const;
|
||||
|
||||
void InitializeVibrationDevice(const Core::HID::VibrationDeviceHandle& vibration_device_handle);
|
||||
|
||||
void InitializeVibrationDeviceAtIndex(u64 aruid, Core::HID::NpadIdType npad_id,
|
||||
std::size_t device_index);
|
||||
|
||||
void SetPermitVibrationSession(bool permit_vibration_session);
|
||||
|
||||
bool IsVibrationDeviceMounted(
|
||||
u64 aruid, const Core::HID::VibrationDeviceHandle& vibration_device_handle) const;
|
||||
|
||||
Result AcquireNpadStyleSetUpdateEventHandle(u64 aruid, Kernel::KReadableEvent** out_event,
|
||||
Core::HID::NpadIdType npad_id);
|
||||
|
||||
// Adds a new controller at an index.
|
||||
void AddNewControllerAt(u64 aruid, Core::HID::NpadStyleIndex controller,
|
||||
Core::HID::NpadIdType npad_id);
|
||||
// Adds a new controller at an index with connection status.
|
||||
void UpdateControllerAt(u64 aruid, Core::HID::NpadStyleIndex controller,
|
||||
Core::HID::NpadIdType npad_id, bool connected);
|
||||
|
||||
Result DisconnectNpad(u64 aruid, Core::HID::NpadIdType npad_id);
|
||||
|
||||
Result IsFirmwareUpdateAvailableForSixAxisSensor(
|
||||
u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
bool& is_firmware_available) const;
|
||||
Result ResetIsSixAxisSensorDeviceNewlyAssigned(
|
||||
u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle);
|
||||
|
||||
Result GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const;
|
||||
|
||||
Result IsUnintendedHomeButtonInputProtectionEnabled(bool& out_is_enabled, u64 aruid,
|
||||
Core::HID::NpadIdType npad_id) const;
|
||||
Result EnableUnintendedHomeButtonInputProtection(u64 aruid, Core::HID::NpadIdType npad_id,
|
||||
bool is_enabled);
|
||||
|
||||
void SetNpadAnalogStickUseCenterClamp(u64 aruid, bool is_enabled);
|
||||
void ClearAllConnectedControllers();
|
||||
void DisconnectAllConnectedControllers();
|
||||
void ConnectAllDisconnectedControllers();
|
||||
void ClearAllControllers();
|
||||
|
||||
Result MergeSingleJoyAsDualJoy(u64 aruid, Core::HID::NpadIdType npad_id_1,
|
||||
Core::HID::NpadIdType npad_id_2);
|
||||
Result StartLrAssignmentMode(u64 aruid);
|
||||
Result StopLrAssignmentMode(u64 aruid);
|
||||
Result SwapNpadAssignment(u64 aruid, Core::HID::NpadIdType npad_id_1,
|
||||
Core::HID::NpadIdType npad_id_2);
|
||||
|
||||
// Logical OR for all buttons presses on all controllers
|
||||
// Specifically for cheat engine and other features.
|
||||
Core::HID::NpadButton GetAndResetPressState();
|
||||
|
||||
Result ApplyNpadSystemCommonPolicy(u64 aruid);
|
||||
Result ApplyNpadSystemCommonPolicyFull(u64 aruid);
|
||||
Result ClearNpadSystemCommonPolicy(u64 aruid);
|
||||
|
||||
void SetRevision(u64 aruid, NpadRevision revision);
|
||||
NpadRevision GetRevision(u64 aruid);
|
||||
|
||||
Result RegisterAppletResourceUserId(u64 aruid);
|
||||
void UnregisterAppletResourceUserId(u64 aruid);
|
||||
void SetNpadExternals(std::shared_ptr<AppletResource> resource,
|
||||
std::recursive_mutex* shared_mutex);
|
||||
|
||||
AppletDetailedUiType GetAppletDetailedUiType(Core::HID::NpadIdType npad_id);
|
||||
|
||||
private:
|
||||
struct VibrationData {
|
||||
bool device_mounted{};
|
||||
Core::HID::VibrationValue latest_vibration_value{};
|
||||
std::chrono::steady_clock::time_point last_vibration_timepoint{};
|
||||
};
|
||||
|
||||
struct NpadControllerData {
|
||||
NpadInternalState* shared_memory = nullptr;
|
||||
Core::HID::EmulatedController* device = nullptr;
|
||||
|
||||
std::array<VibrationData, 2> vibration{};
|
||||
bool is_connected{};
|
||||
|
||||
// Dual joycons can have only one side connected
|
||||
bool is_dual_left_connected{true};
|
||||
bool is_dual_right_connected{true};
|
||||
|
||||
// Current pad state
|
||||
NPadGenericState npad_pad_state{};
|
||||
NPadGenericState npad_libnx_state{};
|
||||
NpadGcTriggerState npad_trigger_state{};
|
||||
int callback_key{};
|
||||
};
|
||||
|
||||
void ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t controller_idx);
|
||||
void InitNewlyAddedController(u64 aruid, Core::HID::NpadIdType npad_id);
|
||||
void RequestPadStateUpdate(u64 aruid, Core::HID::NpadIdType npad_id);
|
||||
void WriteEmptyEntry(NpadInternalState* npad);
|
||||
|
||||
NpadControllerData& GetControllerFromHandle(
|
||||
u64 aruid, const Core::HID::VibrationDeviceHandle& device_handle);
|
||||
const NpadControllerData& GetControllerFromHandle(
|
||||
u64 aruid, const Core::HID::VibrationDeviceHandle& device_handle) const;
|
||||
NpadControllerData& GetControllerFromHandle(
|
||||
u64 aruid, const Core::HID::SixAxisSensorHandle& device_handle);
|
||||
const NpadControllerData& GetControllerFromHandle(
|
||||
u64 aruid, const Core::HID::SixAxisSensorHandle& device_handle) const;
|
||||
NpadControllerData& GetControllerFromNpadIdType(u64 aruid, Core::HID::NpadIdType npad_id);
|
||||
const NpadControllerData& GetControllerFromNpadIdType(u64 aruid,
|
||||
Core::HID::NpadIdType npad_id) const;
|
||||
|
||||
Core::HID::SixAxisSensorProperties& GetSixaxisProperties(
|
||||
u64 aruid, const Core::HID::SixAxisSensorHandle& device_handle);
|
||||
const Core::HID::SixAxisSensorProperties& GetSixaxisProperties(
|
||||
u64 aruid, const Core::HID::SixAxisSensorHandle& device_handle) const;
|
||||
|
||||
Core::HID::HIDCore& hid_core;
|
||||
KernelHelpers::ServiceContext& service_context;
|
||||
|
||||
s32 ref_counter{};
|
||||
mutable std::mutex mutex;
|
||||
NPadResource npad_resource;
|
||||
AppletResourceHolder applet_resource_holder{};
|
||||
Kernel::KEvent* input_event{nullptr};
|
||||
std::mutex* input_mutex{nullptr};
|
||||
|
||||
std::atomic<u64> press_state{};
|
||||
bool permit_vibration_session_enabled;
|
||||
std::array<std::array<NpadControllerData, MaxSupportedNpadIdTypes>, AruidIndexMax>
|
||||
controller_data{};
|
||||
};
|
||||
} // namespace Service::HID
|
|
@ -1,228 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "core/hle/service/hid/controllers/npad/npad_data.h"
|
||||
#include "core/hle/service/hid/hid_util.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
NPadData::NPadData() {
|
||||
ClearNpadSystemCommonPolicy();
|
||||
}
|
||||
|
||||
NPadData::~NPadData() = default;
|
||||
|
||||
NpadStatus NPadData::GetNpadStatus() const {
|
||||
return status;
|
||||
}
|
||||
|
||||
void NPadData::SetNpadAnalogStickUseCenterClamp(bool is_enabled) {
|
||||
status.use_center_clamp.Assign(is_enabled);
|
||||
}
|
||||
|
||||
bool NPadData::GetNpadAnalogStickUseCenterClamp() const {
|
||||
return status.use_center_clamp.As<bool>();
|
||||
}
|
||||
|
||||
void NPadData::SetNpadSystemExtStateEnabled(bool is_enabled) {
|
||||
status.system_ext_state.Assign(is_enabled);
|
||||
}
|
||||
|
||||
bool NPadData::GetNpadSystemExtState() const {
|
||||
return status.system_ext_state.As<bool>();
|
||||
}
|
||||
|
||||
Result NPadData::SetSupportedNpadIdType(std::span<const Core::HID::NpadIdType> list) {
|
||||
// Note: Real limit is 11. But array size is 10. N's bug?
|
||||
if (list.size() > MaxSupportedNpadIdTypes) {
|
||||
return ResultInvalidArraySize;
|
||||
}
|
||||
|
||||
supported_npad_id_types_count = list.size();
|
||||
memcpy(supported_npad_id_types.data(), list.data(),
|
||||
list.size() * sizeof(Core::HID::NpadIdType));
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
std::size_t NPadData::GetSupportedNpadIdType(std::span<Core::HID::NpadIdType> out_list) const {
|
||||
std::size_t out_size = std::min(supported_npad_id_types_count, out_list.size());
|
||||
|
||||
memcpy(out_list.data(), supported_npad_id_types.data(),
|
||||
out_size * sizeof(Core::HID::NpadIdType));
|
||||
|
||||
return out_size;
|
||||
}
|
||||
|
||||
bool NPadData::IsNpadIdTypeSupported(Core::HID::NpadIdType npad_id) const {
|
||||
for (std::size_t i = 0; i < supported_npad_id_types_count; i++) {
|
||||
if (supported_npad_id_types[i] == npad_id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void NPadData::SetNpadSystemCommonPolicy(bool is_full_policy) {
|
||||
supported_npad_style_set = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::JoyDual |
|
||||
Core::HID::NpadStyleSet::SystemExt | Core::HID::NpadStyleSet::System;
|
||||
handheld_activation_mode = NpadHandheldActivationMode::Dual;
|
||||
|
||||
status.is_supported_styleset_set.Assign(true);
|
||||
status.is_hold_type_set.Assign(true);
|
||||
status.lr_assignment_mode.Assign(false);
|
||||
status.is_policy.Assign(true);
|
||||
if (is_full_policy) {
|
||||
status.is_full_policy.Assign(true);
|
||||
}
|
||||
|
||||
supported_npad_id_types_count = 10;
|
||||
supported_npad_id_types[0] = Core::HID::NpadIdType::Player1;
|
||||
supported_npad_id_types[1] = Core::HID::NpadIdType::Player2;
|
||||
supported_npad_id_types[2] = Core::HID::NpadIdType::Player3;
|
||||
supported_npad_id_types[3] = Core::HID::NpadIdType::Player4;
|
||||
supported_npad_id_types[4] = Core::HID::NpadIdType::Player5;
|
||||
supported_npad_id_types[5] = Core::HID::NpadIdType::Player6;
|
||||
supported_npad_id_types[6] = Core::HID::NpadIdType::Player7;
|
||||
supported_npad_id_types[7] = Core::HID::NpadIdType::Player8;
|
||||
supported_npad_id_types[8] = Core::HID::NpadIdType::Other;
|
||||
supported_npad_id_types[9] = Core::HID::NpadIdType::Handheld;
|
||||
|
||||
for (auto& input_protection : is_unintended_home_button_input_protection) {
|
||||
input_protection = true;
|
||||
}
|
||||
}
|
||||
|
||||
void NPadData::ClearNpadSystemCommonPolicy() {
|
||||
status.raw = 0;
|
||||
supported_npad_style_set = Core::HID::NpadStyleSet::All;
|
||||
npad_hold_type = NpadJoyHoldType::Vertical;
|
||||
handheld_activation_mode = NpadHandheldActivationMode::Dual;
|
||||
|
||||
for (auto& button_assignment : npad_button_assignment) {
|
||||
button_assignment = Core::HID::NpadButton::None;
|
||||
}
|
||||
|
||||
supported_npad_id_types_count = 10;
|
||||
supported_npad_id_types[0] = Core::HID::NpadIdType::Player1;
|
||||
supported_npad_id_types[1] = Core::HID::NpadIdType::Player2;
|
||||
supported_npad_id_types[2] = Core::HID::NpadIdType::Player3;
|
||||
supported_npad_id_types[3] = Core::HID::NpadIdType::Player4;
|
||||
supported_npad_id_types[4] = Core::HID::NpadIdType::Player5;
|
||||
supported_npad_id_types[5] = Core::HID::NpadIdType::Player6;
|
||||
supported_npad_id_types[6] = Core::HID::NpadIdType::Player7;
|
||||
supported_npad_id_types[7] = Core::HID::NpadIdType::Player8;
|
||||
supported_npad_id_types[8] = Core::HID::NpadIdType::Other;
|
||||
supported_npad_id_types[9] = Core::HID::NpadIdType::Handheld;
|
||||
|
||||
for (auto& input_protection : is_unintended_home_button_input_protection) {
|
||||
input_protection = true;
|
||||
}
|
||||
}
|
||||
|
||||
void NPadData::SetNpadJoyHoldType(NpadJoyHoldType hold_type) {
|
||||
npad_hold_type = hold_type;
|
||||
status.is_hold_type_set.Assign(true);
|
||||
}
|
||||
|
||||
NpadJoyHoldType NPadData::GetNpadJoyHoldType() const {
|
||||
return npad_hold_type;
|
||||
}
|
||||
|
||||
void NPadData::SetHandheldActivationMode(NpadHandheldActivationMode activation_mode) {
|
||||
handheld_activation_mode = activation_mode;
|
||||
}
|
||||
|
||||
NpadHandheldActivationMode NPadData::GetHandheldActivationMode() const {
|
||||
return handheld_activation_mode;
|
||||
}
|
||||
|
||||
void NPadData::SetSupportedNpadStyleSet(Core::HID::NpadStyleSet style_set) {
|
||||
supported_npad_style_set = style_set;
|
||||
status.is_supported_styleset_set.Assign(true);
|
||||
status.is_hold_type_set.Assign(true);
|
||||
}
|
||||
|
||||
Core::HID::NpadStyleSet NPadData::GetSupportedNpadStyleSet() const {
|
||||
return supported_npad_style_set;
|
||||
}
|
||||
|
||||
bool NPadData::IsNpadStyleIndexSupported(Core::HID::NpadStyleIndex style_index) const {
|
||||
Core::HID::NpadStyleTag style = {supported_npad_style_set};
|
||||
switch (style_index) {
|
||||
case Core::HID::NpadStyleIndex::ProController:
|
||||
return style.fullkey.As<bool>();
|
||||
case Core::HID::NpadStyleIndex::Handheld:
|
||||
return style.handheld.As<bool>();
|
||||
case Core::HID::NpadStyleIndex::JoyconDual:
|
||||
return style.joycon_dual.As<bool>();
|
||||
case Core::HID::NpadStyleIndex::JoyconLeft:
|
||||
return style.joycon_left.As<bool>();
|
||||
case Core::HID::NpadStyleIndex::JoyconRight:
|
||||
return style.joycon_right.As<bool>();
|
||||
case Core::HID::NpadStyleIndex::GameCube:
|
||||
return style.gamecube.As<bool>();
|
||||
case Core::HID::NpadStyleIndex::Pokeball:
|
||||
return style.palma.As<bool>();
|
||||
case Core::HID::NpadStyleIndex::NES:
|
||||
return style.lark.As<bool>();
|
||||
case Core::HID::NpadStyleIndex::SNES:
|
||||
return style.lucia.As<bool>();
|
||||
case Core::HID::NpadStyleIndex::N64:
|
||||
return style.lagoon.As<bool>();
|
||||
case Core::HID::NpadStyleIndex::SegaGenesis:
|
||||
return style.lager.As<bool>();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void NPadData::SetLrAssignmentMode(bool is_enabled) {
|
||||
status.lr_assignment_mode.Assign(is_enabled);
|
||||
}
|
||||
|
||||
bool NPadData::GetLrAssignmentMode() const {
|
||||
return status.lr_assignment_mode.As<bool>();
|
||||
}
|
||||
|
||||
void NPadData::SetAssigningSingleOnSlSrPress(bool is_enabled) {
|
||||
status.assigning_single_on_sl_sr_press.Assign(is_enabled);
|
||||
}
|
||||
|
||||
bool NPadData::GetAssigningSingleOnSlSrPress() const {
|
||||
return status.assigning_single_on_sl_sr_press.As<bool>();
|
||||
}
|
||||
|
||||
void NPadData::SetHomeProtectionEnabled(bool is_enabled, Core::HID::NpadIdType npad_id) {
|
||||
is_unintended_home_button_input_protection[NpadIdTypeToIndex(npad_id)] = is_enabled;
|
||||
}
|
||||
|
||||
bool NPadData::GetHomeProtectionEnabled(Core::HID::NpadIdType npad_id) const {
|
||||
return is_unintended_home_button_input_protection[NpadIdTypeToIndex(npad_id)];
|
||||
}
|
||||
|
||||
void NPadData::SetCaptureButtonAssignment(Core::HID::NpadButton button_assignment,
|
||||
std::size_t style_index) {
|
||||
npad_button_assignment[style_index] = button_assignment;
|
||||
}
|
||||
|
||||
Core::HID::NpadButton NPadData::GetCaptureButtonAssignment(std::size_t style_index) const {
|
||||
return npad_button_assignment[style_index];
|
||||
}
|
||||
|
||||
std::size_t NPadData::GetNpadCaptureButtonAssignmentList(
|
||||
std::span<Core::HID::NpadButton> out_list) const {
|
||||
for (std::size_t i = 0; i < out_list.size(); i++) {
|
||||
Core::HID::NpadStyleSet style_set = GetStylesetByIndex(i);
|
||||
if ((style_set & supported_npad_style_set) == Core::HID::NpadStyleSet::None ||
|
||||
npad_button_assignment[i] == Core::HID::NpadButton::None) {
|
||||
return i;
|
||||
}
|
||||
out_list[i] = npad_button_assignment[i];
|
||||
}
|
||||
|
||||
return out_list.size();
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,88 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <span>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/hid/controllers/types/npad_types.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
struct NpadStatus {
|
||||
union {
|
||||
u32 raw{};
|
||||
|
||||
BitField<0, 1, u32> is_supported_styleset_set;
|
||||
BitField<1, 1, u32> is_hold_type_set;
|
||||
BitField<2, 1, u32> lr_assignment_mode;
|
||||
BitField<3, 1, u32> assigning_single_on_sl_sr_press;
|
||||
BitField<4, 1, u32> is_full_policy;
|
||||
BitField<5, 1, u32> is_policy;
|
||||
BitField<6, 1, u32> use_center_clamp;
|
||||
BitField<7, 1, u32> system_ext_state;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(NpadStatus) == 4, "NpadStatus is an invalid size");
|
||||
|
||||
/// Handles Npad request from HID interfaces
|
||||
class NPadData final {
|
||||
public:
|
||||
explicit NPadData();
|
||||
~NPadData();
|
||||
|
||||
NpadStatus GetNpadStatus() const;
|
||||
|
||||
void SetNpadAnalogStickUseCenterClamp(bool is_enabled);
|
||||
bool GetNpadAnalogStickUseCenterClamp() const;
|
||||
|
||||
void SetNpadSystemExtStateEnabled(bool is_enabled);
|
||||
bool GetNpadSystemExtState() const;
|
||||
|
||||
Result SetSupportedNpadIdType(std::span<const Core::HID::NpadIdType> list);
|
||||
std::size_t GetSupportedNpadIdType(std::span<Core::HID::NpadIdType> out_list) const;
|
||||
bool IsNpadIdTypeSupported(Core::HID::NpadIdType npad_id) const;
|
||||
|
||||
void SetNpadSystemCommonPolicy(bool is_full_policy);
|
||||
void ClearNpadSystemCommonPolicy();
|
||||
|
||||
void SetNpadJoyHoldType(NpadJoyHoldType hold_type);
|
||||
NpadJoyHoldType GetNpadJoyHoldType() const;
|
||||
|
||||
void SetHandheldActivationMode(NpadHandheldActivationMode activation_mode);
|
||||
NpadHandheldActivationMode GetHandheldActivationMode() const;
|
||||
|
||||
void SetSupportedNpadStyleSet(Core::HID::NpadStyleSet style_set);
|
||||
Core::HID::NpadStyleSet GetSupportedNpadStyleSet() const;
|
||||
bool IsNpadStyleIndexSupported(Core::HID::NpadStyleIndex style_index) const;
|
||||
|
||||
void SetLrAssignmentMode(bool is_enabled);
|
||||
bool GetLrAssignmentMode() const;
|
||||
|
||||
void SetAssigningSingleOnSlSrPress(bool is_enabled);
|
||||
bool GetAssigningSingleOnSlSrPress() const;
|
||||
|
||||
void SetHomeProtectionEnabled(bool is_enabled, Core::HID::NpadIdType npad_id);
|
||||
bool GetHomeProtectionEnabled(Core::HID::NpadIdType npad_id) const;
|
||||
|
||||
void SetCaptureButtonAssignment(Core::HID::NpadButton button_assignment,
|
||||
std::size_t style_index);
|
||||
Core::HID::NpadButton GetCaptureButtonAssignment(std::size_t style_index) const;
|
||||
std::size_t GetNpadCaptureButtonAssignmentList(std::span<Core::HID::NpadButton> out_list) const;
|
||||
|
||||
private:
|
||||
NpadStatus status{};
|
||||
Core::HID::NpadStyleSet supported_npad_style_set{Core::HID::NpadStyleSet::All};
|
||||
NpadJoyHoldType npad_hold_type{NpadJoyHoldType::Vertical};
|
||||
NpadHandheldActivationMode handheld_activation_mode{};
|
||||
std::array<Core::HID::NpadIdType, MaxSupportedNpadIdTypes> supported_npad_id_types{};
|
||||
std::array<Core::HID::NpadButton, StyleIndexCount> npad_button_assignment{};
|
||||
std::size_t supported_npad_id_types_count{};
|
||||
std::array<bool, MaxSupportedNpadIdTypes> is_unintended_home_button_input_protection{};
|
||||
};
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,685 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/service/hid/controllers/npad/npad_resource.h"
|
||||
#include "core/hle/service/hid/controllers/types/npad_types.h"
|
||||
#include "core/hle/service/hid/errors.h"
|
||||
#include "core/hle/service/hid/hid_util.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
NPadResource::NPadResource(KernelHelpers::ServiceContext& context) : service_context{context} {}
|
||||
|
||||
NPadResource::~NPadResource() = default;
|
||||
|
||||
Result NPadResource::RegisterAppletResourceUserId(u64 aruid) {
|
||||
const auto aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index < AruidIndexMax) {
|
||||
return ResultAruidAlreadyRegistered;
|
||||
}
|
||||
|
||||
std::size_t data_index = AruidIndexMax;
|
||||
for (std::size_t i = 0; i < AruidIndexMax; i++) {
|
||||
if (!state[i].flag.is_initialized) {
|
||||
data_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (data_index == AruidIndexMax) {
|
||||
return ResultAruidNoAvailableEntries;
|
||||
}
|
||||
|
||||
auto& aruid_data = state[data_index];
|
||||
|
||||
aruid_data.aruid = aruid;
|
||||
aruid_data.flag.is_initialized.Assign(true);
|
||||
|
||||
data_index = AruidIndexMax;
|
||||
for (std::size_t i = 0; i < AruidIndexMax; i++) {
|
||||
if (registration_list.flag[i] == RegistrationStatus::Initialized) {
|
||||
if (registration_list.aruid[i] != aruid) {
|
||||
continue;
|
||||
}
|
||||
data_index = i;
|
||||
break;
|
||||
}
|
||||
if (registration_list.flag[i] == RegistrationStatus::None) {
|
||||
data_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (data_index == AruidIndexMax) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
registration_list.flag[data_index] = RegistrationStatus::Initialized;
|
||||
registration_list.aruid[data_index] = aruid;
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
void NPadResource::UnregisterAppletResourceUserId(u64 aruid) {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
|
||||
DestroyStyleSetUpdateEvents(aruid);
|
||||
if (aruid_index < AruidIndexMax) {
|
||||
state[aruid_index] = {};
|
||||
registration_list.flag[aruid_index] = RegistrationStatus::PendingDelete;
|
||||
}
|
||||
}
|
||||
|
||||
void NPadResource::DestroyStyleSetUpdateEvents(u64 aruid) {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& controller_state : state[aruid_index].controller_state) {
|
||||
if (!controller_state.is_styleset_update_event_initialized) {
|
||||
continue;
|
||||
}
|
||||
service_context.CloseEvent(controller_state.style_set_update_event);
|
||||
controller_state.is_styleset_update_event_initialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
Result NPadResource::Activate(u64 aruid) {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
auto& state_data = state[aruid_index];
|
||||
|
||||
if (state_data.flag.is_assigned) {
|
||||
return ResultAruidAlreadyRegistered;
|
||||
}
|
||||
|
||||
state_data.flag.is_assigned.Assign(true);
|
||||
state_data.data.ClearNpadSystemCommonPolicy();
|
||||
state_data.npad_revision = NpadRevision::Revision0;
|
||||
state_data.button_config = {};
|
||||
|
||||
if (active_data_aruid == aruid) {
|
||||
default_hold_type = active_data.GetNpadJoyHoldType();
|
||||
active_data.SetNpadJoyHoldType(default_hold_type);
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NPadResource::Activate() {
|
||||
if (ref_counter == std::numeric_limits<s32>::max() - 1) {
|
||||
return ResultAppletResourceOverflow;
|
||||
}
|
||||
if (ref_counter == 0) {
|
||||
RegisterAppletResourceUserId(SystemAruid);
|
||||
Activate(SystemAruid);
|
||||
}
|
||||
ref_counter++;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NPadResource::Deactivate() {
|
||||
if (ref_counter == 0) {
|
||||
return ResultAppletResourceNotInitialized;
|
||||
}
|
||||
|
||||
UnregisterAppletResourceUserId(SystemAruid);
|
||||
ref_counter--;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
NPadData* NPadResource::GetActiveData() {
|
||||
return &active_data;
|
||||
}
|
||||
|
||||
u64 NPadResource::GetActiveDataAruid() {
|
||||
return active_data_aruid;
|
||||
}
|
||||
|
||||
void NPadResource::SetAppletResourceUserId(u64 aruid) {
|
||||
if (active_data_aruid == aruid) {
|
||||
return;
|
||||
}
|
||||
|
||||
active_data_aruid = aruid;
|
||||
default_hold_type = active_data.GetNpadJoyHoldType();
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& data = state[aruid_index].data;
|
||||
if (data.GetNpadStatus().is_policy || data.GetNpadStatus().is_full_policy) {
|
||||
data.SetNpadJoyHoldType(default_hold_type);
|
||||
}
|
||||
|
||||
active_data = data;
|
||||
if (data.GetNpadStatus().is_hold_type_set) {
|
||||
active_data.SetNpadJoyHoldType(default_hold_type);
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t NPadResource::GetIndexFromAruid(u64 aruid) const {
|
||||
for (std::size_t i = 0; i < AruidIndexMax; i++) {
|
||||
if (registration_list.flag[i] == RegistrationStatus::Initialized &&
|
||||
registration_list.aruid[i] == aruid) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return AruidIndexMax;
|
||||
}
|
||||
|
||||
Result NPadResource::ApplyNpadSystemCommonPolicy(u64 aruid, bool is_full_policy) {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return ResultNpadNotConnected;
|
||||
}
|
||||
|
||||
auto& data = state[aruid_index].data;
|
||||
data.SetNpadSystemCommonPolicy(is_full_policy);
|
||||
data.SetNpadJoyHoldType(default_hold_type);
|
||||
if (active_data_aruid == aruid) {
|
||||
active_data.SetNpadSystemCommonPolicy(is_full_policy);
|
||||
active_data.SetNpadJoyHoldType(default_hold_type);
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NPadResource::ClearNpadSystemCommonPolicy(u64 aruid) {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return ResultNpadNotConnected;
|
||||
}
|
||||
|
||||
state[aruid_index].data.ClearNpadSystemCommonPolicy();
|
||||
if (active_data_aruid == aruid) {
|
||||
active_data.ClearNpadSystemCommonPolicy();
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NPadResource::SetSupportedNpadStyleSet(u64 aruid, Core::HID::NpadStyleSet style_set) {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return ResultNpadNotConnected;
|
||||
}
|
||||
|
||||
auto& data = state[aruid_index].data;
|
||||
data.SetSupportedNpadStyleSet(style_set);
|
||||
if (active_data_aruid == aruid) {
|
||||
active_data.SetSupportedNpadStyleSet(style_set);
|
||||
active_data.SetNpadJoyHoldType(data.GetNpadJoyHoldType());
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NPadResource::GetSupportedNpadStyleSet(Core::HID::NpadStyleSet& out_style_Set,
|
||||
u64 aruid) const {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return ResultNpadNotConnected;
|
||||
}
|
||||
|
||||
auto& data = state[aruid_index].data;
|
||||
if (!data.GetNpadStatus().is_supported_styleset_set) {
|
||||
return ResultUndefinedStyleset;
|
||||
}
|
||||
|
||||
out_style_Set = data.GetSupportedNpadStyleSet();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NPadResource::GetMaskedSupportedNpadStyleSet(Core::HID::NpadStyleSet& out_style_set,
|
||||
u64 aruid) const {
|
||||
if (aruid == SystemAruid) {
|
||||
out_style_set = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::Handheld |
|
||||
Core::HID::NpadStyleSet::JoyDual | Core::HID::NpadStyleSet::JoyLeft |
|
||||
Core::HID::NpadStyleSet::JoyRight | Core::HID::NpadStyleSet::Palma |
|
||||
Core::HID::NpadStyleSet::SystemExt | Core::HID::NpadStyleSet::System;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return ResultNpadNotConnected;
|
||||
}
|
||||
|
||||
auto& data = state[aruid_index].data;
|
||||
if (!data.GetNpadStatus().is_supported_styleset_set) {
|
||||
return ResultUndefinedStyleset;
|
||||
}
|
||||
|
||||
Core::HID::NpadStyleSet mask{Core::HID::NpadStyleSet::None};
|
||||
out_style_set = data.GetSupportedNpadStyleSet();
|
||||
|
||||
switch (state[aruid_index].npad_revision) {
|
||||
case NpadRevision::Revision1:
|
||||
mask = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::Handheld |
|
||||
Core::HID::NpadStyleSet::JoyDual | Core::HID::NpadStyleSet::JoyLeft |
|
||||
Core::HID::NpadStyleSet::JoyRight | Core::HID::NpadStyleSet::Gc |
|
||||
Core::HID::NpadStyleSet::Palma | Core::HID::NpadStyleSet::SystemExt |
|
||||
Core::HID::NpadStyleSet::System;
|
||||
break;
|
||||
case NpadRevision::Revision2:
|
||||
mask = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::Handheld |
|
||||
Core::HID::NpadStyleSet::JoyDual | Core::HID::NpadStyleSet::JoyLeft |
|
||||
Core::HID::NpadStyleSet::JoyRight | Core::HID::NpadStyleSet::Gc |
|
||||
Core::HID::NpadStyleSet::Palma | Core::HID::NpadStyleSet::Lark |
|
||||
Core::HID::NpadStyleSet::SystemExt | Core::HID::NpadStyleSet::System;
|
||||
break;
|
||||
case NpadRevision::Revision3:
|
||||
mask = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::Handheld |
|
||||
Core::HID::NpadStyleSet::JoyDual | Core::HID::NpadStyleSet::JoyLeft |
|
||||
Core::HID::NpadStyleSet::JoyRight | Core::HID::NpadStyleSet::Gc |
|
||||
Core::HID::NpadStyleSet::Palma | Core::HID::NpadStyleSet::Lark |
|
||||
Core::HID::NpadStyleSet::HandheldLark | Core::HID::NpadStyleSet::Lucia |
|
||||
Core::HID::NpadStyleSet::Lagoon | Core::HID::NpadStyleSet::Lager |
|
||||
Core::HID::NpadStyleSet::SystemExt | Core::HID::NpadStyleSet::System;
|
||||
break;
|
||||
default:
|
||||
mask = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::Handheld |
|
||||
Core::HID::NpadStyleSet::JoyDual | Core::HID::NpadStyleSet::JoyLeft |
|
||||
Core::HID::NpadStyleSet::JoyRight | Core::HID::NpadStyleSet::SystemExt |
|
||||
Core::HID::NpadStyleSet::System;
|
||||
break;
|
||||
}
|
||||
|
||||
out_style_set = out_style_set & mask;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NPadResource::GetAvailableStyleset(Core::HID::NpadStyleSet& out_style_set, u64 aruid) const {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return ResultNpadNotConnected;
|
||||
}
|
||||
|
||||
auto& data = state[aruid_index].data;
|
||||
if (!data.GetNpadStatus().is_supported_styleset_set) {
|
||||
return ResultUndefinedStyleset;
|
||||
}
|
||||
|
||||
Core::HID::NpadStyleSet mask{Core::HID::NpadStyleSet::None};
|
||||
out_style_set = data.GetSupportedNpadStyleSet();
|
||||
|
||||
switch (state[aruid_index].npad_revision) {
|
||||
case NpadRevision::Revision1:
|
||||
mask = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::Handheld |
|
||||
Core::HID::NpadStyleSet::JoyDual | Core::HID::NpadStyleSet::JoyLeft |
|
||||
Core::HID::NpadStyleSet::JoyRight | Core::HID::NpadStyleSet::Gc |
|
||||
Core::HID::NpadStyleSet::Palma | Core::HID::NpadStyleSet::SystemExt |
|
||||
Core::HID::NpadStyleSet::System;
|
||||
break;
|
||||
case NpadRevision::Revision2:
|
||||
mask = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::Handheld |
|
||||
Core::HID::NpadStyleSet::JoyDual | Core::HID::NpadStyleSet::JoyLeft |
|
||||
Core::HID::NpadStyleSet::JoyRight | Core::HID::NpadStyleSet::Gc |
|
||||
Core::HID::NpadStyleSet::Palma | Core::HID::NpadStyleSet::Lark |
|
||||
Core::HID::NpadStyleSet::SystemExt | Core::HID::NpadStyleSet::System;
|
||||
break;
|
||||
case NpadRevision::Revision3:
|
||||
mask = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::Handheld |
|
||||
Core::HID::NpadStyleSet::JoyDual | Core::HID::NpadStyleSet::JoyLeft |
|
||||
Core::HID::NpadStyleSet::JoyRight | Core::HID::NpadStyleSet::Gc |
|
||||
Core::HID::NpadStyleSet::Palma | Core::HID::NpadStyleSet::Lark |
|
||||
Core::HID::NpadStyleSet::HandheldLark | Core::HID::NpadStyleSet::Lucia |
|
||||
Core::HID::NpadStyleSet::Lagoon | Core::HID::NpadStyleSet::Lager |
|
||||
Core::HID::NpadStyleSet::SystemExt | Core::HID::NpadStyleSet::System;
|
||||
break;
|
||||
default:
|
||||
mask = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::Handheld |
|
||||
Core::HID::NpadStyleSet::JoyDual | Core::HID::NpadStyleSet::JoyLeft |
|
||||
Core::HID::NpadStyleSet::JoyRight | Core::HID::NpadStyleSet::SystemExt |
|
||||
Core::HID::NpadStyleSet::System;
|
||||
break;
|
||||
}
|
||||
|
||||
out_style_set = out_style_set & mask;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
NpadRevision NPadResource::GetNpadRevision(u64 aruid) const {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return NpadRevision::Revision0;
|
||||
}
|
||||
|
||||
return state[aruid_index].npad_revision;
|
||||
}
|
||||
|
||||
Result NPadResource::IsSupportedNpadStyleSet(bool& is_set, u64 aruid) {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return ResultNpadNotConnected;
|
||||
}
|
||||
|
||||
is_set = state[aruid_index].data.GetNpadStatus().is_supported_styleset_set.Value() != 0;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NPadResource::SetNpadJoyHoldType(u64 aruid, NpadJoyHoldType hold_type) {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return ResultNpadNotConnected;
|
||||
}
|
||||
|
||||
state[aruid_index].data.SetNpadJoyHoldType(hold_type);
|
||||
if (active_data_aruid == aruid) {
|
||||
active_data.SetNpadJoyHoldType(hold_type);
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NPadResource::GetNpadJoyHoldType(NpadJoyHoldType& hold_type, u64 aruid) const {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return ResultNpadNotConnected;
|
||||
}
|
||||
|
||||
auto& data = state[aruid_index].data;
|
||||
if (data.GetNpadStatus().is_policy || data.GetNpadStatus().is_full_policy) {
|
||||
hold_type = active_data.GetNpadJoyHoldType();
|
||||
return ResultSuccess;
|
||||
}
|
||||
hold_type = data.GetNpadJoyHoldType();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NPadResource::SetNpadHandheldActivationMode(u64 aruid,
|
||||
NpadHandheldActivationMode activation_mode) {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return ResultNpadNotConnected;
|
||||
}
|
||||
|
||||
state[aruid_index].data.SetHandheldActivationMode(activation_mode);
|
||||
if (active_data_aruid == aruid) {
|
||||
active_data.SetHandheldActivationMode(activation_mode);
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NPadResource::GetNpadHandheldActivationMode(NpadHandheldActivationMode& activation_mode,
|
||||
u64 aruid) const {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return ResultNpadNotConnected;
|
||||
}
|
||||
|
||||
activation_mode = state[aruid_index].data.GetHandheldActivationMode();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NPadResource::SetSupportedNpadIdType(
|
||||
u64 aruid, std::span<const Core::HID::NpadIdType> supported_npad_list) {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return ResultNpadNotConnected;
|
||||
}
|
||||
if (supported_npad_list.size() > MaxSupportedNpadIdTypes) {
|
||||
return ResultInvalidArraySize;
|
||||
}
|
||||
|
||||
Result result = state[aruid_index].data.SetSupportedNpadIdType(supported_npad_list);
|
||||
if (result.IsSuccess() && active_data_aruid == aruid) {
|
||||
result = active_data.SetSupportedNpadIdType(supported_npad_list);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool NPadResource::IsControllerSupported(u64 aruid, Core::HID::NpadStyleIndex style_index) const {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return false;
|
||||
}
|
||||
return state[aruid_index].data.IsNpadStyleIndexSupported(style_index);
|
||||
}
|
||||
|
||||
Result NPadResource::SetLrAssignmentMode(u64 aruid, bool is_enabled) {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return ResultNpadNotConnected;
|
||||
}
|
||||
|
||||
state[aruid_index].data.SetLrAssignmentMode(is_enabled);
|
||||
if (active_data_aruid == aruid) {
|
||||
active_data.SetLrAssignmentMode(is_enabled);
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NPadResource::GetLrAssignmentMode(bool& is_enabled, u64 aruid) const {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return ResultNpadNotConnected;
|
||||
}
|
||||
|
||||
is_enabled = state[aruid_index].data.GetLrAssignmentMode();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NPadResource::SetAssigningSingleOnSlSrPress(u64 aruid, bool is_enabled) {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return ResultNpadNotConnected;
|
||||
}
|
||||
|
||||
state[aruid_index].data.SetAssigningSingleOnSlSrPress(is_enabled);
|
||||
if (active_data_aruid == aruid) {
|
||||
active_data.SetAssigningSingleOnSlSrPress(is_enabled);
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NPadResource::IsAssigningSingleOnSlSrPressEnabled(bool& is_enabled, u64 aruid) const {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return ResultNpadNotConnected;
|
||||
}
|
||||
|
||||
is_enabled = state[aruid_index].data.GetAssigningSingleOnSlSrPress();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NPadResource::AcquireNpadStyleSetUpdateEventHandle(u64 aruid,
|
||||
Kernel::KReadableEvent** out_event,
|
||||
Core::HID::NpadIdType npad_id) {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return ResultNpadNotConnected;
|
||||
}
|
||||
|
||||
auto& controller_state = state[aruid_index].controller_state[NpadIdTypeToIndex(npad_id)];
|
||||
if (!controller_state.is_styleset_update_event_initialized) {
|
||||
// Auto clear = true
|
||||
controller_state.style_set_update_event =
|
||||
service_context.CreateEvent("NpadResource:StylesetUpdateEvent");
|
||||
|
||||
// Assume creating the event succeeds otherwise crash the system here
|
||||
controller_state.is_styleset_update_event_initialized = true;
|
||||
}
|
||||
|
||||
*out_event = &controller_state.style_set_update_event->GetReadableEvent();
|
||||
|
||||
if (controller_state.is_styleset_update_event_initialized) {
|
||||
controller_state.style_set_update_event->Signal();
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NPadResource::SignalStyleSetUpdateEvent(u64 aruid, Core::HID::NpadIdType npad_id) {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return ResultNpadNotConnected;
|
||||
}
|
||||
auto controller = state[aruid_index].controller_state[NpadIdTypeToIndex(npad_id)];
|
||||
if (controller.is_styleset_update_event_initialized) {
|
||||
controller.style_set_update_event->Signal();
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NPadResource::GetHomeProtectionEnabled(bool& is_enabled, u64 aruid,
|
||||
Core::HID::NpadIdType npad_id) const {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return ResultNpadNotConnected;
|
||||
}
|
||||
|
||||
is_enabled = state[aruid_index].data.GetHomeProtectionEnabled(npad_id);
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NPadResource::SetHomeProtectionEnabled(u64 aruid, Core::HID::NpadIdType npad_id,
|
||||
bool is_enabled) {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return ResultNpadNotConnected;
|
||||
}
|
||||
|
||||
state[aruid_index].data.SetHomeProtectionEnabled(is_enabled, npad_id);
|
||||
if (active_data_aruid == aruid) {
|
||||
active_data.SetHomeProtectionEnabled(is_enabled, npad_id);
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NPadResource::SetNpadAnalogStickUseCenterClamp(u64 aruid, bool is_enabled) {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return ResultNpadNotConnected;
|
||||
}
|
||||
|
||||
state[aruid_index].data.SetNpadAnalogStickUseCenterClamp(is_enabled);
|
||||
if (active_data_aruid == aruid) {
|
||||
active_data.SetNpadAnalogStickUseCenterClamp(is_enabled);
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NPadResource::SetButtonConfig(u64 aruid, Core::HID::NpadIdType npad_id, std::size_t index,
|
||||
Core::HID::NpadButton button_config) {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return ResultNpadNotConnected;
|
||||
}
|
||||
|
||||
state[aruid_index].button_config[NpadIdTypeToIndex(npad_id)][index] = button_config;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Core::HID::NpadButton NPadResource::GetButtonConfig(u64 aruid, Core::HID::NpadIdType npad_id,
|
||||
std::size_t index, Core::HID::NpadButton mask,
|
||||
bool is_enabled) {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return Core::HID::NpadButton::None;
|
||||
}
|
||||
|
||||
auto& button_config = state[aruid_index].button_config[NpadIdTypeToIndex(npad_id)][index];
|
||||
if (is_enabled) {
|
||||
button_config = button_config | mask;
|
||||
return button_config;
|
||||
}
|
||||
|
||||
button_config = Core::HID::NpadButton::None;
|
||||
return Core::HID::NpadButton::None;
|
||||
}
|
||||
|
||||
void NPadResource::ResetButtonConfig() {
|
||||
for (auto& selected_state : state) {
|
||||
selected_state.button_config = {};
|
||||
}
|
||||
}
|
||||
|
||||
Result NPadResource::SetNpadCaptureButtonAssignment(u64 aruid,
|
||||
Core::HID::NpadStyleSet npad_style_set,
|
||||
Core::HID::NpadButton button_assignment) {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return ResultNpadNotConnected;
|
||||
}
|
||||
|
||||
// Must be a power of two
|
||||
const auto raw_styleset = static_cast<u32>(npad_style_set);
|
||||
if (raw_styleset == 0 && (raw_styleset & (raw_styleset - 1)) != 0) {
|
||||
return ResultMultipleStyleSetSelected;
|
||||
}
|
||||
|
||||
std::size_t style_index{};
|
||||
Core::HID::NpadStyleSet style_selected{};
|
||||
for (style_index = 0; style_index < StyleIndexCount; ++style_index) {
|
||||
style_selected = GetStylesetByIndex(style_index);
|
||||
if (npad_style_set == style_selected) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (style_selected == Core::HID::NpadStyleSet::None) {
|
||||
return ResultMultipleStyleSetSelected;
|
||||
}
|
||||
|
||||
state[aruid_index].data.SetCaptureButtonAssignment(button_assignment, style_index);
|
||||
if (active_data_aruid == aruid) {
|
||||
active_data.SetCaptureButtonAssignment(button_assignment, style_index);
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NPadResource::ClearNpadCaptureButtonAssignment(u64 aruid) {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return ResultNpadNotConnected;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < StyleIndexCount; i++) {
|
||||
state[aruid_index].data.SetCaptureButtonAssignment(Core::HID::NpadButton::None, i);
|
||||
if (active_data_aruid == aruid) {
|
||||
active_data.SetCaptureButtonAssignment(Core::HID::NpadButton::None, i);
|
||||
}
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
std::size_t NPadResource::GetNpadCaptureButtonAssignment(std::span<Core::HID::NpadButton> out_list,
|
||||
u64 aruid) const {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return 0;
|
||||
}
|
||||
return state[aruid_index].data.GetNpadCaptureButtonAssignmentList(out_list);
|
||||
}
|
||||
|
||||
void NPadResource::SetNpadRevision(u64 aruid, NpadRevision revision) {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return;
|
||||
}
|
||||
|
||||
state[aruid_index].npad_revision = revision;
|
||||
}
|
||||
|
||||
Result NPadResource::SetNpadSystemExtStateEnabled(u64 aruid, bool is_enabled) {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index >= AruidIndexMax) {
|
||||
return ResultNpadNotConnected;
|
||||
}
|
||||
|
||||
state[aruid_index].data.SetNpadAnalogStickUseCenterClamp(is_enabled);
|
||||
if (active_data_aruid == aruid) {
|
||||
active_data.SetNpadAnalogStickUseCenterClamp(is_enabled);
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,132 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <mutex>
|
||||
#include <span>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/npad/npad_data.h"
|
||||
#include "core/hle/service/hid/controllers/types/npad_types.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
class KReadableEvent;
|
||||
}
|
||||
|
||||
namespace Service::HID {
|
||||
struct DataStatusFlag;
|
||||
|
||||
struct NpadControllerState {
|
||||
bool is_styleset_update_event_initialized{};
|
||||
INSERT_PADDING_BYTES(0x7);
|
||||
Kernel::KEvent* style_set_update_event{nullptr};
|
||||
INSERT_PADDING_BYTES(0x27);
|
||||
};
|
||||
|
||||
struct NpadState {
|
||||
DataStatusFlag flag{};
|
||||
u64 aruid{};
|
||||
NPadData data{};
|
||||
std::array<std::array<Core::HID::NpadButton, StyleIndexCount>, MaxSupportedNpadIdTypes>
|
||||
button_config;
|
||||
std::array<NpadControllerState, MaxSupportedNpadIdTypes> controller_state;
|
||||
NpadRevision npad_revision;
|
||||
};
|
||||
|
||||
/// Handles Npad request from HID interfaces
|
||||
class NPadResource final {
|
||||
public:
|
||||
explicit NPadResource(KernelHelpers::ServiceContext& context);
|
||||
~NPadResource();
|
||||
|
||||
NPadData* GetActiveData();
|
||||
u64 GetActiveDataAruid();
|
||||
|
||||
Result RegisterAppletResourceUserId(u64 aruid);
|
||||
void UnregisterAppletResourceUserId(u64 aruid);
|
||||
|
||||
void DestroyStyleSetUpdateEvents(u64 aruid);
|
||||
|
||||
Result Activate(u64 aruid);
|
||||
Result Activate();
|
||||
Result Deactivate();
|
||||
|
||||
void SetAppletResourceUserId(u64 aruid);
|
||||
std::size_t GetIndexFromAruid(u64 aruid) const;
|
||||
|
||||
Result ApplyNpadSystemCommonPolicy(u64 aruid, bool is_full_policy);
|
||||
Result ClearNpadSystemCommonPolicy(u64 aruid);
|
||||
|
||||
Result SetSupportedNpadStyleSet(u64 aruid, Core::HID::NpadStyleSet style_set);
|
||||
Result GetSupportedNpadStyleSet(Core::HID::NpadStyleSet& out_style_Set, u64 aruid) const;
|
||||
Result GetMaskedSupportedNpadStyleSet(Core::HID::NpadStyleSet& out_style_set, u64 aruid) const;
|
||||
Result GetAvailableStyleset(Core::HID::NpadStyleSet& out_style_set, u64 aruid) const;
|
||||
|
||||
NpadRevision GetNpadRevision(u64 aruid) const;
|
||||
void SetNpadRevision(u64 aruid, NpadRevision revision);
|
||||
|
||||
Result IsSupportedNpadStyleSet(bool& is_set, u64 aruid);
|
||||
|
||||
Result SetNpadJoyHoldType(u64 aruid, NpadJoyHoldType hold_type);
|
||||
Result GetNpadJoyHoldType(NpadJoyHoldType& hold_type, u64 aruid) const;
|
||||
|
||||
Result SetNpadHandheldActivationMode(u64 aruid, NpadHandheldActivationMode activation_mode);
|
||||
Result GetNpadHandheldActivationMode(NpadHandheldActivationMode& activation_mode,
|
||||
u64 aruid) const;
|
||||
|
||||
Result SetSupportedNpadIdType(u64 aruid,
|
||||
std::span<const Core::HID::NpadIdType> supported_npad_list);
|
||||
bool IsControllerSupported(u64 aruid, Core::HID::NpadStyleIndex style_index) const;
|
||||
|
||||
Result SetLrAssignmentMode(u64 aruid, bool is_enabled);
|
||||
Result GetLrAssignmentMode(bool& is_enabled, u64 aruid) const;
|
||||
|
||||
Result SetAssigningSingleOnSlSrPress(u64 aruid, bool is_enabled);
|
||||
Result IsAssigningSingleOnSlSrPressEnabled(bool& is_enabled, u64 aruid) const;
|
||||
|
||||
Result AcquireNpadStyleSetUpdateEventHandle(u64 aruid, Kernel::KReadableEvent** out_event,
|
||||
Core::HID::NpadIdType npad_id);
|
||||
Result SignalStyleSetUpdateEvent(u64 aruid, Core::HID::NpadIdType npad_id);
|
||||
|
||||
Result GetHomeProtectionEnabled(bool& is_enabled, u64 aruid,
|
||||
Core::HID::NpadIdType npad_id) const;
|
||||
Result SetHomeProtectionEnabled(u64 aruid, Core::HID::NpadIdType npad_id, bool is_enabled);
|
||||
|
||||
Result SetNpadAnalogStickUseCenterClamp(u64 aruid, bool is_enabled);
|
||||
|
||||
Result SetButtonConfig(u64 aruid, Core::HID::NpadIdType npad_id, std::size_t index,
|
||||
Core::HID::NpadButton button_config);
|
||||
Core::HID::NpadButton GetButtonConfig(u64 aruid, Core::HID::NpadIdType npad_id,
|
||||
std::size_t index, Core::HID::NpadButton mask,
|
||||
bool is_enabled);
|
||||
void ResetButtonConfig();
|
||||
|
||||
Result SetNpadCaptureButtonAssignment(u64 aruid, Core::HID::NpadStyleSet npad_style_set,
|
||||
Core::HID::NpadButton button_assignment);
|
||||
Result ClearNpadCaptureButtonAssignment(u64 aruid);
|
||||
std::size_t GetNpadCaptureButtonAssignment(std::span<Core::HID::NpadButton> out_list,
|
||||
u64 aruid) const;
|
||||
|
||||
Result SetNpadSystemExtStateEnabled(u64 aruid, bool is_enabled);
|
||||
|
||||
private:
|
||||
NPadData active_data{};
|
||||
AruidRegisterList registration_list{};
|
||||
std::array<NpadState, AruidIndexMax> state{};
|
||||
u64 active_data_aruid{};
|
||||
NpadJoyHoldType default_hold_type{};
|
||||
s32 ref_counter{};
|
||||
|
||||
KernelHelpers::ServiceContext& service_context;
|
||||
};
|
||||
} // namespace Service::HID
|
|
@ -1,226 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/service/hid/controllers/palma.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
Palma::Palma(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_)
|
||||
: ControllerBase{hid_core_}, service_context{service_context_} {
|
||||
controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other);
|
||||
operation_complete_event = service_context.CreateEvent("hid:PalmaOperationCompleteEvent");
|
||||
}
|
||||
|
||||
Palma::~Palma() {
|
||||
service_context.CloseEvent(operation_complete_event);
|
||||
};
|
||||
|
||||
void Palma::OnInit() {}
|
||||
|
||||
void Palma::OnRelease() {}
|
||||
|
||||
void Palma::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
if (!IsControllerActivated()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Result Palma::GetPalmaConnectionHandle(Core::HID::NpadIdType npad_id,
|
||||
PalmaConnectionHandle& handle) {
|
||||
active_handle.npad_id = npad_id;
|
||||
handle = active_handle;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result Palma::InitializePalma(const PalmaConnectionHandle& handle) {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
Activate();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Kernel::KReadableEvent& Palma::AcquirePalmaOperationCompleteEvent(
|
||||
const PalmaConnectionHandle& handle) const {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
LOG_ERROR(Service_HID, "Invalid npad id {}", handle.npad_id);
|
||||
}
|
||||
return operation_complete_event->GetReadableEvent();
|
||||
}
|
||||
|
||||
Result Palma::GetPalmaOperationInfo(const PalmaConnectionHandle& handle,
|
||||
PalmaOperationType& operation_type,
|
||||
PalmaOperationData& data) const {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
operation_type = operation.operation;
|
||||
data = operation.data;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result Palma::PlayPalmaActivity(const PalmaConnectionHandle& handle, u64 palma_activity) {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
operation.operation = PalmaOperationType::PlayActivity;
|
||||
operation.result = PalmaResultSuccess;
|
||||
operation.data = {};
|
||||
operation_complete_event->Signal();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result Palma::SetPalmaFrModeType(const PalmaConnectionHandle& handle, PalmaFrModeType fr_mode_) {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
fr_mode = fr_mode_;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result Palma::ReadPalmaStep(const PalmaConnectionHandle& handle) {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
operation.operation = PalmaOperationType::ReadStep;
|
||||
operation.result = PalmaResultSuccess;
|
||||
operation.data = {};
|
||||
operation_complete_event->Signal();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result Palma::EnablePalmaStep(const PalmaConnectionHandle& handle, bool is_enabled) {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result Palma::ResetPalmaStep(const PalmaConnectionHandle& handle) {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
void Palma::ReadPalmaApplicationSection() {}
|
||||
|
||||
void Palma::WritePalmaApplicationSection() {}
|
||||
|
||||
Result Palma::ReadPalmaUniqueCode(const PalmaConnectionHandle& handle) {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
operation.operation = PalmaOperationType::ReadUniqueCode;
|
||||
operation.result = PalmaResultSuccess;
|
||||
operation.data = {};
|
||||
operation_complete_event->Signal();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result Palma::SetPalmaUniqueCodeInvalid(const PalmaConnectionHandle& handle) {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
operation.operation = PalmaOperationType::SetUniqueCodeInvalid;
|
||||
operation.result = PalmaResultSuccess;
|
||||
operation.data = {};
|
||||
operation_complete_event->Signal();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
void Palma::WritePalmaActivityEntry() {}
|
||||
|
||||
Result Palma::WritePalmaRgbLedPatternEntry(const PalmaConnectionHandle& handle, u64 unknown) {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
operation.operation = PalmaOperationType::WriteRgbLedPatternEntry;
|
||||
operation.result = PalmaResultSuccess;
|
||||
operation.data = {};
|
||||
operation_complete_event->Signal();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result Palma::WritePalmaWaveEntry(const PalmaConnectionHandle& handle, PalmaWaveSet wave,
|
||||
Common::ProcessAddress t_mem, u64 size) {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
operation.operation = PalmaOperationType::WriteWaveEntry;
|
||||
operation.result = PalmaResultSuccess;
|
||||
operation.data = {};
|
||||
operation_complete_event->Signal();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result Palma::SetPalmaDataBaseIdentificationVersion(const PalmaConnectionHandle& handle,
|
||||
s32 database_id_version_) {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
database_id_version = database_id_version_;
|
||||
operation.operation = PalmaOperationType::ReadDataBaseIdentificationVersion;
|
||||
operation.result = PalmaResultSuccess;
|
||||
operation.data[0] = {};
|
||||
operation_complete_event->Signal();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result Palma::GetPalmaDataBaseIdentificationVersion(const PalmaConnectionHandle& handle) {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
operation.operation = PalmaOperationType::ReadDataBaseIdentificationVersion;
|
||||
operation.result = PalmaResultSuccess;
|
||||
operation.data = {};
|
||||
operation.data[0] = static_cast<u8>(database_id_version);
|
||||
operation_complete_event->Signal();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
void Palma::SuspendPalmaFeature() {}
|
||||
|
||||
Result Palma::GetPalmaOperationResult(const PalmaConnectionHandle& handle) const {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
return operation.result;
|
||||
}
|
||||
void Palma::ReadPalmaPlayLog() {}
|
||||
|
||||
void Palma::ResetPalmaPlayLog() {}
|
||||
|
||||
void Palma::SetIsPalmaAllConnectable(bool is_all_connectable) {
|
||||
// If true controllers are able to be paired
|
||||
is_connectable = is_all_connectable;
|
||||
}
|
||||
|
||||
void Palma::SetIsPalmaPairedConnectable() {}
|
||||
|
||||
Result Palma::PairPalma(const PalmaConnectionHandle& handle) {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
// TODO: Do something
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
void Palma::SetPalmaBoostMode(bool boost_mode) {}
|
||||
|
||||
void Palma::CancelWritePalmaWaveEntry() {}
|
||||
|
||||
void Palma::EnablePalmaBoostMode() {}
|
||||
|
||||
void Palma::GetPalmaBluetoothAddress() {}
|
||||
|
||||
void Palma::SetDisallowedPalmaConnection() {}
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,162 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/typed_address.h"
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
#include "core/hle/service/hid/errors.h"
|
||||
|
||||
namespace Kernel {
|
||||
class KEvent;
|
||||
class KReadableEvent;
|
||||
} // namespace Kernel
|
||||
|
||||
namespace Service::KernelHelpers {
|
||||
class ServiceContext;
|
||||
}
|
||||
|
||||
namespace Core::HID {
|
||||
class EmulatedController;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Service::HID {
|
||||
class Palma final : public ControllerBase {
|
||||
public:
|
||||
using PalmaOperationData = std::array<u8, 0x140>;
|
||||
|
||||
// This is nn::hid::PalmaOperationType
|
||||
enum class PalmaOperationType {
|
||||
PlayActivity,
|
||||
SetFrModeType,
|
||||
ReadStep,
|
||||
EnableStep,
|
||||
ResetStep,
|
||||
ReadApplicationSection,
|
||||
WriteApplicationSection,
|
||||
ReadUniqueCode,
|
||||
SetUniqueCodeInvalid,
|
||||
WriteActivityEntry,
|
||||
WriteRgbLedPatternEntry,
|
||||
WriteWaveEntry,
|
||||
ReadDataBaseIdentificationVersion,
|
||||
WriteDataBaseIdentificationVersion,
|
||||
SuspendFeature,
|
||||
ReadPlayLog,
|
||||
ResetPlayLog,
|
||||
};
|
||||
|
||||
// This is nn::hid::PalmaWaveSet
|
||||
enum class PalmaWaveSet : u64 {
|
||||
Small,
|
||||
Medium,
|
||||
Large,
|
||||
};
|
||||
|
||||
// This is nn::hid::PalmaFrModeType
|
||||
enum class PalmaFrModeType : u64 {
|
||||
Off,
|
||||
B01,
|
||||
B02,
|
||||
B03,
|
||||
Downloaded,
|
||||
};
|
||||
|
||||
// This is nn::hid::PalmaFeature
|
||||
enum class PalmaFeature : u64 {
|
||||
FrMode,
|
||||
RumbleFeedback,
|
||||
Step,
|
||||
MuteSwitch,
|
||||
};
|
||||
|
||||
// This is nn::hid::PalmaOperationInfo
|
||||
struct PalmaOperationInfo {
|
||||
PalmaOperationType operation{};
|
||||
Result result{PalmaResultSuccess};
|
||||
PalmaOperationData data{};
|
||||
};
|
||||
static_assert(sizeof(PalmaOperationInfo) == 0x148, "PalmaOperationInfo is an invalid size");
|
||||
|
||||
// This is nn::hid::PalmaActivityEntry
|
||||
struct PalmaActivityEntry {
|
||||
u32 rgb_led_pattern_index;
|
||||
INSERT_PADDING_BYTES(2);
|
||||
PalmaWaveSet wave_set;
|
||||
u32 wave_index;
|
||||
INSERT_PADDING_BYTES(12);
|
||||
};
|
||||
static_assert(sizeof(PalmaActivityEntry) == 0x20, "PalmaActivityEntry is an invalid size");
|
||||
|
||||
struct PalmaConnectionHandle {
|
||||
Core::HID::NpadIdType npad_id;
|
||||
INSERT_PADDING_BYTES(4); // Unknown
|
||||
};
|
||||
static_assert(sizeof(PalmaConnectionHandle) == 0x8,
|
||||
"PalmaConnectionHandle has incorrect size.");
|
||||
|
||||
explicit Palma(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_);
|
||||
~Palma() override;
|
||||
|
||||
// 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(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
Result GetPalmaConnectionHandle(Core::HID::NpadIdType npad_id, PalmaConnectionHandle& handle);
|
||||
Result InitializePalma(const PalmaConnectionHandle& handle);
|
||||
Kernel::KReadableEvent& AcquirePalmaOperationCompleteEvent(
|
||||
const PalmaConnectionHandle& handle) const;
|
||||
Result GetPalmaOperationInfo(const PalmaConnectionHandle& handle,
|
||||
PalmaOperationType& operation_type,
|
||||
PalmaOperationData& data) const;
|
||||
Result PlayPalmaActivity(const PalmaConnectionHandle& handle, u64 palma_activity);
|
||||
Result SetPalmaFrModeType(const PalmaConnectionHandle& handle, PalmaFrModeType fr_mode_);
|
||||
Result ReadPalmaStep(const PalmaConnectionHandle& handle);
|
||||
Result EnablePalmaStep(const PalmaConnectionHandle& handle, bool is_enabled);
|
||||
Result ResetPalmaStep(const PalmaConnectionHandle& handle);
|
||||
Result ReadPalmaUniqueCode(const PalmaConnectionHandle& handle);
|
||||
Result SetPalmaUniqueCodeInvalid(const PalmaConnectionHandle& handle);
|
||||
Result WritePalmaRgbLedPatternEntry(const PalmaConnectionHandle& handle, u64 unknown);
|
||||
Result WritePalmaWaveEntry(const PalmaConnectionHandle& handle, PalmaWaveSet wave,
|
||||
Common::ProcessAddress t_mem, u64 size);
|
||||
Result SetPalmaDataBaseIdentificationVersion(const PalmaConnectionHandle& handle,
|
||||
s32 database_id_version_);
|
||||
Result GetPalmaDataBaseIdentificationVersion(const PalmaConnectionHandle& handle);
|
||||
Result GetPalmaOperationResult(const PalmaConnectionHandle& handle) const;
|
||||
void SetIsPalmaAllConnectable(bool is_all_connectable);
|
||||
Result PairPalma(const PalmaConnectionHandle& handle);
|
||||
void SetPalmaBoostMode(bool boost_mode);
|
||||
|
||||
private:
|
||||
void ReadPalmaApplicationSection();
|
||||
void WritePalmaApplicationSection();
|
||||
void WritePalmaActivityEntry();
|
||||
void SuspendPalmaFeature();
|
||||
void ReadPalmaPlayLog();
|
||||
void ResetPalmaPlayLog();
|
||||
void SetIsPalmaPairedConnectable();
|
||||
void CancelWritePalmaWaveEntry();
|
||||
void EnablePalmaBoostMode();
|
||||
void GetPalmaBluetoothAddress();
|
||||
void SetDisallowedPalmaConnection();
|
||||
|
||||
bool is_connectable{};
|
||||
s32 database_id_version{};
|
||||
PalmaOperationInfo operation{};
|
||||
PalmaFrModeType fr_mode{};
|
||||
PalmaConnectionHandle active_handle{};
|
||||
|
||||
Core::HID::EmulatedController* controller;
|
||||
|
||||
Kernel::KEvent* operation_complete_event;
|
||||
KernelHelpers::ServiceContext& service_context;
|
||||
};
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,66 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include <cstring>
|
||||
#include "common/common_types.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/frontend/emu_window.h"
|
||||
#include "core/hid/emulated_console.h"
|
||||
#include "core/hid/emulated_devices.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/service/hid/controllers/seven_six_axis.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Service::HID {
|
||||
SevenSixAxis::SevenSixAxis(Core::System& system_)
|
||||
: ControllerBase{system_.HIDCore()}, system{system_} {
|
||||
console = hid_core.GetEmulatedConsole();
|
||||
}
|
||||
|
||||
SevenSixAxis::~SevenSixAxis() = default;
|
||||
|
||||
void SevenSixAxis::OnInit() {}
|
||||
void SevenSixAxis::OnRelease() {}
|
||||
|
||||
void SevenSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
if (!IsControllerActivated() || transfer_memory == 0) {
|
||||
seven_sixaxis_lifo.buffer_count = 0;
|
||||
seven_sixaxis_lifo.buffer_tail = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& last_entry = seven_sixaxis_lifo.ReadCurrentEntry().state;
|
||||
next_seven_sixaxis_state.sampling_number = last_entry.sampling_number + 1;
|
||||
|
||||
const auto motion_status = console->GetMotion();
|
||||
last_global_timestamp = core_timing.GetGlobalTimeNs().count();
|
||||
|
||||
// This value increments every time the switch goes to sleep
|
||||
next_seven_sixaxis_state.unknown = 1;
|
||||
next_seven_sixaxis_state.timestamp = last_global_timestamp - last_saved_timestamp;
|
||||
next_seven_sixaxis_state.accel = motion_status.accel;
|
||||
next_seven_sixaxis_state.gyro = motion_status.gyro;
|
||||
next_seven_sixaxis_state.quaternion = {
|
||||
{
|
||||
motion_status.quaternion.xyz.y,
|
||||
motion_status.quaternion.xyz.x,
|
||||
-motion_status.quaternion.w,
|
||||
},
|
||||
-motion_status.quaternion.xyz.z,
|
||||
};
|
||||
|
||||
seven_sixaxis_lifo.WriteNextEntry(next_seven_sixaxis_state);
|
||||
system.ApplicationMemory().WriteBlock(transfer_memory, &seven_sixaxis_lifo,
|
||||
sizeof(seven_sixaxis_lifo));
|
||||
}
|
||||
|
||||
void SevenSixAxis::SetTransferMemoryAddress(Common::ProcessAddress t_mem) {
|
||||
transfer_memory = t_mem;
|
||||
}
|
||||
|
||||
void SevenSixAxis::ResetTimestamp() {
|
||||
last_saved_timestamp = last_global_timestamp;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,65 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/quaternion.h"
|
||||
#include "common/typed_address.h"
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
#include "core/hle/service/hid/ring_lifo.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
} // namespace Core
|
||||
|
||||
namespace Core::HID {
|
||||
class EmulatedConsole;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Service::HID {
|
||||
class SevenSixAxis final : public ControllerBase {
|
||||
public:
|
||||
explicit SevenSixAxis(Core::System& system_);
|
||||
~SevenSixAxis() override;
|
||||
|
||||
// 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(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
// Called on InitializeSevenSixAxisSensor
|
||||
void SetTransferMemoryAddress(Common::ProcessAddress t_mem);
|
||||
|
||||
// Called on ResetSevenSixAxisSensorTimestamp
|
||||
void ResetTimestamp();
|
||||
|
||||
private:
|
||||
struct SevenSixAxisState {
|
||||
INSERT_PADDING_WORDS(2); // unused
|
||||
u64 timestamp{};
|
||||
u64 sampling_number{};
|
||||
u64 unknown{};
|
||||
Common::Vec3f accel{};
|
||||
Common::Vec3f gyro{};
|
||||
Common::Quaternion<f32> quaternion{};
|
||||
};
|
||||
static_assert(sizeof(SevenSixAxisState) == 0x48, "SevenSixAxisState is an invalid size");
|
||||
|
||||
Lifo<SevenSixAxisState, 0x21> seven_sixaxis_lifo{};
|
||||
static_assert(sizeof(seven_sixaxis_lifo) == 0xA70, "SevenSixAxisState is an invalid size");
|
||||
|
||||
u64 last_saved_timestamp{};
|
||||
u64 last_global_timestamp{};
|
||||
|
||||
SevenSixAxisState next_seven_sixaxis_state{};
|
||||
Common::ProcessAddress transfer_memory{};
|
||||
Core::HID::EmulatedConsole* console = nullptr;
|
||||
|
||||
Core::System& system;
|
||||
};
|
||||
} // namespace Service::HID
|
|
@ -1,54 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/k_shared_memory.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/shared_memory_holder.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
#include "core/hle/service/hid/errors.h"
|
||||
|
||||
namespace Service::HID {
|
||||
SharedMemoryHolder::SharedMemoryHolder() {}
|
||||
|
||||
SharedMemoryHolder::~SharedMemoryHolder() {
|
||||
Finalize();
|
||||
}
|
||||
|
||||
Result SharedMemoryHolder::Initialize(Core::System& system) {
|
||||
shared_memory = Kernel::KSharedMemory::Create(system.Kernel());
|
||||
const Result result = shared_memory->Initialize(
|
||||
system.DeviceMemory(), nullptr, Kernel::Svc::MemoryPermission::None,
|
||||
Kernel::Svc::MemoryPermission::Read, sizeof(SharedMemoryFormat));
|
||||
if (result.IsError()) {
|
||||
return result;
|
||||
}
|
||||
Kernel::KSharedMemory::Register(system.Kernel(), shared_memory);
|
||||
|
||||
is_created = true;
|
||||
is_mapped = true;
|
||||
address = std::construct_at(reinterpret_cast<SharedMemoryFormat*>(shared_memory->GetPointer()));
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
void SharedMemoryHolder::Finalize() {
|
||||
if (address != nullptr) {
|
||||
shared_memory->Close();
|
||||
}
|
||||
is_created = false;
|
||||
is_mapped = false;
|
||||
address = nullptr;
|
||||
}
|
||||
|
||||
bool SharedMemoryHolder::IsMapped() {
|
||||
return is_mapped;
|
||||
}
|
||||
|
||||
SharedMemoryFormat* SharedMemoryHolder::GetAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
Kernel::KSharedMemory* SharedMemoryHolder::GetHandle() {
|
||||
return shared_memory;
|
||||
}
|
||||
} // namespace Service::HID
|
|
@ -1,44 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
class KSharedMemory;
|
||||
}
|
||||
|
||||
namespace Service::HID {
|
||||
struct SharedMemoryFormat;
|
||||
|
||||
// This is nn::hid::detail::SharedMemoryHolder
|
||||
class SharedMemoryHolder {
|
||||
public:
|
||||
SharedMemoryHolder();
|
||||
~SharedMemoryHolder();
|
||||
|
||||
Result Initialize(Core::System& system);
|
||||
void Finalize();
|
||||
|
||||
bool IsMapped();
|
||||
SharedMemoryFormat* GetAddress();
|
||||
Kernel::KSharedMemory* GetHandle();
|
||||
|
||||
private:
|
||||
bool is_owner{};
|
||||
bool is_created{};
|
||||
bool is_mapped{};
|
||||
INSERT_PADDING_BYTES(0x5);
|
||||
Kernel::KSharedMemory* shared_memory;
|
||||
INSERT_PADDING_BYTES(0x38);
|
||||
SharedMemoryFormat* address = nullptr;
|
||||
};
|
||||
// Correct size is 0x50 bytes
|
||||
static_assert(sizeof(SharedMemoryHolder) == 0x50, "SharedMemoryHolder is an invalid size");
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,421 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/service/hid/controllers/npad.h"
|
||||
#include "core/hle/service/hid/controllers/six_axis.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
#include "core/hle/service/hid/errors.h"
|
||||
#include "core/hle/service/hid/hid_util.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
SixAxis::SixAxis(Core::HID::HIDCore& hid_core_, std::shared_ptr<NPad> npad_)
|
||||
: ControllerBase{hid_core_}, npad{npad_} {
|
||||
for (std::size_t i = 0; i < controller_data.size(); ++i) {
|
||||
auto& controller = controller_data[i];
|
||||
controller.device = hid_core.GetEmulatedControllerByIndex(i);
|
||||
}
|
||||
}
|
||||
|
||||
SixAxis::~SixAxis() = default;
|
||||
|
||||
void SixAxis::OnInit() {}
|
||||
void SixAxis::OnRelease() {}
|
||||
|
||||
void SixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
std::scoped_lock shared_lock{*shared_mutex};
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr || !data->flag.is_assigned) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < controller_data.size(); ++i) {
|
||||
NpadSharedMemoryEntry& shared_memory = data->shared_memory_format->npad.npad_entry[i];
|
||||
auto& controller = controller_data[i];
|
||||
const auto& controller_type = controller.device->GetNpadStyleIndex();
|
||||
|
||||
if (controller_type == Core::HID::NpadStyleIndex::None ||
|
||||
!controller.device->IsConnected()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& motion_state = controller.device->GetMotions();
|
||||
auto& sixaxis_fullkey_state = controller.sixaxis_fullkey_state;
|
||||
auto& sixaxis_handheld_state = controller.sixaxis_handheld_state;
|
||||
auto& sixaxis_dual_left_state = controller.sixaxis_dual_left_state;
|
||||
auto& sixaxis_dual_right_state = controller.sixaxis_dual_right_state;
|
||||
auto& sixaxis_left_lifo_state = controller.sixaxis_left_lifo_state;
|
||||
auto& sixaxis_right_lifo_state = controller.sixaxis_right_lifo_state;
|
||||
|
||||
auto& sixaxis_fullkey_lifo = shared_memory.internal_state.sixaxis_fullkey_lifo;
|
||||
auto& sixaxis_handheld_lifo = shared_memory.internal_state.sixaxis_handheld_lifo;
|
||||
auto& sixaxis_dual_left_lifo = shared_memory.internal_state.sixaxis_dual_left_lifo;
|
||||
auto& sixaxis_dual_right_lifo = shared_memory.internal_state.sixaxis_dual_right_lifo;
|
||||
auto& sixaxis_left_lifo = shared_memory.internal_state.sixaxis_left_lifo;
|
||||
auto& sixaxis_right_lifo = shared_memory.internal_state.sixaxis_right_lifo;
|
||||
|
||||
// Clear previous state
|
||||
sixaxis_fullkey_state = {};
|
||||
sixaxis_handheld_state = {};
|
||||
sixaxis_dual_left_state = {};
|
||||
sixaxis_dual_right_state = {};
|
||||
sixaxis_left_lifo_state = {};
|
||||
sixaxis_right_lifo_state = {};
|
||||
|
||||
if (controller.sixaxis_sensor_enabled && Settings::values.motion_enabled.GetValue()) {
|
||||
controller.sixaxis_at_rest = true;
|
||||
for (std::size_t e = 0; e < motion_state.size(); ++e) {
|
||||
controller.sixaxis_at_rest =
|
||||
controller.sixaxis_at_rest && motion_state[e].is_at_rest;
|
||||
}
|
||||
}
|
||||
|
||||
const auto set_motion_state = [&](Core::HID::SixAxisSensorState& state,
|
||||
const Core::HID::ControllerMotion& hid_state) {
|
||||
using namespace std::literals::chrono_literals;
|
||||
static constexpr Core::HID::SixAxisSensorState default_motion_state = {
|
||||
.delta_time = std::chrono::nanoseconds(5ms).count(),
|
||||
.accel = {0, 0, -1.0f},
|
||||
.orientation =
|
||||
{
|
||||
Common::Vec3f{1.0f, 0, 0},
|
||||
Common::Vec3f{0, 1.0f, 0},
|
||||
Common::Vec3f{0, 0, 1.0f},
|
||||
},
|
||||
.attribute = {1},
|
||||
};
|
||||
if (!controller.sixaxis_sensor_enabled) {
|
||||
state = default_motion_state;
|
||||
return;
|
||||
}
|
||||
if (!Settings::values.motion_enabled.GetValue()) {
|
||||
state = default_motion_state;
|
||||
return;
|
||||
}
|
||||
state.attribute.is_connected.Assign(1);
|
||||
state.delta_time = std::chrono::nanoseconds(5ms).count();
|
||||
state.accel = hid_state.accel;
|
||||
state.gyro = hid_state.gyro;
|
||||
state.rotation = hid_state.rotation;
|
||||
state.orientation = hid_state.orientation;
|
||||
};
|
||||
|
||||
switch (controller_type) {
|
||||
case Core::HID::NpadStyleIndex::None:
|
||||
ASSERT(false);
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::ProController:
|
||||
set_motion_state(sixaxis_fullkey_state, motion_state[0]);
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::Handheld:
|
||||
set_motion_state(sixaxis_handheld_state, motion_state[0]);
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::JoyconDual:
|
||||
set_motion_state(sixaxis_dual_left_state, motion_state[0]);
|
||||
set_motion_state(sixaxis_dual_right_state, motion_state[1]);
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::JoyconLeft:
|
||||
set_motion_state(sixaxis_left_lifo_state, motion_state[0]);
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::JoyconRight:
|
||||
set_motion_state(sixaxis_right_lifo_state, motion_state[1]);
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::Pokeball:
|
||||
using namespace std::literals::chrono_literals;
|
||||
set_motion_state(sixaxis_fullkey_state, motion_state[0]);
|
||||
sixaxis_fullkey_state.delta_time = std::chrono::nanoseconds(15ms).count();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
sixaxis_fullkey_state.sampling_number =
|
||||
sixaxis_fullkey_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
|
||||
sixaxis_handheld_state.sampling_number =
|
||||
sixaxis_handheld_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
|
||||
sixaxis_dual_left_state.sampling_number =
|
||||
sixaxis_dual_left_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
|
||||
sixaxis_dual_right_state.sampling_number =
|
||||
sixaxis_dual_right_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
|
||||
sixaxis_left_lifo_state.sampling_number =
|
||||
sixaxis_left_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
|
||||
sixaxis_right_lifo_state.sampling_number =
|
||||
sixaxis_right_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
|
||||
|
||||
if (IndexToNpadIdType(i) == Core::HID::NpadIdType::Handheld) {
|
||||
// This buffer only is updated on handheld on HW
|
||||
sixaxis_handheld_lifo.lifo.WriteNextEntry(sixaxis_handheld_state);
|
||||
} else {
|
||||
// Handheld doesn't update this buffer on HW
|
||||
sixaxis_fullkey_lifo.lifo.WriteNextEntry(sixaxis_fullkey_state);
|
||||
}
|
||||
|
||||
sixaxis_dual_left_lifo.lifo.WriteNextEntry(sixaxis_dual_left_state);
|
||||
sixaxis_dual_right_lifo.lifo.WriteNextEntry(sixaxis_dual_right_state);
|
||||
sixaxis_left_lifo.lifo.WriteNextEntry(sixaxis_left_lifo_state);
|
||||
sixaxis_right_lifo.lifo.WriteNextEntry(sixaxis_right_lifo_state);
|
||||
}
|
||||
}
|
||||
|
||||
Result SixAxis::SetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
Core::HID::GyroscopeZeroDriftMode drift_mode) {
|
||||
const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
|
||||
if (is_valid.IsError()) {
|
||||
LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
auto& sixaxis = GetSixaxisState(sixaxis_handle);
|
||||
auto& controller = GetControllerFromHandle(sixaxis_handle);
|
||||
sixaxis.gyroscope_zero_drift_mode = drift_mode;
|
||||
controller.device->SetGyroscopeZeroDriftMode(drift_mode);
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result SixAxis::GetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
Core::HID::GyroscopeZeroDriftMode& drift_mode) const {
|
||||
const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
|
||||
if (is_valid.IsError()) {
|
||||
LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
const auto& sixaxis = GetSixaxisState(sixaxis_handle);
|
||||
drift_mode = sixaxis.gyroscope_zero_drift_mode;
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result SixAxis::IsSixAxisSensorAtRest(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
bool& is_at_rest) const {
|
||||
const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
|
||||
if (is_valid.IsError()) {
|
||||
LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
const auto& controller = GetControllerFromHandle(sixaxis_handle);
|
||||
is_at_rest = controller.sixaxis_at_rest;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result SixAxis::LoadSixAxisSensorCalibrationParameter(
|
||||
const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
Core::HID::SixAxisSensorCalibrationParameter& calibration) const {
|
||||
const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
|
||||
if (is_valid.IsError()) {
|
||||
LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
// TODO: Request this data to the controller. On error return 0xd8ca
|
||||
const auto& sixaxis = GetSixaxisState(sixaxis_handle);
|
||||
calibration = sixaxis.calibration;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result SixAxis::GetSixAxisSensorIcInformation(
|
||||
const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
Core::HID::SixAxisSensorIcInformation& ic_information) const {
|
||||
const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
|
||||
if (is_valid.IsError()) {
|
||||
LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
// TODO: Request this data to the controller. On error return 0xd8ca
|
||||
const auto& sixaxis = GetSixaxisState(sixaxis_handle);
|
||||
ic_information = sixaxis.ic_information;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result SixAxis::EnableSixAxisSensorUnalteredPassthrough(
|
||||
const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool is_enabled) {
|
||||
const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
|
||||
if (is_valid.IsError()) {
|
||||
LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
auto& sixaxis = GetSixaxisState(sixaxis_handle);
|
||||
sixaxis.unaltered_passtrough = is_enabled;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result SixAxis::IsSixAxisSensorUnalteredPassthroughEnabled(
|
||||
const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_enabled) const {
|
||||
const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
|
||||
if (is_valid.IsError()) {
|
||||
LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
const auto& sixaxis = GetSixaxisState(sixaxis_handle);
|
||||
is_enabled = sixaxis.unaltered_passtrough;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result SixAxis::SetSixAxisEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
bool sixaxis_status) {
|
||||
const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
|
||||
if (is_valid.IsError()) {
|
||||
LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
auto& controller = GetControllerFromHandle(sixaxis_handle);
|
||||
controller.sixaxis_sensor_enabled = sixaxis_status;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result SixAxis::IsSixAxisSensorFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
bool& is_fusion_enabled) const {
|
||||
const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
|
||||
if (is_valid.IsError()) {
|
||||
LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
const auto& sixaxis = GetSixaxisState(sixaxis_handle);
|
||||
is_fusion_enabled = sixaxis.is_fusion_enabled;
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
Result SixAxis::SetSixAxisFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
bool is_fusion_enabled) {
|
||||
const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
|
||||
if (is_valid.IsError()) {
|
||||
LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
auto& sixaxis = GetSixaxisState(sixaxis_handle);
|
||||
sixaxis.is_fusion_enabled = is_fusion_enabled;
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result SixAxis::SetSixAxisFusionParameters(
|
||||
const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters) {
|
||||
const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
|
||||
if (is_valid.IsError()) {
|
||||
LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
const auto param1 = sixaxis_fusion_parameters.parameter1;
|
||||
if (param1 < 0.0f || param1 > 1.0f) {
|
||||
return InvalidSixAxisFusionRange;
|
||||
}
|
||||
|
||||
auto& sixaxis = GetSixaxisState(sixaxis_handle);
|
||||
sixaxis.fusion = sixaxis_fusion_parameters;
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result SixAxis::GetSixAxisFusionParameters(
|
||||
const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
Core::HID::SixAxisSensorFusionParameters& parameters) const {
|
||||
const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
|
||||
if (is_valid.IsError()) {
|
||||
LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
const auto& sixaxis = GetSixaxisState(sixaxis_handle);
|
||||
parameters = sixaxis.fusion;
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
SixAxis::SixaxisParameters& SixAxis::GetSixaxisState(
|
||||
const Core::HID::SixAxisSensorHandle& sixaxis_handle) {
|
||||
auto& controller = GetControllerFromHandle(sixaxis_handle);
|
||||
switch (sixaxis_handle.npad_type) {
|
||||
case Core::HID::NpadStyleIndex::ProController:
|
||||
case Core::HID::NpadStyleIndex::Pokeball:
|
||||
return controller.sixaxis_fullkey;
|
||||
case Core::HID::NpadStyleIndex::Handheld:
|
||||
return controller.sixaxis_handheld;
|
||||
case Core::HID::NpadStyleIndex::JoyconDual:
|
||||
if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) {
|
||||
return controller.sixaxis_dual_left;
|
||||
}
|
||||
return controller.sixaxis_dual_right;
|
||||
case Core::HID::NpadStyleIndex::JoyconLeft:
|
||||
return controller.sixaxis_left;
|
||||
case Core::HID::NpadStyleIndex::JoyconRight:
|
||||
return controller.sixaxis_right;
|
||||
default:
|
||||
return controller.sixaxis_unknown;
|
||||
}
|
||||
}
|
||||
|
||||
const SixAxis::SixaxisParameters& SixAxis::GetSixaxisState(
|
||||
const Core::HID::SixAxisSensorHandle& sixaxis_handle) const {
|
||||
const auto& controller = GetControllerFromHandle(sixaxis_handle);
|
||||
switch (sixaxis_handle.npad_type) {
|
||||
case Core::HID::NpadStyleIndex::ProController:
|
||||
case Core::HID::NpadStyleIndex::Pokeball:
|
||||
return controller.sixaxis_fullkey;
|
||||
case Core::HID::NpadStyleIndex::Handheld:
|
||||
return controller.sixaxis_handheld;
|
||||
case Core::HID::NpadStyleIndex::JoyconDual:
|
||||
if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) {
|
||||
return controller.sixaxis_dual_left;
|
||||
}
|
||||
return controller.sixaxis_dual_right;
|
||||
case Core::HID::NpadStyleIndex::JoyconLeft:
|
||||
return controller.sixaxis_left;
|
||||
case Core::HID::NpadStyleIndex::JoyconRight:
|
||||
return controller.sixaxis_right;
|
||||
default:
|
||||
return controller.sixaxis_unknown;
|
||||
}
|
||||
}
|
||||
|
||||
SixAxis::NpadControllerData& SixAxis::GetControllerFromHandle(
|
||||
const Core::HID::SixAxisSensorHandle& device_handle) {
|
||||
const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id);
|
||||
return GetControllerFromNpadIdType(npad_id);
|
||||
}
|
||||
|
||||
const SixAxis::NpadControllerData& SixAxis::GetControllerFromHandle(
|
||||
const Core::HID::SixAxisSensorHandle& device_handle) const {
|
||||
const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id);
|
||||
return GetControllerFromNpadIdType(npad_id);
|
||||
}
|
||||
|
||||
SixAxis::NpadControllerData& SixAxis::GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) {
|
||||
if (!IsNpadIdValid(npad_id)) {
|
||||
LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
|
||||
npad_id = Core::HID::NpadIdType::Player1;
|
||||
}
|
||||
const auto npad_index = NpadIdTypeToIndex(npad_id);
|
||||
return controller_data[npad_index];
|
||||
}
|
||||
|
||||
const SixAxis::NpadControllerData& SixAxis::GetControllerFromNpadIdType(
|
||||
Core::HID::NpadIdType npad_id) const {
|
||||
if (!IsNpadIdValid(npad_id)) {
|
||||
LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
|
||||
npad_id = Core::HID::NpadIdType::Player1;
|
||||
}
|
||||
const auto npad_index = NpadIdTypeToIndex(npad_id);
|
||||
return controller_data[npad_index];
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,111 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
#include "core/hle/service/hid/ring_lifo.h"
|
||||
|
||||
namespace Core::HID {
|
||||
class EmulatedController;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Service::HID {
|
||||
class NPad;
|
||||
|
||||
class SixAxis final : public ControllerBase {
|
||||
public:
|
||||
explicit SixAxis(Core::HID::HIDCore& hid_core_, std::shared_ptr<NPad> npad_);
|
||||
~SixAxis() override;
|
||||
|
||||
// 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(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
Result SetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
Core::HID::GyroscopeZeroDriftMode drift_mode);
|
||||
Result GetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
Core::HID::GyroscopeZeroDriftMode& drift_mode) const;
|
||||
Result IsSixAxisSensorAtRest(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
bool& is_at_rest) const;
|
||||
Result EnableSixAxisSensorUnalteredPassthrough(
|
||||
const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool is_enabled);
|
||||
Result IsSixAxisSensorUnalteredPassthroughEnabled(
|
||||
const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_enabled) const;
|
||||
Result LoadSixAxisSensorCalibrationParameter(
|
||||
const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
Core::HID::SixAxisSensorCalibrationParameter& calibration) const;
|
||||
Result GetSixAxisSensorIcInformation(
|
||||
const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
Core::HID::SixAxisSensorIcInformation& ic_information) const;
|
||||
Result SetSixAxisEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
bool sixaxis_status);
|
||||
Result IsSixAxisSensorFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
bool& is_fusion_enabled) const;
|
||||
Result SetSixAxisFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
bool is_fusion_enabled);
|
||||
Result SetSixAxisFusionParameters(
|
||||
const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters);
|
||||
Result GetSixAxisFusionParameters(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
Core::HID::SixAxisSensorFusionParameters& parameters) const;
|
||||
|
||||
private:
|
||||
static constexpr std::size_t NPAD_COUNT = 10;
|
||||
|
||||
struct SixaxisParameters {
|
||||
bool is_fusion_enabled{true};
|
||||
bool unaltered_passtrough{false};
|
||||
Core::HID::SixAxisSensorFusionParameters fusion{};
|
||||
Core::HID::SixAxisSensorCalibrationParameter calibration{};
|
||||
Core::HID::SixAxisSensorIcInformation ic_information{};
|
||||
Core::HID::GyroscopeZeroDriftMode gyroscope_zero_drift_mode{
|
||||
Core::HID::GyroscopeZeroDriftMode::Standard};
|
||||
};
|
||||
|
||||
struct NpadControllerData {
|
||||
Core::HID::EmulatedController* device = nullptr;
|
||||
|
||||
// Motion parameters
|
||||
bool sixaxis_at_rest{true};
|
||||
bool sixaxis_sensor_enabled{true};
|
||||
SixaxisParameters sixaxis_fullkey{};
|
||||
SixaxisParameters sixaxis_handheld{};
|
||||
SixaxisParameters sixaxis_dual_left{};
|
||||
SixaxisParameters sixaxis_dual_right{};
|
||||
SixaxisParameters sixaxis_left{};
|
||||
SixaxisParameters sixaxis_right{};
|
||||
SixaxisParameters sixaxis_unknown{};
|
||||
|
||||
// Current pad state
|
||||
Core::HID::SixAxisSensorState sixaxis_fullkey_state{};
|
||||
Core::HID::SixAxisSensorState sixaxis_handheld_state{};
|
||||
Core::HID::SixAxisSensorState sixaxis_dual_left_state{};
|
||||
Core::HID::SixAxisSensorState sixaxis_dual_right_state{};
|
||||
Core::HID::SixAxisSensorState sixaxis_left_lifo_state{};
|
||||
Core::HID::SixAxisSensorState sixaxis_right_lifo_state{};
|
||||
int callback_key{};
|
||||
};
|
||||
|
||||
SixaxisParameters& GetSixaxisState(const Core::HID::SixAxisSensorHandle& device_handle);
|
||||
const SixaxisParameters& GetSixaxisState(
|
||||
const Core::HID::SixAxisSensorHandle& device_handle) const;
|
||||
|
||||
NpadControllerData& GetControllerFromHandle(
|
||||
const Core::HID::SixAxisSensorHandle& device_handle);
|
||||
const NpadControllerData& GetControllerFromHandle(
|
||||
const Core::HID::SixAxisSensorHandle& device_handle) const;
|
||||
NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id);
|
||||
const NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) const;
|
||||
|
||||
std::shared_ptr<NPad> npad;
|
||||
std::array<NpadControllerData, NPAD_COUNT> controller_data{};
|
||||
};
|
||||
} // namespace Service::HID
|
|
@ -1,39 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/sleep_button.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
SleepButton::SleepButton(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {}
|
||||
|
||||
SleepButton::~SleepButton() = default;
|
||||
|
||||
void SleepButton::OnInit() {}
|
||||
|
||||
void SleepButton::OnRelease() {}
|
||||
|
||||
void SleepButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
if (!smart_update) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::scoped_lock shared_lock{*shared_mutex};
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr || !data->flag.is_assigned) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& header = data->shared_memory_format->capture_button.header;
|
||||
header.timestamp = core_timing.GetGlobalTimeNs().count();
|
||||
header.total_entry_count = 17;
|
||||
header.entry_count = 0;
|
||||
header.last_entry_index = 0;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,27 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
class SleepButton final : public ControllerBase {
|
||||
public:
|
||||
explicit SleepButton(Core::HID::HIDCore& hid_core_);
|
||||
~SleepButton() override;
|
||||
|
||||
// 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(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
private:
|
||||
bool smart_update{};
|
||||
};
|
||||
} // namespace Service::HID
|
|
@ -1,132 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include "common/common_types.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/frontend/emu_window.h"
|
||||
#include "core/hid/emulated_console.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/touchscreen.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
TouchScreen::TouchScreen(Core::HID::HIDCore& hid_core_)
|
||||
: ControllerBase{hid_core_}, touchscreen_width(Layout::ScreenUndocked::Width),
|
||||
touchscreen_height(Layout::ScreenUndocked::Height) {
|
||||
console = hid_core.GetEmulatedConsole();
|
||||
}
|
||||
|
||||
TouchScreen::~TouchScreen() = default;
|
||||
|
||||
void TouchScreen::OnInit() {}
|
||||
|
||||
void TouchScreen::OnRelease() {}
|
||||
|
||||
void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr || !data->flag.is_assigned) {
|
||||
return;
|
||||
}
|
||||
|
||||
TouchScreenSharedMemoryFormat& shared_memory = data->shared_memory_format->touch_screen;
|
||||
shared_memory.touch_screen_lifo.timestamp = core_timing.GetGlobalTimeNs().count();
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
shared_memory.touch_screen_lifo.buffer_count = 0;
|
||||
shared_memory.touch_screen_lifo.buffer_tail = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto touch_status = console->GetTouch();
|
||||
for (std::size_t id = 0; id < MAX_FINGERS; id++) {
|
||||
const auto& current_touch = touch_status[id];
|
||||
auto& finger = fingers[id];
|
||||
finger.id = current_touch.id;
|
||||
|
||||
if (finger.attribute.start_touch) {
|
||||
finger.attribute.raw = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (finger.attribute.end_touch) {
|
||||
finger.attribute.raw = 0;
|
||||
finger.pressed = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!finger.pressed && current_touch.pressed) {
|
||||
// Ignore all touch fingers if disabled
|
||||
if (!Settings::values.touchscreen.enabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
finger.attribute.start_touch.Assign(1);
|
||||
finger.pressed = true;
|
||||
finger.position = current_touch.position;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (finger.pressed && !current_touch.pressed) {
|
||||
finger.attribute.raw = 0;
|
||||
finger.attribute.end_touch.Assign(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only update position if touch is not on a special frame
|
||||
finger.position = current_touch.position;
|
||||
}
|
||||
|
||||
std::array<Core::HID::TouchFinger, MAX_FINGERS> active_fingers;
|
||||
const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(),
|
||||
[](const auto& finger) { return finger.pressed; });
|
||||
const auto active_fingers_count =
|
||||
static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter));
|
||||
|
||||
const u64 timestamp = static_cast<u64>(core_timing.GetGlobalTimeNs().count());
|
||||
const auto& last_entry = shared_memory.touch_screen_lifo.ReadCurrentEntry().state;
|
||||
|
||||
next_state.sampling_number = last_entry.sampling_number + 1;
|
||||
next_state.entry_count = static_cast<s32>(active_fingers_count);
|
||||
|
||||
for (std::size_t id = 0; id < MAX_FINGERS; ++id) {
|
||||
auto& touch_entry = next_state.states[id];
|
||||
if (id < active_fingers_count) {
|
||||
const auto& [active_x, active_y] = active_fingers[id].position;
|
||||
touch_entry.position = {
|
||||
.x = static_cast<u16>(active_x * static_cast<float>(touchscreen_width)),
|
||||
.y = static_cast<u16>(active_y * static_cast<float>(touchscreen_height)),
|
||||
};
|
||||
touch_entry.diameter_x = Settings::values.touchscreen.diameter_x;
|
||||
touch_entry.diameter_y = Settings::values.touchscreen.diameter_y;
|
||||
touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle;
|
||||
touch_entry.delta_time = timestamp - active_fingers[id].last_touch;
|
||||
fingers[active_fingers[id].id].last_touch = timestamp;
|
||||
touch_entry.finger = active_fingers[id].id;
|
||||
touch_entry.attribute.raw = active_fingers[id].attribute.raw;
|
||||
} else {
|
||||
// Clear touch entry
|
||||
touch_entry.attribute.raw = 0;
|
||||
touch_entry.position = {};
|
||||
touch_entry.diameter_x = 0;
|
||||
touch_entry.diameter_y = 0;
|
||||
touch_entry.rotation_angle = 0;
|
||||
touch_entry.delta_time = 0;
|
||||
touch_entry.finger = 0;
|
||||
}
|
||||
}
|
||||
|
||||
shared_memory.touch_screen_lifo.WriteNextEntry(next_state);
|
||||
}
|
||||
|
||||
void TouchScreen::SetTouchscreenDimensions(u32 width, u32 height) {
|
||||
touchscreen_width = width;
|
||||
touchscreen_height = height;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,43 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
#include "core/hle/service/hid/controllers/types/touch_types.h"
|
||||
|
||||
namespace Core::HID {
|
||||
class EmulatedConsole;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Service::HID {
|
||||
struct TouchScreenSharedMemoryFormat;
|
||||
|
||||
class TouchScreen final : public ControllerBase {
|
||||
public:
|
||||
explicit TouchScreen(Core::HID::HIDCore& hid_core_);
|
||||
~TouchScreen() override;
|
||||
|
||||
// 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(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
void SetTouchscreenDimensions(u32 width, u32 height);
|
||||
|
||||
private:
|
||||
TouchScreenState next_state{};
|
||||
Core::HID::EmulatedConsole* console = nullptr;
|
||||
|
||||
std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers{};
|
||||
u32 touchscreen_width;
|
||||
u32 touchscreen_height;
|
||||
};
|
||||
} // namespace Service::HID
|
|
@ -1,31 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
// This is nn::hid::DebugPadAttribute
|
||||
struct DebugPadAttribute {
|
||||
union {
|
||||
u32 raw{};
|
||||
BitField<0, 1, u32> connected;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(DebugPadAttribute) == 0x4, "DebugPadAttribute is an invalid size");
|
||||
|
||||
// This is nn::hid::DebugPadState
|
||||
struct DebugPadState {
|
||||
s64 sampling_number{};
|
||||
DebugPadAttribute attribute{};
|
||||
Core::HID::DebugPadButton pad_state{};
|
||||
Core::HID::AnalogStickState r_stick{};
|
||||
Core::HID::AnalogStickState l_stick{};
|
||||
};
|
||||
static_assert(sizeof(DebugPadState) == 0x20, "DebugPadState is an invalid state");
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,77 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/point.h"
|
||||
|
||||
namespace Service::HID {
|
||||
static constexpr size_t MAX_FINGERS = 16;
|
||||
static constexpr size_t MAX_POINTS = 4;
|
||||
|
||||
// This is nn::hid::GestureType
|
||||
enum class GestureType : u32 {
|
||||
Idle, // Nothing touching the screen
|
||||
Complete, // Set at the end of a touch event
|
||||
Cancel, // Set when the number of fingers change
|
||||
Touch, // A finger just touched the screen
|
||||
Press, // Set if last type is touch and the finger hasn't moved
|
||||
Tap, // Fast press then release
|
||||
Pan, // All points moving together across the screen
|
||||
Swipe, // Fast press movement and release of a single point
|
||||
Pinch, // All points moving away/closer to the midpoint
|
||||
Rotate, // All points rotating from the midpoint
|
||||
};
|
||||
|
||||
// This is nn::hid::GestureDirection
|
||||
enum class GestureDirection : u32 {
|
||||
None,
|
||||
Left,
|
||||
Up,
|
||||
Right,
|
||||
Down,
|
||||
};
|
||||
|
||||
// This is nn::hid::GestureAttribute
|
||||
struct GestureAttribute {
|
||||
union {
|
||||
u32 raw{};
|
||||
|
||||
BitField<4, 1, u32> is_new_touch;
|
||||
BitField<8, 1, u32> is_double_tap;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size");
|
||||
|
||||
// This is nn::hid::GestureState
|
||||
struct GestureState {
|
||||
s64 sampling_number{};
|
||||
s64 detection_count{};
|
||||
GestureType type{GestureType::Idle};
|
||||
GestureDirection direction{GestureDirection::None};
|
||||
Common::Point<s32> pos{};
|
||||
Common::Point<s32> delta{};
|
||||
f32 vel_x{};
|
||||
f32 vel_y{};
|
||||
GestureAttribute attributes{};
|
||||
f32 scale{};
|
||||
f32 rotation_angle{};
|
||||
s32 point_count{};
|
||||
std::array<Common::Point<s32>, 4> points{};
|
||||
};
|
||||
static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size");
|
||||
|
||||
struct GestureProperties {
|
||||
std::array<Common::Point<s32>, MAX_POINTS> points{};
|
||||
std::size_t active_points{};
|
||||
Common::Point<s32> mid_point{};
|
||||
s64 detection_count{};
|
||||
u64 delta_time{};
|
||||
f32 average_distance{};
|
||||
f32 angle{};
|
||||
};
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,20 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
// This is nn::hid::detail::KeyboardState
|
||||
struct KeyboardState {
|
||||
s64 sampling_number{};
|
||||
Core::HID::KeyboardModifier modifier{};
|
||||
Core::HID::KeyboardAttribute attribute{};
|
||||
Core::HID::KeyboardKey key{};
|
||||
};
|
||||
static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size");
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,8 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Service::HID {} // namespace Service::HID
|
|
@ -1,255 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
|
||||
namespace Service::HID {
|
||||
static constexpr std::size_t MaxSupportedNpadIdTypes = 10;
|
||||
static constexpr std::size_t StyleIndexCount = 7;
|
||||
|
||||
// This is nn::hid::NpadJoyHoldType
|
||||
enum class NpadJoyHoldType : u64 {
|
||||
Vertical = 0,
|
||||
Horizontal = 1,
|
||||
};
|
||||
|
||||
// This is nn::hid::NpadJoyAssignmentMode
|
||||
enum class NpadJoyAssignmentMode : u32 {
|
||||
Dual = 0,
|
||||
Single = 1,
|
||||
};
|
||||
|
||||
// This is nn::hid::NpadJoyDeviceType
|
||||
enum class NpadJoyDeviceType : s64 {
|
||||
Left = 0,
|
||||
Right = 1,
|
||||
};
|
||||
|
||||
// This is nn::hid::NpadHandheldActivationMode
|
||||
enum class NpadHandheldActivationMode : u64 {
|
||||
Dual = 0,
|
||||
Single = 1,
|
||||
None = 2,
|
||||
MaxActivationMode = 3,
|
||||
};
|
||||
|
||||
// This is nn::hid::system::AppletFooterUiAttributesSet
|
||||
struct AppletFooterUiAttributes {
|
||||
INSERT_PADDING_BYTES(0x4);
|
||||
};
|
||||
|
||||
// This is nn::hid::system::AppletFooterUiType
|
||||
enum class AppletFooterUiType : u8 {
|
||||
None = 0,
|
||||
HandheldNone = 1,
|
||||
HandheldJoyConLeftOnly = 2,
|
||||
HandheldJoyConRightOnly = 3,
|
||||
HandheldJoyConLeftJoyConRight = 4,
|
||||
JoyDual = 5,
|
||||
JoyDualLeftOnly = 6,
|
||||
JoyDualRightOnly = 7,
|
||||
JoyLeftHorizontal = 8,
|
||||
JoyLeftVertical = 9,
|
||||
JoyRightHorizontal = 10,
|
||||
JoyRightVertical = 11,
|
||||
SwitchProController = 12,
|
||||
CompatibleProController = 13,
|
||||
CompatibleJoyCon = 14,
|
||||
LarkHvc1 = 15,
|
||||
LarkHvc2 = 16,
|
||||
LarkNesLeft = 17,
|
||||
LarkNesRight = 18,
|
||||
Lucia = 19,
|
||||
Verification = 20,
|
||||
Lagon = 21,
|
||||
};
|
||||
|
||||
using AppletFooterUiVariant = u8;
|
||||
|
||||
// This is "nn::hid::system::AppletDetailedUiType".
|
||||
struct AppletDetailedUiType {
|
||||
AppletFooterUiVariant ui_variant;
|
||||
INSERT_PADDING_BYTES(0x2);
|
||||
AppletFooterUiType footer;
|
||||
};
|
||||
static_assert(sizeof(AppletDetailedUiType) == 0x4, "AppletDetailedUiType is an invalid size");
|
||||
// This is nn::hid::NpadCommunicationMode
|
||||
enum class NpadCommunicationMode : u64 {
|
||||
Mode_5ms = 0,
|
||||
Mode_10ms = 1,
|
||||
Mode_15ms = 2,
|
||||
Default = 3,
|
||||
};
|
||||
|
||||
enum class NpadRevision : u32 {
|
||||
Revision0 = 0,
|
||||
Revision1 = 1,
|
||||
Revision2 = 2,
|
||||
Revision3 = 3,
|
||||
};
|
||||
|
||||
// This is nn::hid::detail::ColorAttribute
|
||||
enum class ColorAttribute : u32 {
|
||||
Ok = 0,
|
||||
ReadError = 1,
|
||||
NoController = 2,
|
||||
};
|
||||
static_assert(sizeof(ColorAttribute) == 4, "ColorAttribute is an invalid size");
|
||||
|
||||
// This is nn::hid::detail::NpadFullKeyColorState
|
||||
struct NpadFullKeyColorState {
|
||||
ColorAttribute attribute{ColorAttribute::NoController};
|
||||
Core::HID::NpadControllerColor fullkey{};
|
||||
};
|
||||
static_assert(sizeof(NpadFullKeyColorState) == 0xC, "NpadFullKeyColorState is an invalid size");
|
||||
|
||||
// This is nn::hid::detail::NpadJoyColorState
|
||||
struct NpadJoyColorState {
|
||||
ColorAttribute attribute{ColorAttribute::NoController};
|
||||
Core::HID::NpadControllerColor left{};
|
||||
Core::HID::NpadControllerColor right{};
|
||||
};
|
||||
static_assert(sizeof(NpadJoyColorState) == 0x14, "NpadJoyColorState is an invalid size");
|
||||
|
||||
// This is nn::hid::NpadAttribute
|
||||
struct NpadAttribute {
|
||||
union {
|
||||
u32 raw{};
|
||||
BitField<0, 1, u32> is_connected;
|
||||
BitField<1, 1, u32> is_wired;
|
||||
BitField<2, 1, u32> is_left_connected;
|
||||
BitField<3, 1, u32> is_left_wired;
|
||||
BitField<4, 1, u32> is_right_connected;
|
||||
BitField<5, 1, u32> is_right_wired;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(NpadAttribute) == 4, "NpadAttribute is an invalid size");
|
||||
|
||||
// This is nn::hid::NpadFullKeyState
|
||||
// This is nn::hid::NpadHandheldState
|
||||
// This is nn::hid::NpadJoyDualState
|
||||
// This is nn::hid::NpadJoyLeftState
|
||||
// This is nn::hid::NpadJoyRightState
|
||||
// This is nn::hid::NpadPalmaState
|
||||
// This is nn::hid::NpadSystemExtState
|
||||
struct NPadGenericState {
|
||||
s64_le sampling_number{};
|
||||
Core::HID::NpadButtonState npad_buttons{};
|
||||
Core::HID::AnalogStickState l_stick{};
|
||||
Core::HID::AnalogStickState r_stick{};
|
||||
NpadAttribute connection_status{};
|
||||
INSERT_PADDING_BYTES(4); // Reserved
|
||||
};
|
||||
static_assert(sizeof(NPadGenericState) == 0x28, "NPadGenericState is an invalid size");
|
||||
|
||||
// This is nn::hid::server::NpadGcTriggerState
|
||||
struct NpadGcTriggerState {
|
||||
s64 sampling_number{};
|
||||
s32 l_analog{};
|
||||
s32 r_analog{};
|
||||
};
|
||||
static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size");
|
||||
|
||||
// This is nn::hid::NpadSystemProperties
|
||||
struct NPadSystemProperties {
|
||||
union {
|
||||
s64 raw{};
|
||||
BitField<0, 1, s64> is_charging_joy_dual;
|
||||
BitField<1, 1, s64> is_charging_joy_left;
|
||||
BitField<2, 1, s64> is_charging_joy_right;
|
||||
BitField<3, 1, s64> is_powered_joy_dual;
|
||||
BitField<4, 1, s64> is_powered_joy_left;
|
||||
BitField<5, 1, s64> is_powered_joy_right;
|
||||
BitField<9, 1, s64> is_system_unsupported_button;
|
||||
BitField<10, 1, s64> is_system_ext_unsupported_button;
|
||||
BitField<11, 1, s64> is_vertical;
|
||||
BitField<12, 1, s64> is_horizontal;
|
||||
BitField<13, 1, s64> use_plus;
|
||||
BitField<14, 1, s64> use_minus;
|
||||
BitField<15, 1, s64> use_directional_buttons;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(NPadSystemProperties) == 0x8, "NPadSystemProperties is an invalid size");
|
||||
|
||||
// This is nn::hid::NpadSystemButtonProperties
|
||||
struct NpadSystemButtonProperties {
|
||||
union {
|
||||
s32 raw{};
|
||||
BitField<0, 1, s32> is_home_button_protection_enabled;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(NpadSystemButtonProperties) == 0x4, "NPadButtonProperties is an invalid size");
|
||||
|
||||
// This is nn::hid::system::DeviceType
|
||||
struct DeviceType {
|
||||
union {
|
||||
u32 raw{};
|
||||
BitField<0, 1, s32> fullkey;
|
||||
BitField<1, 1, s32> debug_pad;
|
||||
BitField<2, 1, s32> handheld_left;
|
||||
BitField<3, 1, s32> handheld_right;
|
||||
BitField<4, 1, s32> joycon_left;
|
||||
BitField<5, 1, s32> joycon_right;
|
||||
BitField<6, 1, s32> palma;
|
||||
BitField<7, 1, s32> lark_hvc_left;
|
||||
BitField<8, 1, s32> lark_hvc_right;
|
||||
BitField<9, 1, s32> lark_nes_left;
|
||||
BitField<10, 1, s32> lark_nes_right;
|
||||
BitField<11, 1, s32> handheld_lark_hvc_left;
|
||||
BitField<12, 1, s32> handheld_lark_hvc_right;
|
||||
BitField<13, 1, s32> handheld_lark_nes_left;
|
||||
BitField<14, 1, s32> handheld_lark_nes_right;
|
||||
BitField<15, 1, s32> lucia;
|
||||
BitField<16, 1, s32> lagon;
|
||||
BitField<17, 1, s32> lager;
|
||||
BitField<31, 1, s32> system;
|
||||
};
|
||||
};
|
||||
|
||||
// This is nn::hid::detail::NfcXcdDeviceHandleStateImpl
|
||||
struct NfcXcdDeviceHandleStateImpl {
|
||||
u64 handle{};
|
||||
bool is_available{};
|
||||
bool is_activated{};
|
||||
INSERT_PADDING_BYTES(0x6); // Reserved
|
||||
u64 sampling_number{};
|
||||
};
|
||||
static_assert(sizeof(NfcXcdDeviceHandleStateImpl) == 0x18,
|
||||
"NfcXcdDeviceHandleStateImpl is an invalid size");
|
||||
|
||||
// This is nn::hid::NpadLarkType
|
||||
enum class NpadLarkType : u32 {
|
||||
Invalid,
|
||||
H1,
|
||||
H2,
|
||||
NL,
|
||||
NR,
|
||||
};
|
||||
|
||||
// This is nn::hid::NpadLuciaType
|
||||
enum class NpadLuciaType : u32 {
|
||||
Invalid,
|
||||
J,
|
||||
E,
|
||||
U,
|
||||
};
|
||||
|
||||
// This is nn::hid::NpadLagonType
|
||||
enum class NpadLagonType : u32 {
|
||||
Invalid,
|
||||
};
|
||||
|
||||
// This is nn::hid::NpadLagerType
|
||||
enum class NpadLagerType : u32 {
|
||||
Invalid,
|
||||
J,
|
||||
E,
|
||||
U,
|
||||
};
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,240 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/vector_math.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/service/hid//controllers/types/debug_pad_types.h"
|
||||
#include "core/hle/service/hid//controllers/types/keyboard_types.h"
|
||||
#include "core/hle/service/hid//controllers/types/mouse_types.h"
|
||||
#include "core/hle/service/hid//controllers/types/npad_types.h"
|
||||
#include "core/hle/service/hid//controllers/types/touch_types.h"
|
||||
#include "core/hle/service/hid/ring_lifo.h"
|
||||
|
||||
namespace Service::HID {
|
||||
static const std::size_t HidEntryCount = 17;
|
||||
|
||||
struct CommonHeader {
|
||||
s64 timestamp{};
|
||||
s64 total_entry_count{};
|
||||
s64 last_entry_index{};
|
||||
s64 entry_count{};
|
||||
};
|
||||
static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size");
|
||||
|
||||
// This is nn::hid::detail::DebugPadSharedMemoryFormat
|
||||
struct DebugPadSharedMemoryFormat {
|
||||
// This is nn::hid::detail::DebugPadLifo
|
||||
Lifo<DebugPadState, HidEntryCount> debug_pad_lifo{};
|
||||
static_assert(sizeof(debug_pad_lifo) == 0x2C8, "debug_pad_lifo is an invalid size");
|
||||
INSERT_PADDING_WORDS(0x4E);
|
||||
};
|
||||
static_assert(sizeof(DebugPadSharedMemoryFormat) == 0x400,
|
||||
"DebugPadSharedMemoryFormat is an invalid size");
|
||||
|
||||
// This is nn::hid::detail::TouchScreenSharedMemoryFormat
|
||||
struct TouchScreenSharedMemoryFormat {
|
||||
// This is nn::hid::detail::TouchScreenLifo
|
||||
Lifo<TouchScreenState, HidEntryCount> touch_screen_lifo{};
|
||||
static_assert(sizeof(touch_screen_lifo) == 0x2C38, "touch_screen_lifo is an invalid size");
|
||||
INSERT_PADDING_WORDS(0xF2);
|
||||
};
|
||||
static_assert(sizeof(TouchScreenSharedMemoryFormat) == 0x3000,
|
||||
"TouchScreenSharedMemoryFormat is an invalid size");
|
||||
|
||||
// This is nn::hid::detail::MouseSharedMemoryFormat
|
||||
struct MouseSharedMemoryFormat {
|
||||
// This is nn::hid::detail::MouseLifo
|
||||
Lifo<Core::HID::MouseState, HidEntryCount> mouse_lifo{};
|
||||
static_assert(sizeof(mouse_lifo) == 0x350, "mouse_lifo is an invalid size");
|
||||
INSERT_PADDING_WORDS(0x2C);
|
||||
};
|
||||
static_assert(sizeof(MouseSharedMemoryFormat) == 0x400,
|
||||
"MouseSharedMemoryFormat is an invalid size");
|
||||
|
||||
// This is nn::hid::detail::KeyboardSharedMemoryFormat
|
||||
struct KeyboardSharedMemoryFormat {
|
||||
// This is nn::hid::detail::KeyboardLifo
|
||||
Lifo<KeyboardState, HidEntryCount> keyboard_lifo{};
|
||||
static_assert(sizeof(keyboard_lifo) == 0x3D8, "keyboard_lifo is an invalid size");
|
||||
INSERT_PADDING_WORDS(0xA);
|
||||
};
|
||||
static_assert(sizeof(KeyboardSharedMemoryFormat) == 0x400,
|
||||
"KeyboardSharedMemoryFormat is an invalid size");
|
||||
|
||||
// This is nn::hid::detail::DigitizerSharedMemoryFormat
|
||||
struct DigitizerSharedMemoryFormat {
|
||||
CommonHeader header;
|
||||
INSERT_PADDING_BYTES(0xFE0);
|
||||
};
|
||||
static_assert(sizeof(DigitizerSharedMemoryFormat) == 0x1000,
|
||||
"DigitizerSharedMemoryFormat is an invalid size");
|
||||
|
||||
// This is nn::hid::detail::HomeButtonSharedMemoryFormat
|
||||
struct HomeButtonSharedMemoryFormat {
|
||||
CommonHeader header;
|
||||
INSERT_PADDING_BYTES(0x1E0);
|
||||
};
|
||||
static_assert(sizeof(HomeButtonSharedMemoryFormat) == 0x200,
|
||||
"HomeButtonSharedMemoryFormat is an invalid size");
|
||||
|
||||
// This is nn::hid::detail::SleepButtonSharedMemoryFormat
|
||||
struct SleepButtonSharedMemoryFormat {
|
||||
CommonHeader header;
|
||||
INSERT_PADDING_BYTES(0x1E0);
|
||||
};
|
||||
static_assert(sizeof(SleepButtonSharedMemoryFormat) == 0x200,
|
||||
"SleepButtonSharedMemoryFormat is an invalid size");
|
||||
|
||||
// This is nn::hid::detail::CaptureButtonSharedMemoryFormat
|
||||
struct CaptureButtonSharedMemoryFormat {
|
||||
CommonHeader header;
|
||||
INSERT_PADDING_BYTES(0x1E0);
|
||||
};
|
||||
static_assert(sizeof(CaptureButtonSharedMemoryFormat) == 0x200,
|
||||
"CaptureButtonSharedMemoryFormat is an invalid size");
|
||||
|
||||
// This is nn::hid::detail::InputDetectorSharedMemoryFormat
|
||||
struct InputDetectorSharedMemoryFormat {
|
||||
CommonHeader header;
|
||||
INSERT_PADDING_BYTES(0x7E0);
|
||||
};
|
||||
static_assert(sizeof(InputDetectorSharedMemoryFormat) == 0x800,
|
||||
"InputDetectorSharedMemoryFormat is an invalid size");
|
||||
|
||||
// This is nn::hid::detail::UniquePadSharedMemoryFormat
|
||||
struct UniquePadSharedMemoryFormat {
|
||||
CommonHeader header;
|
||||
INSERT_PADDING_BYTES(0x3FE0);
|
||||
};
|
||||
static_assert(sizeof(UniquePadSharedMemoryFormat) == 0x4000,
|
||||
"UniquePadSharedMemoryFormat is an invalid size");
|
||||
|
||||
// This is nn::hid::detail::NpadSixAxisSensorLifo
|
||||
struct NpadSixAxisSensorLifo {
|
||||
Lifo<Core::HID::SixAxisSensorState, HidEntryCount> lifo;
|
||||
};
|
||||
|
||||
// This is nn::hid::detail::NpadInternalState
|
||||
struct NpadInternalState {
|
||||
Core::HID::NpadStyleTag style_tag{Core::HID::NpadStyleSet::None};
|
||||
NpadJoyAssignmentMode assignment_mode{NpadJoyAssignmentMode::Dual};
|
||||
NpadFullKeyColorState fullkey_color{};
|
||||
NpadJoyColorState joycon_color{};
|
||||
Lifo<NPadGenericState, HidEntryCount> fullkey_lifo{};
|
||||
Lifo<NPadGenericState, HidEntryCount> handheld_lifo{};
|
||||
Lifo<NPadGenericState, HidEntryCount> joy_dual_lifo{};
|
||||
Lifo<NPadGenericState, HidEntryCount> joy_left_lifo{};
|
||||
Lifo<NPadGenericState, HidEntryCount> joy_right_lifo{};
|
||||
Lifo<NPadGenericState, HidEntryCount> palma_lifo{};
|
||||
Lifo<NPadGenericState, HidEntryCount> system_ext_lifo{};
|
||||
NpadSixAxisSensorLifo sixaxis_fullkey_lifo{};
|
||||
NpadSixAxisSensorLifo sixaxis_handheld_lifo{};
|
||||
NpadSixAxisSensorLifo sixaxis_dual_left_lifo{};
|
||||
NpadSixAxisSensorLifo sixaxis_dual_right_lifo{};
|
||||
NpadSixAxisSensorLifo sixaxis_left_lifo{};
|
||||
NpadSixAxisSensorLifo sixaxis_right_lifo{};
|
||||
DeviceType device_type{};
|
||||
INSERT_PADDING_BYTES(0x4); // Reserved
|
||||
NPadSystemProperties system_properties{};
|
||||
NpadSystemButtonProperties button_properties{};
|
||||
Core::HID::NpadBatteryLevel battery_level_dual{};
|
||||
Core::HID::NpadBatteryLevel battery_level_left{};
|
||||
Core::HID::NpadBatteryLevel battery_level_right{};
|
||||
AppletFooterUiAttributes applet_footer_attributes{};
|
||||
AppletFooterUiType applet_footer_type{AppletFooterUiType::None};
|
||||
INSERT_PADDING_BYTES(0x5B); // Reserved
|
||||
INSERT_PADDING_BYTES(0x20); // Unknown
|
||||
Lifo<NpadGcTriggerState, HidEntryCount> gc_trigger_lifo{};
|
||||
NpadLarkType lark_type_l_and_main{};
|
||||
NpadLarkType lark_type_r{};
|
||||
NpadLuciaType lucia_type{};
|
||||
NpadLagerType lager_type{};
|
||||
Core::HID::SixAxisSensorProperties sixaxis_fullkey_properties;
|
||||
Core::HID::SixAxisSensorProperties sixaxis_handheld_properties;
|
||||
Core::HID::SixAxisSensorProperties sixaxis_dual_left_properties;
|
||||
Core::HID::SixAxisSensorProperties sixaxis_dual_right_properties;
|
||||
Core::HID::SixAxisSensorProperties sixaxis_left_properties;
|
||||
Core::HID::SixAxisSensorProperties sixaxis_right_properties;
|
||||
};
|
||||
static_assert(sizeof(NpadInternalState) == 0x43F8, "NpadInternalState is an invalid size");
|
||||
|
||||
// This is nn::hid::detail::NpadSharedMemoryEntry
|
||||
struct NpadSharedMemoryEntry {
|
||||
NpadInternalState internal_state;
|
||||
INSERT_PADDING_BYTES(0xC08);
|
||||
};
|
||||
static_assert(sizeof(NpadSharedMemoryEntry) == 0x5000, "NpadSharedMemoryEntry is an invalid size");
|
||||
|
||||
// This is nn::hid::detail::NpadSharedMemoryFormat
|
||||
struct NpadSharedMemoryFormat {
|
||||
std::array<NpadSharedMemoryEntry, MaxSupportedNpadIdTypes> npad_entry;
|
||||
};
|
||||
static_assert(sizeof(NpadSharedMemoryFormat) == 0x32000,
|
||||
"NpadSharedMemoryFormat is an invalid size");
|
||||
|
||||
// This is nn::hid::detail::GestureSharedMemoryFormat
|
||||
struct GestureSharedMemoryFormat {
|
||||
// This is nn::hid::detail::GestureLifo
|
||||
Lifo<GestureState, HidEntryCount> gesture_lifo{};
|
||||
static_assert(sizeof(gesture_lifo) == 0x708, "gesture_lifo is an invalid size");
|
||||
INSERT_PADDING_WORDS(0x3E);
|
||||
};
|
||||
static_assert(sizeof(GestureSharedMemoryFormat) == 0x800,
|
||||
"GestureSharedMemoryFormat is an invalid size");
|
||||
|
||||
// This is nn::hid::detail::ConsoleSixAxisSensorSharedMemoryFormat
|
||||
struct ConsoleSixAxisSensorSharedMemoryFormat {
|
||||
u64 sampling_number{};
|
||||
bool is_seven_six_axis_sensor_at_rest{};
|
||||
INSERT_PADDING_BYTES(3); // padding
|
||||
f32 verticalization_error{};
|
||||
Common::Vec3f gyro_bias{};
|
||||
INSERT_PADDING_BYTES(4); // padding
|
||||
};
|
||||
static_assert(sizeof(ConsoleSixAxisSensorSharedMemoryFormat) == 0x20,
|
||||
"ConsoleSixAxisSensorSharedMemoryFormat is an invalid size");
|
||||
|
||||
// This is nn::hid::detail::SharedMemoryFormat
|
||||
struct SharedMemoryFormat {
|
||||
void Initialize() {}
|
||||
|
||||
DebugPadSharedMemoryFormat debug_pad;
|
||||
TouchScreenSharedMemoryFormat touch_screen;
|
||||
MouseSharedMemoryFormat mouse;
|
||||
KeyboardSharedMemoryFormat keyboard;
|
||||
DigitizerSharedMemoryFormat digitizer;
|
||||
HomeButtonSharedMemoryFormat home_button;
|
||||
SleepButtonSharedMemoryFormat sleep_button;
|
||||
CaptureButtonSharedMemoryFormat capture_button;
|
||||
InputDetectorSharedMemoryFormat input_detector;
|
||||
UniquePadSharedMemoryFormat unique_pad;
|
||||
NpadSharedMemoryFormat npad;
|
||||
GestureSharedMemoryFormat gesture;
|
||||
ConsoleSixAxisSensorSharedMemoryFormat console;
|
||||
INSERT_PADDING_BYTES(0x19E0);
|
||||
MouseSharedMemoryFormat debug_mouse;
|
||||
INSERT_PADDING_BYTES(0x2000);
|
||||
};
|
||||
static_assert(offsetof(SharedMemoryFormat, debug_pad) == 0x0, "debug_pad has wrong offset");
|
||||
static_assert(offsetof(SharedMemoryFormat, touch_screen) == 0x400, "touch_screen has wrong offset");
|
||||
static_assert(offsetof(SharedMemoryFormat, mouse) == 0x3400, "mouse has wrong offset");
|
||||
static_assert(offsetof(SharedMemoryFormat, keyboard) == 0x3800, "keyboard has wrong offset");
|
||||
static_assert(offsetof(SharedMemoryFormat, digitizer) == 0x3C00, "digitizer has wrong offset");
|
||||
static_assert(offsetof(SharedMemoryFormat, home_button) == 0x4C00, "home_button has wrong offset");
|
||||
static_assert(offsetof(SharedMemoryFormat, sleep_button) == 0x4E00,
|
||||
"sleep_button has wrong offset");
|
||||
static_assert(offsetof(SharedMemoryFormat, capture_button) == 0x5000,
|
||||
"capture_button has wrong offset");
|
||||
static_assert(offsetof(SharedMemoryFormat, input_detector) == 0x5200,
|
||||
"input_detector has wrong offset");
|
||||
static_assert(offsetof(SharedMemoryFormat, npad) == 0x9A00, "npad has wrong offset");
|
||||
static_assert(offsetof(SharedMemoryFormat, gesture) == 0x3BA00, "gesture has wrong offset");
|
||||
static_assert(offsetof(SharedMemoryFormat, console) == 0x3C200, "console has wrong offset");
|
||||
static_assert(offsetof(SharedMemoryFormat, debug_mouse) == 0x3DC00, "debug_mouse has wrong offset");
|
||||
static_assert(sizeof(SharedMemoryFormat) == 0x40000, "SharedMemoryFormat is an invalid size");
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,90 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <array>
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/point.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
|
||||
namespace Service::HID {
|
||||
static constexpr std::size_t MAX_FINGERS = 16;
|
||||
static constexpr size_t MAX_POINTS = 4;
|
||||
|
||||
// This is nn::hid::GestureType
|
||||
enum class GestureType : u32 {
|
||||
Idle, // Nothing touching the screen
|
||||
Complete, // Set at the end of a touch event
|
||||
Cancel, // Set when the number of fingers change
|
||||
Touch, // A finger just touched the screen
|
||||
Press, // Set if last type is touch and the finger hasn't moved
|
||||
Tap, // Fast press then release
|
||||
Pan, // All points moving together across the screen
|
||||
Swipe, // Fast press movement and release of a single point
|
||||
Pinch, // All points moving away/closer to the midpoint
|
||||
Rotate, // All points rotating from the midpoint
|
||||
};
|
||||
|
||||
// This is nn::hid::GestureDirection
|
||||
enum class GestureDirection : u32 {
|
||||
None,
|
||||
Left,
|
||||
Up,
|
||||
Right,
|
||||
Down,
|
||||
};
|
||||
|
||||
// This is nn::hid::GestureAttribute
|
||||
struct GestureAttribute {
|
||||
union {
|
||||
u32 raw{};
|
||||
|
||||
BitField<4, 1, u32> is_new_touch;
|
||||
BitField<8, 1, u32> is_double_tap;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size");
|
||||
|
||||
// This is nn::hid::GestureState
|
||||
struct GestureState {
|
||||
s64 sampling_number{};
|
||||
s64 detection_count{};
|
||||
GestureType type{GestureType::Idle};
|
||||
GestureDirection direction{GestureDirection::None};
|
||||
Common::Point<s32> pos{};
|
||||
Common::Point<s32> delta{};
|
||||
f32 vel_x{};
|
||||
f32 vel_y{};
|
||||
GestureAttribute attributes{};
|
||||
f32 scale{};
|
||||
f32 rotation_angle{};
|
||||
s32 point_count{};
|
||||
std::array<Common::Point<s32>, 4> points{};
|
||||
};
|
||||
static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size");
|
||||
|
||||
struct GestureProperties {
|
||||
std::array<Common::Point<s32>, MAX_POINTS> points{};
|
||||
std::size_t active_points{};
|
||||
Common::Point<s32> mid_point{};
|
||||
s64 detection_count{};
|
||||
u64 delta_time{};
|
||||
f32 average_distance{};
|
||||
f32 angle{};
|
||||
};
|
||||
|
||||
// This is nn::hid::TouchScreenState
|
||||
struct TouchScreenState {
|
||||
s64 sampling_number{};
|
||||
s32 entry_count{};
|
||||
INSERT_PADDING_BYTES(4); // Reserved
|
||||
std::array<Core::HID::TouchState, MAX_FINGERS> states{};
|
||||
};
|
||||
static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size");
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,38 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
#include "core/hle/service/hid/controllers/unique_pad.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
UniquePad::UniquePad(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {}
|
||||
|
||||
UniquePad::~UniquePad() = default;
|
||||
|
||||
void UniquePad::OnInit() {}
|
||||
|
||||
void UniquePad::OnRelease() {}
|
||||
|
||||
void UniquePad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
if (!smart_update) {
|
||||
return;
|
||||
}
|
||||
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr || !data->flag.is_assigned) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& header = data->shared_memory_format->capture_button.header;
|
||||
header.timestamp = core_timing.GetGlobalTimeNs().count();
|
||||
header.total_entry_count = 17;
|
||||
header.entry_count = 0;
|
||||
header.last_entry_index = 0;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,27 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
class UniquePad final : public ControllerBase {
|
||||
public:
|
||||
explicit UniquePad(Core::HID::HIDCore& hid_core_);
|
||||
~UniquePad() override;
|
||||
|
||||
// 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(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
private:
|
||||
bool smart_update{};
|
||||
};
|
||||
} // namespace Service::HID
|
|
@ -1,59 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
constexpr Result PalmaResultSuccess{ErrorModule::HID, 0};
|
||||
constexpr Result NpadInvalidHandle{ErrorModule::HID, 100};
|
||||
constexpr Result NpadDeviceIndexOutOfRange{ErrorModule::HID, 107};
|
||||
|
||||
constexpr Result ResultVibrationNotInitialized{ErrorModule::HID, 121};
|
||||
constexpr Result ResultVibrationInvalidStyleIndex{ErrorModule::HID, 122};
|
||||
constexpr Result ResultVibrationInvalidNpadId{ErrorModule::HID, 123};
|
||||
constexpr Result ResultVibrationDeviceIndexOutOfRange{ErrorModule::HID, 124};
|
||||
constexpr Result ResultVibrationStrenghtOutOfRange{ErrorModule::HID, 126};
|
||||
constexpr Result ResultVibrationArraySizeMismatch{ErrorModule::HID, 131};
|
||||
|
||||
constexpr Result InvalidSixAxisFusionRange{ErrorModule::HID, 423};
|
||||
|
||||
constexpr Result ResultNfcIsNotReady{ErrorModule::HID, 461};
|
||||
constexpr Result ResultNfcXcdHandleIsNotInitialized{ErrorModule::HID, 464};
|
||||
constexpr Result ResultIrSensorIsNotReady{ErrorModule::HID, 501};
|
||||
constexpr Result ResultMcuIsNotReady{ErrorModule::HID, 541};
|
||||
|
||||
constexpr Result NpadIsDualJoycon{ErrorModule::HID, 601};
|
||||
constexpr Result NpadIsSameType{ErrorModule::HID, 602};
|
||||
constexpr Result ResultNpadIsNotProController{ErrorModule::HID, 604};
|
||||
|
||||
constexpr Result ResultInvalidNpadId{ErrorModule::HID, 709};
|
||||
constexpr Result ResultNpadNotConnected{ErrorModule::HID, 710};
|
||||
constexpr Result ResultNpadHandlerOverflow{ErrorModule::HID, 711};
|
||||
constexpr Result ResultNpadHandlerNotInitialized{ErrorModule::HID, 712};
|
||||
constexpr Result ResultInvalidArraySize{ErrorModule::HID, 715};
|
||||
constexpr Result ResultUndefinedStyleset{ErrorModule::HID, 716};
|
||||
constexpr Result ResultMultipleStyleSetSelected{ErrorModule::HID, 717};
|
||||
|
||||
constexpr Result ResultAppletResourceOverflow{ErrorModule::HID, 1041};
|
||||
constexpr Result ResultAppletResourceNotInitialized{ErrorModule::HID, 1042};
|
||||
constexpr Result ResultSharedMemoryNotInitialized{ErrorModule::HID, 1043};
|
||||
constexpr Result ResultAruidNoAvailableEntries{ErrorModule::HID, 1044};
|
||||
constexpr Result ResultAruidAlreadyRegistered{ErrorModule::HID, 1046};
|
||||
constexpr Result ResultAruidNotRegistered{ErrorModule::HID, 1047};
|
||||
|
||||
constexpr Result ResultNpadResourceOverflow{ErrorModule::HID, 2001};
|
||||
constexpr Result ResultNpadResourceNotInitialized{ErrorModule::HID, 2002};
|
||||
|
||||
constexpr Result InvalidPalmaHandle{ErrorModule::HID, 3302};
|
||||
|
||||
} // namespace Service::HID
|
||||
|
||||
namespace Service::IRS {
|
||||
|
||||
constexpr Result InvalidProcessorState{ErrorModule::Irsensor, 78};
|
||||
constexpr Result InvalidIrCameraHandle{ErrorModule::Irsensor, 204};
|
||||
|
||||
} // namespace Service::IRS
|
|
@ -5,14 +5,14 @@
|
|||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/service/hid/hid.h"
|
||||
#include "core/hle/service/hid/hid_debug_server.h"
|
||||
#include "core/hle/service/hid/hid_firmware_settings.h"
|
||||
#include "core/hle/service/hid/hid_server.h"
|
||||
#include "core/hle/service/hid/hid_system_server.h"
|
||||
#include "core/hle/service/hid/hidbus.h"
|
||||
#include "core/hle/service/hid/irs.h"
|
||||
#include "core/hle/service/hid/resource_manager.h"
|
||||
#include "core/hle/service/hid/xcd.h"
|
||||
#include "core/hle/service/server_manager.h"
|
||||
#include "hid_core/resource_manager.h"
|
||||
#include "hid_core/resources/hid_firmware_settings.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "core/hle/service/hid/hid_debug_server.h"
|
||||
#include "core/hle/service/hid/resource_manager.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "hid_core/resource_manager.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "core/hle/service/hid/hid_firmware_settings.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
HidFirmwareSettings::HidFirmwareSettings() {
|
||||
LoadSettings(true);
|
||||
}
|
||||
|
||||
void HidFirmwareSettings::Reload() {
|
||||
LoadSettings(true);
|
||||
}
|
||||
|
||||
void HidFirmwareSettings::LoadSettings(bool reload_config) {
|
||||
if (is_initalized && !reload_config) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Use nn::settings::fwdbg::GetSettingsItemValue to load config values
|
||||
|
||||
is_debug_pad_enabled = true;
|
||||
is_device_managed = true;
|
||||
is_touch_i2c_managed = is_device_managed;
|
||||
is_future_devices_emulated = false;
|
||||
is_mcu_hardware_error_emulated = false;
|
||||
is_rail_enabled = true;
|
||||
is_firmware_update_failure_emulated = false;
|
||||
is_firmware_update_failure = {};
|
||||
is_ble_disabled = false;
|
||||
is_dscale_disabled = false;
|
||||
is_handheld_forced = true;
|
||||
features_per_id_disabled = {};
|
||||
is_touch_firmware_auto_update_disabled = false;
|
||||
is_initalized = true;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsDebugPadEnabled() {
|
||||
LoadSettings(false);
|
||||
return is_debug_pad_enabled;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsDeviceManaged() {
|
||||
LoadSettings(false);
|
||||
return is_device_managed;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsEmulateFutureDevice() {
|
||||
LoadSettings(false);
|
||||
return is_future_devices_emulated;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsTouchI2cManaged() {
|
||||
LoadSettings(false);
|
||||
return is_touch_i2c_managed;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsHandheldForced() {
|
||||
LoadSettings(false);
|
||||
return is_handheld_forced;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsRailEnabled() {
|
||||
LoadSettings(false);
|
||||
return is_rail_enabled;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsHardwareErrorEmulated() {
|
||||
LoadSettings(false);
|
||||
return is_mcu_hardware_error_emulated;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsBleDisabled() {
|
||||
LoadSettings(false);
|
||||
return is_ble_disabled;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsDscaleDisabled() {
|
||||
LoadSettings(false);
|
||||
return is_dscale_disabled;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsTouchAutoUpdateDisabled() {
|
||||
LoadSettings(false);
|
||||
return is_touch_firmware_auto_update_disabled;
|
||||
}
|
||||
|
||||
HidFirmwareSettings::FirmwareSetting HidFirmwareSettings::GetFirmwareUpdateFailure() {
|
||||
LoadSettings(false);
|
||||
return is_firmware_update_failure;
|
||||
}
|
||||
|
||||
HidFirmwareSettings::FeaturesPerId HidFirmwareSettings::FeaturesDisabledPerId() {
|
||||
LoadSettings(false);
|
||||
return features_per_id_disabled;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,54 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
/// Loads firmware config from nn::settings::fwdbg
|
||||
class HidFirmwareSettings {
|
||||
public:
|
||||
using FirmwareSetting = std::array<u8, 4>;
|
||||
using FeaturesPerId = std::array<bool, 0xA8>;
|
||||
|
||||
HidFirmwareSettings();
|
||||
|
||||
void Reload();
|
||||
void LoadSettings(bool reload_config);
|
||||
|
||||
bool IsDebugPadEnabled();
|
||||
bool IsDeviceManaged();
|
||||
bool IsEmulateFutureDevice();
|
||||
bool IsTouchI2cManaged();
|
||||
bool IsHandheldForced();
|
||||
bool IsRailEnabled();
|
||||
bool IsHardwareErrorEmulated();
|
||||
bool IsBleDisabled();
|
||||
bool IsDscaleDisabled();
|
||||
bool IsTouchAutoUpdateDisabled();
|
||||
|
||||
FirmwareSetting GetFirmwareUpdateFailure();
|
||||
FeaturesPerId FeaturesDisabledPerId();
|
||||
|
||||
private:
|
||||
bool is_initalized{};
|
||||
|
||||
// Debug settings
|
||||
bool is_debug_pad_enabled{};
|
||||
bool is_device_managed{};
|
||||
bool is_touch_i2c_managed{};
|
||||
bool is_future_devices_emulated{};
|
||||
bool is_mcu_hardware_error_emulated{};
|
||||
bool is_rail_enabled{};
|
||||
bool is_firmware_update_failure_emulated{};
|
||||
bool is_ble_disabled{};
|
||||
bool is_dscale_disabled{};
|
||||
bool is_handheld_forced{};
|
||||
bool is_touch_firmware_auto_update_disabled{};
|
||||
FirmwareSetting is_firmware_update_failure{};
|
||||
FeaturesPerId features_per_id_disabled{};
|
||||
};
|
||||
|
||||
} // namespace Service::HID
|
|
@ -5,30 +5,29 @@
|
|||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/kernel/k_shared_memory.h"
|
||||
#include "core/hle/kernel/k_transfer_memory.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/service/hid/errors.h"
|
||||
#include "core/hle/service/hid/hid_firmware_settings.h"
|
||||
#include "core/hle/service/hid/hid_server.h"
|
||||
#include "core/hle/service/hid/hid_util.h"
|
||||
#include "core/hle/service/hid/resource_manager.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/memory.h"
|
||||
#include "hid_core/hid_result.h"
|
||||
#include "hid_core/hid_util.h"
|
||||
#include "hid_core/resource_manager.h"
|
||||
#include "hid_core/resources/hid_firmware_settings.h"
|
||||
|
||||
#include "core/hle/service/hid/controllers/console_six_axis.h"
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
#include "core/hle/service/hid/controllers/debug_pad.h"
|
||||
#include "core/hle/service/hid/controllers/gesture.h"
|
||||
#include "core/hle/service/hid/controllers/keyboard.h"
|
||||
#include "core/hle/service/hid/controllers/mouse.h"
|
||||
#include "core/hle/service/hid/controllers/npad.h"
|
||||
#include "core/hle/service/hid/controllers/palma.h"
|
||||
#include "core/hle/service/hid/controllers/seven_six_axis.h"
|
||||
#include "core/hle/service/hid/controllers/six_axis.h"
|
||||
#include "core/hle/service/hid/controllers/touchscreen.h"
|
||||
#include "core/hle/service/hid/controllers/types/npad_types.h"
|
||||
#include "hid_core/resources/controller_base.h"
|
||||
#include "hid_core/resources/debug_pad/debug_pad.h"
|
||||
#include "hid_core/resources/keyboard/keyboard.h"
|
||||
#include "hid_core/resources/mouse/mouse.h"
|
||||
#include "hid_core/resources/npad/npad.h"
|
||||
#include "hid_core/resources/npad/npad_types.h"
|
||||
#include "hid_core/resources/palma/palma.h"
|
||||
#include "hid_core/resources/six_axis/console_six_axis.h"
|
||||
#include "hid_core/resources/six_axis/seven_six_axis.h"
|
||||
#include "hid_core/resources/six_axis/six_axis.h"
|
||||
#include "hid_core/resources/touch_screen/gesture.h"
|
||||
#include "hid_core/resources/touch_screen/touch_screen.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/service/hid/controllers/npad.h"
|
||||
#include "core/hle/service/hid/controllers/palma.h"
|
||||
#include "core/hle/service/hid/controllers/touchscreen.h"
|
||||
#include "core/hle/service/hid/controllers/types/npad_types.h"
|
||||
#include "core/hle/service/hid/errors.h"
|
||||
#include "core/hle/service/hid/hid_system_server.h"
|
||||
#include "core/hle/service/hid/resource_manager.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "hid_core/hid_result.h"
|
||||
#include "hid_core/resource_manager.h"
|
||||
#include "hid_core/resources/npad/npad.h"
|
||||
#include "hid_core/resources/npad/npad_types.h"
|
||||
#include "hid_core/resources/palma/palma.h"
|
||||
#include "hid_core/resources/touch_screen/touch_screen.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
|
@ -270,7 +269,7 @@ void IHidSystemServer::GetLastActiveNpad(HLERequestContext& ctx) {
|
|||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(system.HIDCore().GetLastActiveController());
|
||||
rb.Push(0); // Dont forget to fix this
|
||||
}
|
||||
|
||||
void IHidSystemServer::ApplyNpadSystemCommonPolicyFull(HLERequestContext& ctx) {
|
||||
|
|
|
@ -1,146 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/service/hid/errors.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
constexpr bool IsNpadIdValid(const Core::HID::NpadIdType npad_id) {
|
||||
switch (npad_id) {
|
||||
case Core::HID::NpadIdType::Player1:
|
||||
case Core::HID::NpadIdType::Player2:
|
||||
case Core::HID::NpadIdType::Player3:
|
||||
case Core::HID::NpadIdType::Player4:
|
||||
case Core::HID::NpadIdType::Player5:
|
||||
case Core::HID::NpadIdType::Player6:
|
||||
case Core::HID::NpadIdType::Player7:
|
||||
case Core::HID::NpadIdType::Player8:
|
||||
case Core::HID::NpadIdType::Other:
|
||||
case Core::HID::NpadIdType::Handheld:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr Result IsSixaxisHandleValid(const Core::HID::SixAxisSensorHandle& handle) {
|
||||
const auto npad_id = IsNpadIdValid(static_cast<Core::HID::NpadIdType>(handle.npad_id));
|
||||
const bool device_index = handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex;
|
||||
|
||||
if (!npad_id) {
|
||||
return ResultInvalidNpadId;
|
||||
}
|
||||
if (!device_index) {
|
||||
return NpadDeviceIndexOutOfRange;
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
constexpr Result IsVibrationHandleValid(const Core::HID::VibrationDeviceHandle& handle) {
|
||||
switch (handle.npad_type) {
|
||||
case Core::HID::NpadStyleIndex::ProController:
|
||||
case Core::HID::NpadStyleIndex::Handheld:
|
||||
case Core::HID::NpadStyleIndex::JoyconDual:
|
||||
case Core::HID::NpadStyleIndex::JoyconLeft:
|
||||
case Core::HID::NpadStyleIndex::JoyconRight:
|
||||
case Core::HID::NpadStyleIndex::GameCube:
|
||||
case Core::HID::NpadStyleIndex::N64:
|
||||
case Core::HID::NpadStyleIndex::SystemExt:
|
||||
case Core::HID::NpadStyleIndex::System:
|
||||
// These support vibration
|
||||
break;
|
||||
default:
|
||||
return ResultVibrationInvalidStyleIndex;
|
||||
}
|
||||
|
||||
if (!IsNpadIdValid(static_cast<Core::HID::NpadIdType>(handle.npad_id))) {
|
||||
return ResultVibrationInvalidNpadId;
|
||||
}
|
||||
|
||||
if (handle.device_index >= Core::HID::DeviceIndex::MaxDeviceIndex) {
|
||||
return ResultVibrationDeviceIndexOutOfRange;
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
/// Converts a Core::HID::NpadIdType to an array index.
|
||||
constexpr size_t NpadIdTypeToIndex(Core::HID::NpadIdType npad_id_type) {
|
||||
switch (npad_id_type) {
|
||||
case Core::HID::NpadIdType::Player1:
|
||||
return 0;
|
||||
case Core::HID::NpadIdType::Player2:
|
||||
return 1;
|
||||
case Core::HID::NpadIdType::Player3:
|
||||
return 2;
|
||||
case Core::HID::NpadIdType::Player4:
|
||||
return 3;
|
||||
case Core::HID::NpadIdType::Player5:
|
||||
return 4;
|
||||
case Core::HID::NpadIdType::Player6:
|
||||
return 5;
|
||||
case Core::HID::NpadIdType::Player7:
|
||||
return 6;
|
||||
case Core::HID::NpadIdType::Player8:
|
||||
return 7;
|
||||
case Core::HID::NpadIdType::Handheld:
|
||||
return 8;
|
||||
case Core::HID::NpadIdType::Other:
|
||||
return 9;
|
||||
default:
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts an array index to a Core::HID::NpadIdType
|
||||
constexpr Core::HID::NpadIdType IndexToNpadIdType(size_t index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return Core::HID::NpadIdType::Player1;
|
||||
case 1:
|
||||
return Core::HID::NpadIdType::Player2;
|
||||
case 2:
|
||||
return Core::HID::NpadIdType::Player3;
|
||||
case 3:
|
||||
return Core::HID::NpadIdType::Player4;
|
||||
case 4:
|
||||
return Core::HID::NpadIdType::Player5;
|
||||
case 5:
|
||||
return Core::HID::NpadIdType::Player6;
|
||||
case 6:
|
||||
return Core::HID::NpadIdType::Player7;
|
||||
case 7:
|
||||
return Core::HID::NpadIdType::Player8;
|
||||
case 8:
|
||||
return Core::HID::NpadIdType::Handheld;
|
||||
case 9:
|
||||
return Core::HID::NpadIdType::Other;
|
||||
default:
|
||||
return Core::HID::NpadIdType::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr Core::HID::NpadStyleSet GetStylesetByIndex(std::size_t index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return Core::HID::NpadStyleSet::Fullkey;
|
||||
case 1:
|
||||
return Core::HID::NpadStyleSet::Handheld;
|
||||
case 2:
|
||||
return Core::HID::NpadStyleSet::JoyDual;
|
||||
case 3:
|
||||
return Core::HID::NpadStyleSet::JoyLeft;
|
||||
case 4:
|
||||
return Core::HID::NpadStyleSet::JoyRight;
|
||||
case 5:
|
||||
return Core::HID::NpadStyleSet::Palma;
|
||||
default:
|
||||
return Core::HID::NpadStyleSet::None;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
|
@ -5,18 +5,18 @@
|
|||
#include "common/settings.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/kernel/k_shared_memory.h"
|
||||
#include "core/hle/kernel/k_transfer_memory.h"
|
||||
#include "core/hle/service/hid/hidbus.h"
|
||||
#include "core/hle/service/hid/hidbus/ringcon.h"
|
||||
#include "core/hle/service/hid/hidbus/starlink.h"
|
||||
#include "core/hle/service/hid/hidbus/stubbed.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/memory.h"
|
||||
#include "hid_core/hid_types.h"
|
||||
#include "hid_core/hidbus/ringcon.h"
|
||||
#include "hid_core/hidbus/starlink.h"
|
||||
#include "hid_core/hidbus/stubbed.h"
|
||||
|
||||
namespace Service::HID {
|
||||
// (15ms, 66Hz)
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
|
||||
#include <functional>
|
||||
|
||||
#include "core/hle/service/hid/hidbus/hidbus_base.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "hid_core/hidbus/hidbus_base.h"
|
||||
|
||||
namespace Core::Timing {
|
||||
struct EventType;
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/service/hid/hidbus/hidbus_base.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
HidbusBase::HidbusBase(Core::System& system_, KernelHelpers::ServiceContext& service_context_)
|
||||
: system(system_), service_context(service_context_) {
|
||||
send_command_async_event = service_context.CreateEvent("hidbus:SendCommandAsyncEvent");
|
||||
}
|
||||
|
||||
HidbusBase::~HidbusBase() {
|
||||
service_context.CloseEvent(send_command_async_event);
|
||||
};
|
||||
|
||||
void HidbusBase::ActivateDevice() {
|
||||
if (is_activated) {
|
||||
return;
|
||||
}
|
||||
is_activated = true;
|
||||
OnInit();
|
||||
}
|
||||
|
||||
void HidbusBase::DeactivateDevice() {
|
||||
if (is_activated) {
|
||||
OnRelease();
|
||||
}
|
||||
is_activated = false;
|
||||
}
|
||||
|
||||
bool HidbusBase::IsDeviceActivated() const {
|
||||
return is_activated;
|
||||
}
|
||||
|
||||
void HidbusBase::Enable(bool enable) {
|
||||
device_enabled = enable;
|
||||
}
|
||||
|
||||
bool HidbusBase::IsEnabled() const {
|
||||
return device_enabled;
|
||||
}
|
||||
|
||||
bool HidbusBase::IsPollingMode() const {
|
||||
return polling_mode_enabled;
|
||||
}
|
||||
|
||||
JoyPollingMode HidbusBase::GetPollingMode() const {
|
||||
return polling_mode;
|
||||
}
|
||||
|
||||
void HidbusBase::SetPollingMode(JoyPollingMode mode) {
|
||||
polling_mode = mode;
|
||||
polling_mode_enabled = true;
|
||||
}
|
||||
|
||||
void HidbusBase::DisablePollingMode() {
|
||||
polling_mode_enabled = false;
|
||||
}
|
||||
|
||||
void HidbusBase::SetTransferMemoryAddress(Common::ProcessAddress t_mem) {
|
||||
transfer_memory = t_mem;
|
||||
}
|
||||
|
||||
Kernel::KReadableEvent& HidbusBase::GetSendCommandAsycEvent() const {
|
||||
return send_command_async_event->GetReadableEvent();
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,183 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <span>
|
||||
#include "common/typed_address.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
class KEvent;
|
||||
class KReadableEvent;
|
||||
} // namespace Kernel
|
||||
|
||||
namespace Service::KernelHelpers {
|
||||
class ServiceContext;
|
||||
}
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
// This is nn::hidbus::JoyPollingMode
|
||||
enum class JoyPollingMode : u32 {
|
||||
SixAxisSensorDisable,
|
||||
SixAxisSensorEnable,
|
||||
ButtonOnly,
|
||||
};
|
||||
|
||||
struct DataAccessorHeader {
|
||||
Result result{ResultUnknown};
|
||||
INSERT_PADDING_WORDS(0x1);
|
||||
std::array<u8, 0x18> unused{};
|
||||
u64 latest_entry{};
|
||||
u64 total_entries{};
|
||||
};
|
||||
static_assert(sizeof(DataAccessorHeader) == 0x30, "DataAccessorHeader is an invalid size");
|
||||
|
||||
struct JoyDisableSixAxisPollingData {
|
||||
std::array<u8, 0x26> data;
|
||||
u8 out_size;
|
||||
INSERT_PADDING_BYTES(0x1);
|
||||
u64 sampling_number;
|
||||
};
|
||||
static_assert(sizeof(JoyDisableSixAxisPollingData) == 0x30,
|
||||
"JoyDisableSixAxisPollingData is an invalid size");
|
||||
|
||||
struct JoyEnableSixAxisPollingData {
|
||||
std::array<u8, 0x8> data;
|
||||
u8 out_size;
|
||||
INSERT_PADDING_BYTES(0x7);
|
||||
u64 sampling_number;
|
||||
};
|
||||
static_assert(sizeof(JoyEnableSixAxisPollingData) == 0x18,
|
||||
"JoyEnableSixAxisPollingData is an invalid size");
|
||||
|
||||
struct JoyButtonOnlyPollingData {
|
||||
std::array<u8, 0x2c> data;
|
||||
u8 out_size;
|
||||
INSERT_PADDING_BYTES(0x3);
|
||||
u64 sampling_number;
|
||||
};
|
||||
static_assert(sizeof(JoyButtonOnlyPollingData) == 0x38,
|
||||
"JoyButtonOnlyPollingData is an invalid size");
|
||||
|
||||
struct JoyDisableSixAxisPollingEntry {
|
||||
u64 sampling_number;
|
||||
JoyDisableSixAxisPollingData polling_data;
|
||||
};
|
||||
static_assert(sizeof(JoyDisableSixAxisPollingEntry) == 0x38,
|
||||
"JoyDisableSixAxisPollingEntry is an invalid size");
|
||||
|
||||
struct JoyEnableSixAxisPollingEntry {
|
||||
u64 sampling_number;
|
||||
JoyEnableSixAxisPollingData polling_data;
|
||||
};
|
||||
static_assert(sizeof(JoyEnableSixAxisPollingEntry) == 0x20,
|
||||
"JoyEnableSixAxisPollingEntry is an invalid size");
|
||||
|
||||
struct JoyButtonOnlyPollingEntry {
|
||||
u64 sampling_number;
|
||||
JoyButtonOnlyPollingData polling_data;
|
||||
};
|
||||
static_assert(sizeof(JoyButtonOnlyPollingEntry) == 0x40,
|
||||
"JoyButtonOnlyPollingEntry is an invalid size");
|
||||
|
||||
struct JoyDisableSixAxisDataAccessor {
|
||||
DataAccessorHeader header{};
|
||||
std::array<JoyDisableSixAxisPollingEntry, 0xb> entries{};
|
||||
};
|
||||
static_assert(sizeof(JoyDisableSixAxisDataAccessor) == 0x298,
|
||||
"JoyDisableSixAxisDataAccessor is an invalid size");
|
||||
|
||||
struct JoyEnableSixAxisDataAccessor {
|
||||
DataAccessorHeader header{};
|
||||
std::array<JoyEnableSixAxisPollingEntry, 0xb> entries{};
|
||||
};
|
||||
static_assert(sizeof(JoyEnableSixAxisDataAccessor) == 0x190,
|
||||
"JoyEnableSixAxisDataAccessor is an invalid size");
|
||||
|
||||
struct ButtonOnlyPollingDataAccessor {
|
||||
DataAccessorHeader header;
|
||||
std::array<JoyButtonOnlyPollingEntry, 0xb> entries;
|
||||
};
|
||||
static_assert(sizeof(ButtonOnlyPollingDataAccessor) == 0x2F0,
|
||||
"ButtonOnlyPollingDataAccessor is an invalid size");
|
||||
|
||||
class HidbusBase {
|
||||
public:
|
||||
explicit HidbusBase(Core::System& system_, KernelHelpers::ServiceContext& service_context_);
|
||||
virtual ~HidbusBase();
|
||||
|
||||
void ActivateDevice();
|
||||
|
||||
void DeactivateDevice();
|
||||
|
||||
bool IsDeviceActivated() const;
|
||||
|
||||
// Enables/disables the device
|
||||
void Enable(bool enable);
|
||||
|
||||
// returns true if device is enabled
|
||||
bool IsEnabled() const;
|
||||
|
||||
// returns true if polling mode is enabled
|
||||
bool IsPollingMode() const;
|
||||
|
||||
// returns polling mode
|
||||
JoyPollingMode GetPollingMode() const;
|
||||
|
||||
// Sets and enables JoyPollingMode
|
||||
void SetPollingMode(JoyPollingMode mode);
|
||||
|
||||
// Disables JoyPollingMode
|
||||
void DisablePollingMode();
|
||||
|
||||
// Called on EnableJoyPollingReceiveMode
|
||||
void SetTransferMemoryAddress(Common::ProcessAddress t_mem);
|
||||
|
||||
Kernel::KReadableEvent& GetSendCommandAsycEvent() const;
|
||||
|
||||
virtual void OnInit() {}
|
||||
|
||||
virtual void OnRelease() {}
|
||||
|
||||
// Updates device transfer memory
|
||||
virtual void OnUpdate() {}
|
||||
|
||||
// Returns the device ID of the joycon
|
||||
virtual u8 GetDeviceId() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Assigns a command from data
|
||||
virtual bool SetCommand(std::span<const u8> data) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Returns a reply from a command
|
||||
virtual std::vector<u8> GetReply() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
protected:
|
||||
bool is_activated{};
|
||||
bool device_enabled{};
|
||||
bool polling_mode_enabled{};
|
||||
JoyPollingMode polling_mode = {};
|
||||
// TODO(German77): All data accessors need to be replaced with a ring lifo object
|
||||
JoyDisableSixAxisDataAccessor disable_sixaxis_data{};
|
||||
JoyEnableSixAxisDataAccessor enable_sixaxis_data{};
|
||||
ButtonOnlyPollingDataAccessor button_only_data{};
|
||||
|
||||
Common::ProcessAddress transfer_memory{};
|
||||
|
||||
Core::System& system;
|
||||
Kernel::KEvent* send_command_async_event;
|
||||
KernelHelpers::ServiceContext& service_context;
|
||||
};
|
||||
} // namespace Service::HID
|
|
@ -1,292 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/service/hid/hidbus/ringcon.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
RingController::RingController(Core::System& system_,
|
||||
KernelHelpers::ServiceContext& service_context_)
|
||||
: HidbusBase(system_, service_context_) {
|
||||
input = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
|
||||
}
|
||||
|
||||
RingController::~RingController() = default;
|
||||
|
||||
void RingController::OnInit() {
|
||||
input->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::Ring);
|
||||
return;
|
||||
}
|
||||
|
||||
void RingController::OnRelease() {
|
||||
input->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::Active);
|
||||
return;
|
||||
};
|
||||
|
||||
void RingController::OnUpdate() {
|
||||
if (!is_activated) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!device_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!polling_mode_enabled || transfer_memory == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Increment multitasking counters from motion and sensor data
|
||||
|
||||
switch (polling_mode) {
|
||||
case JoyPollingMode::SixAxisSensorEnable: {
|
||||
enable_sixaxis_data.header.total_entries = 10;
|
||||
enable_sixaxis_data.header.result = ResultSuccess;
|
||||
const auto& last_entry =
|
||||
enable_sixaxis_data.entries[enable_sixaxis_data.header.latest_entry];
|
||||
|
||||
enable_sixaxis_data.header.latest_entry =
|
||||
(enable_sixaxis_data.header.latest_entry + 1) % 10;
|
||||
auto& curr_entry = enable_sixaxis_data.entries[enable_sixaxis_data.header.latest_entry];
|
||||
|
||||
curr_entry.sampling_number = last_entry.sampling_number + 1;
|
||||
curr_entry.polling_data.sampling_number = curr_entry.sampling_number;
|
||||
|
||||
const RingConData ringcon_value = GetSensorValue();
|
||||
curr_entry.polling_data.out_size = sizeof(ringcon_value);
|
||||
std::memcpy(curr_entry.polling_data.data.data(), &ringcon_value, sizeof(ringcon_value));
|
||||
|
||||
system.ApplicationMemory().WriteBlock(transfer_memory, &enable_sixaxis_data,
|
||||
sizeof(enable_sixaxis_data));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG_ERROR(Service_HID, "Polling mode not supported {}", polling_mode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RingController::RingConData RingController::GetSensorValue() const {
|
||||
RingConData ringcon_sensor_value{
|
||||
.status = DataValid::Valid,
|
||||
.data = 0,
|
||||
};
|
||||
|
||||
const f32 force_value = input->GetRingSensorForce().force * range;
|
||||
ringcon_sensor_value.data = static_cast<s16>(force_value) + idle_value;
|
||||
|
||||
return ringcon_sensor_value;
|
||||
}
|
||||
|
||||
u8 RingController::GetDeviceId() const {
|
||||
return device_id;
|
||||
}
|
||||
|
||||
std::vector<u8> RingController::GetReply() const {
|
||||
const RingConCommands current_command = command;
|
||||
|
||||
switch (current_command) {
|
||||
case RingConCommands::GetFirmwareVersion:
|
||||
return GetFirmwareVersionReply();
|
||||
case RingConCommands::ReadId:
|
||||
return GetReadIdReply();
|
||||
case RingConCommands::c20105:
|
||||
return GetC020105Reply();
|
||||
case RingConCommands::ReadUnkCal:
|
||||
return GetReadUnkCalReply();
|
||||
case RingConCommands::ReadFactoryCal:
|
||||
return GetReadFactoryCalReply();
|
||||
case RingConCommands::ReadUserCal:
|
||||
return GetReadUserCalReply();
|
||||
case RingConCommands::ReadRepCount:
|
||||
return GetReadRepCountReply();
|
||||
case RingConCommands::ReadTotalPushCount:
|
||||
return GetReadTotalPushCountReply();
|
||||
case RingConCommands::ResetRepCount:
|
||||
return GetResetRepCountReply();
|
||||
case RingConCommands::SaveCalData:
|
||||
return GetSaveDataReply();
|
||||
default:
|
||||
return GetErrorReply();
|
||||
}
|
||||
}
|
||||
|
||||
bool RingController::SetCommand(std::span<const u8> data) {
|
||||
if (data.size() < 4) {
|
||||
LOG_ERROR(Service_HID, "Command size not supported {}", data.size());
|
||||
command = RingConCommands::Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::memcpy(&command, data.data(), sizeof(RingConCommands));
|
||||
|
||||
switch (command) {
|
||||
case RingConCommands::GetFirmwareVersion:
|
||||
case RingConCommands::ReadId:
|
||||
case RingConCommands::c20105:
|
||||
case RingConCommands::ReadUnkCal:
|
||||
case RingConCommands::ReadFactoryCal:
|
||||
case RingConCommands::ReadUserCal:
|
||||
case RingConCommands::ReadRepCount:
|
||||
case RingConCommands::ReadTotalPushCount:
|
||||
ASSERT_MSG(data.size() == 0x4, "data.size is not 0x4 bytes");
|
||||
send_command_async_event->Signal();
|
||||
return true;
|
||||
case RingConCommands::ResetRepCount:
|
||||
ASSERT_MSG(data.size() == 0x4, "data.size is not 0x4 bytes");
|
||||
total_rep_count = 0;
|
||||
send_command_async_event->Signal();
|
||||
return true;
|
||||
case RingConCommands::SaveCalData: {
|
||||
ASSERT_MSG(data.size() == 0x14, "data.size is not 0x14 bytes");
|
||||
|
||||
SaveCalData save_info{};
|
||||
std::memcpy(&save_info, data.data(), sizeof(SaveCalData));
|
||||
user_calibration = save_info.calibration;
|
||||
send_command_async_event->Signal();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
LOG_ERROR(Service_HID, "Command not implemented {}", command);
|
||||
command = RingConCommands::Error;
|
||||
// Signal a reply to avoid softlocking the game
|
||||
send_command_async_event->Signal();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<u8> RingController::GetFirmwareVersionReply() const {
|
||||
const FirmwareVersionReply reply{
|
||||
.status = DataValid::Valid,
|
||||
.firmware = version,
|
||||
};
|
||||
|
||||
return GetDataVector(reply);
|
||||
}
|
||||
|
||||
std::vector<u8> RingController::GetReadIdReply() const {
|
||||
// The values are hardcoded from a real joycon
|
||||
const ReadIdReply reply{
|
||||
.status = DataValid::Valid,
|
||||
.id_l_x0 = 8,
|
||||
.id_l_x0_2 = 41,
|
||||
.id_l_x4 = 22294,
|
||||
.id_h_x0 = 19777,
|
||||
.id_h_x0_2 = 13621,
|
||||
.id_h_x4 = 8245,
|
||||
};
|
||||
|
||||
return GetDataVector(reply);
|
||||
}
|
||||
|
||||
std::vector<u8> RingController::GetC020105Reply() const {
|
||||
const Cmd020105Reply reply{
|
||||
.status = DataValid::Valid,
|
||||
.data = 1,
|
||||
};
|
||||
|
||||
return GetDataVector(reply);
|
||||
}
|
||||
|
||||
std::vector<u8> RingController::GetReadUnkCalReply() const {
|
||||
const ReadUnkCalReply reply{
|
||||
.status = DataValid::Valid,
|
||||
.data = 0,
|
||||
};
|
||||
|
||||
return GetDataVector(reply);
|
||||
}
|
||||
|
||||
std::vector<u8> RingController::GetReadFactoryCalReply() const {
|
||||
const ReadFactoryCalReply reply{
|
||||
.status = DataValid::Valid,
|
||||
.calibration = factory_calibration,
|
||||
};
|
||||
|
||||
return GetDataVector(reply);
|
||||
}
|
||||
|
||||
std::vector<u8> RingController::GetReadUserCalReply() const {
|
||||
const ReadUserCalReply reply{
|
||||
.status = DataValid::Valid,
|
||||
.calibration = user_calibration,
|
||||
};
|
||||
|
||||
return GetDataVector(reply);
|
||||
}
|
||||
|
||||
std::vector<u8> RingController::GetReadRepCountReply() const {
|
||||
const GetThreeByteReply reply{
|
||||
.status = DataValid::Valid,
|
||||
.data = {total_rep_count, 0, 0},
|
||||
.crc = GetCrcValue({total_rep_count, 0, 0, 0}),
|
||||
};
|
||||
|
||||
return GetDataVector(reply);
|
||||
}
|
||||
|
||||
std::vector<u8> RingController::GetReadTotalPushCountReply() const {
|
||||
const GetThreeByteReply reply{
|
||||
.status = DataValid::Valid,
|
||||
.data = {total_push_count, 0, 0},
|
||||
.crc = GetCrcValue({total_push_count, 0, 0, 0}),
|
||||
};
|
||||
|
||||
return GetDataVector(reply);
|
||||
}
|
||||
|
||||
std::vector<u8> RingController::GetResetRepCountReply() const {
|
||||
return GetReadRepCountReply();
|
||||
}
|
||||
|
||||
std::vector<u8> RingController::GetSaveDataReply() const {
|
||||
const StatusReply reply{
|
||||
.status = DataValid::Valid,
|
||||
};
|
||||
|
||||
return GetDataVector(reply);
|
||||
}
|
||||
|
||||
std::vector<u8> RingController::GetErrorReply() const {
|
||||
const ErrorReply reply{
|
||||
.status = DataValid::BadCRC,
|
||||
};
|
||||
|
||||
return GetDataVector(reply);
|
||||
}
|
||||
|
||||
u8 RingController::GetCrcValue(const std::vector<u8>& data) const {
|
||||
u8 crc = 0;
|
||||
for (std::size_t index = 0; index < data.size(); index++) {
|
||||
for (u8 i = 0x80; i > 0; i >>= 1) {
|
||||
bool bit = (crc & 0x80) != 0;
|
||||
if ((data[index] & i) != 0) {
|
||||
bit = !bit;
|
||||
}
|
||||
crc <<= 1;
|
||||
if (bit) {
|
||||
crc ^= 0x8d;
|
||||
}
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::vector<u8> RingController::GetDataVector(const T& reply) const {
|
||||
static_assert(std::is_trivially_copyable_v<T>);
|
||||
std::vector<u8> data;
|
||||
data.resize(sizeof(reply));
|
||||
std::memcpy(data.data(), &reply, sizeof(reply));
|
||||
return data;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,253 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <span>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/service/hid/hidbus/hidbus_base.h"
|
||||
|
||||
namespace Core::HID {
|
||||
class EmulatedController;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
class RingController final : public HidbusBase {
|
||||
public:
|
||||
explicit RingController(Core::System& system_, KernelHelpers::ServiceContext& service_context_);
|
||||
~RingController() override;
|
||||
|
||||
void OnInit() override;
|
||||
|
||||
void OnRelease() override;
|
||||
|
||||
// Updates ringcon transfer memory
|
||||
void OnUpdate() override;
|
||||
|
||||
// Returns the device ID of the joycon
|
||||
u8 GetDeviceId() const override;
|
||||
|
||||
// Assigns a command from data
|
||||
bool SetCommand(std::span<const u8> data) override;
|
||||
|
||||
// Returns a reply from a command
|
||||
std::vector<u8> GetReply() const override;
|
||||
|
||||
private:
|
||||
// These values are obtained from a real ring controller
|
||||
static constexpr s16 idle_value = 2280;
|
||||
static constexpr s16 idle_deadzone = 120;
|
||||
static constexpr s16 range = 2500;
|
||||
|
||||
// Most missing command names are leftovers from other firmware versions
|
||||
enum class RingConCommands : u32 {
|
||||
GetFirmwareVersion = 0x00020000,
|
||||
ReadId = 0x00020100,
|
||||
JoyPolling = 0x00020101,
|
||||
Unknown1 = 0x00020104,
|
||||
c20105 = 0x00020105,
|
||||
Unknown2 = 0x00020204,
|
||||
Unknown3 = 0x00020304,
|
||||
Unknown4 = 0x00020404,
|
||||
ReadUnkCal = 0x00020504,
|
||||
ReadFactoryCal = 0x00020A04,
|
||||
Unknown5 = 0x00021104,
|
||||
Unknown6 = 0x00021204,
|
||||
Unknown7 = 0x00021304,
|
||||
ReadUserCal = 0x00021A04,
|
||||
ReadRepCount = 0x00023104,
|
||||
ReadTotalPushCount = 0x00023204,
|
||||
ResetRepCount = 0x04013104,
|
||||
Unknown8 = 0x04011104,
|
||||
Unknown9 = 0x04011204,
|
||||
Unknown10 = 0x04011304,
|
||||
SaveCalData = 0x10011A04,
|
||||
Error = 0xFFFFFFFF,
|
||||
};
|
||||
|
||||
enum class DataValid : u32 {
|
||||
Valid,
|
||||
BadCRC,
|
||||
Cal,
|
||||
};
|
||||
|
||||
struct FirmwareVersion {
|
||||
u8 sub;
|
||||
u8 main;
|
||||
};
|
||||
static_assert(sizeof(FirmwareVersion) == 0x2, "FirmwareVersion is an invalid size");
|
||||
|
||||
struct FactoryCalibration {
|
||||
s32_le os_max;
|
||||
s32_le hk_max;
|
||||
s32_le zero_min;
|
||||
s32_le zero_max;
|
||||
};
|
||||
static_assert(sizeof(FactoryCalibration) == 0x10, "FactoryCalibration is an invalid size");
|
||||
|
||||
struct CalibrationValue {
|
||||
s16 value;
|
||||
u16 crc;
|
||||
};
|
||||
static_assert(sizeof(CalibrationValue) == 0x4, "CalibrationValue is an invalid size");
|
||||
|
||||
struct UserCalibration {
|
||||
CalibrationValue os_max;
|
||||
CalibrationValue hk_max;
|
||||
CalibrationValue zero;
|
||||
};
|
||||
static_assert(sizeof(UserCalibration) == 0xC, "UserCalibration is an invalid size");
|
||||
|
||||
struct SaveCalData {
|
||||
RingConCommands command;
|
||||
UserCalibration calibration;
|
||||
INSERT_PADDING_BYTES_NOINIT(4);
|
||||
};
|
||||
static_assert(sizeof(SaveCalData) == 0x14, "SaveCalData is an invalid size");
|
||||
static_assert(std::is_trivially_copyable_v<SaveCalData>,
|
||||
"SaveCalData must be trivially copyable");
|
||||
|
||||
struct FirmwareVersionReply {
|
||||
DataValid status;
|
||||
FirmwareVersion firmware;
|
||||
INSERT_PADDING_BYTES(0x2);
|
||||
};
|
||||
static_assert(sizeof(FirmwareVersionReply) == 0x8, "FirmwareVersionReply is an invalid size");
|
||||
|
||||
struct Cmd020105Reply {
|
||||
DataValid status;
|
||||
u8 data;
|
||||
INSERT_PADDING_BYTES(0x3);
|
||||
};
|
||||
static_assert(sizeof(Cmd020105Reply) == 0x8, "Cmd020105Reply is an invalid size");
|
||||
|
||||
struct StatusReply {
|
||||
DataValid status;
|
||||
};
|
||||
static_assert(sizeof(StatusReply) == 0x4, "StatusReply is an invalid size");
|
||||
|
||||
struct GetThreeByteReply {
|
||||
DataValid status;
|
||||
std::array<u8, 3> data;
|
||||
u8 crc;
|
||||
};
|
||||
static_assert(sizeof(GetThreeByteReply) == 0x8, "GetThreeByteReply is an invalid size");
|
||||
|
||||
struct ReadUnkCalReply {
|
||||
DataValid status;
|
||||
u16 data;
|
||||
INSERT_PADDING_BYTES(0x2);
|
||||
};
|
||||
static_assert(sizeof(ReadUnkCalReply) == 0x8, "ReadUnkCalReply is an invalid size");
|
||||
|
||||
struct ReadFactoryCalReply {
|
||||
DataValid status;
|
||||
FactoryCalibration calibration;
|
||||
};
|
||||
static_assert(sizeof(ReadFactoryCalReply) == 0x14, "ReadFactoryCalReply is an invalid size");
|
||||
|
||||
struct ReadUserCalReply {
|
||||
DataValid status;
|
||||
UserCalibration calibration;
|
||||
INSERT_PADDING_BYTES(0x4);
|
||||
};
|
||||
static_assert(sizeof(ReadUserCalReply) == 0x14, "ReadUserCalReply is an invalid size");
|
||||
|
||||
struct ReadIdReply {
|
||||
DataValid status;
|
||||
u16 id_l_x0;
|
||||
u16 id_l_x0_2;
|
||||
u16 id_l_x4;
|
||||
u16 id_h_x0;
|
||||
u16 id_h_x0_2;
|
||||
u16 id_h_x4;
|
||||
};
|
||||
static_assert(sizeof(ReadIdReply) == 0x10, "ReadIdReply is an invalid size");
|
||||
|
||||
struct ErrorReply {
|
||||
DataValid status;
|
||||
INSERT_PADDING_BYTES(0x3);
|
||||
};
|
||||
static_assert(sizeof(ErrorReply) == 0x8, "ErrorReply is an invalid size");
|
||||
|
||||
struct RingConData {
|
||||
DataValid status;
|
||||
s16_le data;
|
||||
INSERT_PADDING_BYTES(0x2);
|
||||
};
|
||||
static_assert(sizeof(RingConData) == 0x8, "RingConData is an invalid size");
|
||||
|
||||
// Returns RingConData struct with pressure sensor values
|
||||
RingConData GetSensorValue() const;
|
||||
|
||||
// Returns 8 byte reply with firmware version
|
||||
std::vector<u8> GetFirmwareVersionReply() const;
|
||||
|
||||
// Returns 16 byte reply with ID values
|
||||
std::vector<u8> GetReadIdReply() const;
|
||||
|
||||
// (STUBBED) Returns 8 byte reply
|
||||
std::vector<u8> GetC020105Reply() const;
|
||||
|
||||
// (STUBBED) Returns 8 byte empty reply
|
||||
std::vector<u8> GetReadUnkCalReply() const;
|
||||
|
||||
// Returns 20 byte reply with factory calibration values
|
||||
std::vector<u8> GetReadFactoryCalReply() const;
|
||||
|
||||
// Returns 20 byte reply with user calibration values
|
||||
std::vector<u8> GetReadUserCalReply() const;
|
||||
|
||||
// Returns 8 byte reply
|
||||
std::vector<u8> GetReadRepCountReply() const;
|
||||
|
||||
// Returns 8 byte reply
|
||||
std::vector<u8> GetReadTotalPushCountReply() const;
|
||||
|
||||
// Returns 8 byte reply
|
||||
std::vector<u8> GetResetRepCountReply() const;
|
||||
|
||||
// Returns 4 byte save data reply
|
||||
std::vector<u8> GetSaveDataReply() const;
|
||||
|
||||
// Returns 8 byte error reply
|
||||
std::vector<u8> GetErrorReply() const;
|
||||
|
||||
// Returns 8 bit redundancy check from provided data
|
||||
u8 GetCrcValue(const std::vector<u8>& data) const;
|
||||
|
||||
// Converts structs to an u8 vector equivalent
|
||||
template <typename T>
|
||||
std::vector<u8> GetDataVector(const T& reply) const;
|
||||
|
||||
RingConCommands command{RingConCommands::Error};
|
||||
|
||||
// These counters are used in multitasking mode while the switch is sleeping
|
||||
// Total steps taken
|
||||
u8 total_rep_count = 0;
|
||||
// Total times the ring was pushed
|
||||
u8 total_push_count = 0;
|
||||
|
||||
const u8 device_id = 0x20;
|
||||
const FirmwareVersion version = {
|
||||
.sub = 0x0,
|
||||
.main = 0x2c,
|
||||
};
|
||||
const FactoryCalibration factory_calibration = {
|
||||
.os_max = idle_value + range + idle_deadzone,
|
||||
.hk_max = idle_value - range - idle_deadzone,
|
||||
.zero_min = idle_value - idle_deadzone,
|
||||
.zero_max = idle_value + idle_deadzone,
|
||||
};
|
||||
UserCalibration user_calibration = {
|
||||
.os_max = {.value = range, .crc = 228},
|
||||
.hk_max = {.value = -range, .crc = 239},
|
||||
.zero = {.value = idle_value, .crc = 225},
|
||||
};
|
||||
|
||||
Core::HID::EmulatedController* input;
|
||||
};
|
||||
} // namespace Service::HID
|
|
@ -1,50 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/service/hid/hidbus/starlink.h"
|
||||
|
||||
namespace Service::HID {
|
||||
constexpr u8 DEVICE_ID = 0x28;
|
||||
|
||||
Starlink::Starlink(Core::System& system_, KernelHelpers::ServiceContext& service_context_)
|
||||
: HidbusBase(system_, service_context_) {}
|
||||
Starlink::~Starlink() = default;
|
||||
|
||||
void Starlink::OnInit() {
|
||||
return;
|
||||
}
|
||||
|
||||
void Starlink::OnRelease() {
|
||||
return;
|
||||
};
|
||||
|
||||
void Starlink::OnUpdate() {
|
||||
if (!is_activated) {
|
||||
return;
|
||||
}
|
||||
if (!device_enabled) {
|
||||
return;
|
||||
}
|
||||
if (!polling_mode_enabled || transfer_memory == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_ERROR(Service_HID, "Polling mode not supported {}", polling_mode);
|
||||
}
|
||||
|
||||
u8 Starlink::GetDeviceId() const {
|
||||
return DEVICE_ID;
|
||||
}
|
||||
|
||||
std::vector<u8> Starlink::GetReply() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
bool Starlink::SetCommand(std::span<const u8> data) {
|
||||
LOG_ERROR(Service_HID, "Command not implemented");
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,37 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/service/hid/hidbus/hidbus_base.h"
|
||||
|
||||
namespace Core::HID {
|
||||
class EmulatedController;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
class Starlink final : public HidbusBase {
|
||||
public:
|
||||
explicit Starlink(Core::System& system_, KernelHelpers::ServiceContext& service_context_);
|
||||
~Starlink() override;
|
||||
|
||||
void OnInit() override;
|
||||
|
||||
void OnRelease() override;
|
||||
|
||||
// Updates ringcon transfer memory
|
||||
void OnUpdate() override;
|
||||
|
||||
// Returns the device ID of the joycon
|
||||
u8 GetDeviceId() const override;
|
||||
|
||||
// Assigns a command from data
|
||||
bool SetCommand(std::span<const u8> data) override;
|
||||
|
||||
// Returns a reply from a command
|
||||
std::vector<u8> GetReply() const override;
|
||||
};
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,50 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/service/hid/hidbus/stubbed.h"
|
||||
|
||||
namespace Service::HID {
|
||||
constexpr u8 DEVICE_ID = 0xFF;
|
||||
|
||||
HidbusStubbed::HidbusStubbed(Core::System& system_, KernelHelpers::ServiceContext& service_context_)
|
||||
: HidbusBase(system_, service_context_) {}
|
||||
HidbusStubbed::~HidbusStubbed() = default;
|
||||
|
||||
void HidbusStubbed::OnInit() {
|
||||
return;
|
||||
}
|
||||
|
||||
void HidbusStubbed::OnRelease() {
|
||||
return;
|
||||
};
|
||||
|
||||
void HidbusStubbed::OnUpdate() {
|
||||
if (!is_activated) {
|
||||
return;
|
||||
}
|
||||
if (!device_enabled) {
|
||||
return;
|
||||
}
|
||||
if (!polling_mode_enabled || transfer_memory == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_ERROR(Service_HID, "Polling mode not supported {}", polling_mode);
|
||||
}
|
||||
|
||||
u8 HidbusStubbed::GetDeviceId() const {
|
||||
return DEVICE_ID;
|
||||
}
|
||||
|
||||
std::vector<u8> HidbusStubbed::GetReply() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
bool HidbusStubbed::SetCommand(std::span<const u8> data) {
|
||||
LOG_ERROR(Service_HID, "Command not implemented");
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,37 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/service/hid/hidbus/hidbus_base.h"
|
||||
|
||||
namespace Core::HID {
|
||||
class EmulatedController;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
class HidbusStubbed final : public HidbusBase {
|
||||
public:
|
||||
explicit HidbusStubbed(Core::System& system_, KernelHelpers::ServiceContext& service_context_);
|
||||
~HidbusStubbed() override;
|
||||
|
||||
void OnInit() override;
|
||||
|
||||
void OnRelease() override;
|
||||
|
||||
// Updates ringcon transfer memory
|
||||
void OnUpdate() override;
|
||||
|
||||
// Returns the device ID of the joycon
|
||||
u8 GetDeviceId() const override;
|
||||
|
||||
// Assigns a command from data
|
||||
bool SetCommand(std::span<const u8> data) override;
|
||||
|
||||
// Returns a reply from a command
|
||||
std::vector<u8> GetReply() const override;
|
||||
};
|
||||
|
||||
} // namespace Service::HID
|
|
@ -6,22 +6,22 @@
|
|||
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/kernel/k_shared_memory.h"
|
||||
#include "core/hle/kernel/k_transfer_memory.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/service/hid/errors.h"
|
||||
#include "core/hle/service/hid/hid_util.h"
|
||||
#include "core/hle/service/hid/irs.h"
|
||||
#include "core/hle/service/hid/irsensor/clustering_processor.h"
|
||||
#include "core/hle/service/hid/irsensor/image_transfer_processor.h"
|
||||
#include "core/hle/service/hid/irsensor/ir_led_processor.h"
|
||||
#include "core/hle/service/hid/irsensor/moment_processor.h"
|
||||
#include "core/hle/service/hid/irsensor/pointing_processor.h"
|
||||
#include "core/hle/service/hid/irsensor/tera_plugin_processor.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/memory.h"
|
||||
#include "hid_core/frontend/emulated_controller.h"
|
||||
#include "hid_core/hid_core.h"
|
||||
#include "hid_core/hid_result.h"
|
||||
#include "hid_core/hid_util.h"
|
||||
#include "hid_core/irsensor/clustering_processor.h"
|
||||
#include "hid_core/irsensor/image_transfer_processor.h"
|
||||
#include "hid_core/irsensor/ir_led_processor.h"
|
||||
#include "hid_core/irsensor/moment_processor.h"
|
||||
#include "hid_core/irsensor/pointing_processor.h"
|
||||
#include "hid_core/irsensor/tera_plugin_processor.h"
|
||||
|
||||
namespace Service::IRS {
|
||||
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
#pragma once
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hid/irs_types.h"
|
||||
#include "core/hle/service/hid/irsensor/processor_base.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "hid_core/hid_types.h"
|
||||
#include "hid_core/irsensor/irs_types.h"
|
||||
#include "hid_core/irsensor/processor_base.h"
|
||||
|
||||
namespace Core::HID {
|
||||
class EmulatedController;
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Service::IRS {
|
||||
|
||||
template <typename State, std::size_t max_buffer_size>
|
||||
struct Lifo {
|
||||
s64 sampling_number{};
|
||||
s64 buffer_count{};
|
||||
std::array<State, max_buffer_size> entries{};
|
||||
|
||||
const State& ReadCurrentEntry() const {
|
||||
return entries[GetBufferTail()];
|
||||
}
|
||||
|
||||
const State& ReadPreviousEntry() const {
|
||||
return entries[GetPreviousEntryIndex()];
|
||||
}
|
||||
|
||||
s64 GetBufferTail() const {
|
||||
return sampling_number % max_buffer_size;
|
||||
}
|
||||
|
||||
std::size_t GetPreviousEntryIndex() const {
|
||||
return static_cast<size_t>((GetBufferTail() + max_buffer_size - 1) % max_buffer_size);
|
||||
}
|
||||
|
||||
std::size_t GetNextEntryIndex() const {
|
||||
return static_cast<size_t>((GetBufferTail() + 1) % max_buffer_size);
|
||||
}
|
||||
|
||||
void WriteNextEntry(const State& new_state) {
|
||||
if (buffer_count < static_cast<s64>(max_buffer_size)) {
|
||||
buffer_count++;
|
||||
}
|
||||
sampling_number++;
|
||||
entries[GetBufferTail()] = new_state;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Service::IRS
|
|
@ -1,267 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include <queue>
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/service/hid/irsensor/clustering_processor.h"
|
||||
|
||||
namespace Service::IRS {
|
||||
ClusteringProcessor::ClusteringProcessor(Core::System& system_,
|
||||
Core::IrSensor::DeviceFormat& device_format,
|
||||
std::size_t npad_index)
|
||||
: device{device_format}, system{system_} {
|
||||
npad_device = system.HIDCore().GetEmulatedControllerByIndex(npad_index);
|
||||
|
||||
device.mode = Core::IrSensor::IrSensorMode::ClusteringProcessor;
|
||||
device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected;
|
||||
device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped;
|
||||
SetDefaultConfig();
|
||||
|
||||
shared_memory = std::construct_at(
|
||||
reinterpret_cast<ClusteringSharedMemory*>(&device_format.state.processor_raw_data));
|
||||
|
||||
Core::HID::ControllerUpdateCallback engine_callback{
|
||||
.on_change = [this](Core::HID::ControllerTriggerType type) { OnControllerUpdate(type); },
|
||||
.is_npad_service = true,
|
||||
};
|
||||
callback_key = npad_device->SetCallback(engine_callback);
|
||||
}
|
||||
|
||||
ClusteringProcessor::~ClusteringProcessor() {
|
||||
npad_device->DeleteCallback(callback_key);
|
||||
};
|
||||
|
||||
void ClusteringProcessor::StartProcessor() {
|
||||
device.camera_status = Core::IrSensor::IrCameraStatus::Available;
|
||||
device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Ready;
|
||||
}
|
||||
|
||||
void ClusteringProcessor::SuspendProcessor() {}
|
||||
|
||||
void ClusteringProcessor::StopProcessor() {}
|
||||
|
||||
void ClusteringProcessor::OnControllerUpdate(Core::HID::ControllerTriggerType type) {
|
||||
if (type != Core::HID::ControllerTriggerType::IrSensor) {
|
||||
return;
|
||||
}
|
||||
|
||||
next_state = {};
|
||||
const auto& camera_data = npad_device->GetCamera();
|
||||
auto filtered_image = camera_data.data;
|
||||
|
||||
RemoveLowIntensityData(filtered_image);
|
||||
|
||||
const auto window_start_x = static_cast<std::size_t>(current_config.window_of_interest.x);
|
||||
const auto window_start_y = static_cast<std::size_t>(current_config.window_of_interest.y);
|
||||
const auto window_end_x =
|
||||
window_start_x + static_cast<std::size_t>(current_config.window_of_interest.width);
|
||||
const auto window_end_y =
|
||||
window_start_y + static_cast<std::size_t>(current_config.window_of_interest.height);
|
||||
|
||||
for (std::size_t y = window_start_y; y < window_end_y; y++) {
|
||||
for (std::size_t x = window_start_x; x < window_end_x; x++) {
|
||||
u8 pixel = GetPixel(filtered_image, x, y);
|
||||
if (pixel == 0) {
|
||||
continue;
|
||||
}
|
||||
const auto cluster = GetClusterProperties(filtered_image, x, y);
|
||||
if (cluster.pixel_count > current_config.pixel_count_max) {
|
||||
continue;
|
||||
}
|
||||
if (cluster.pixel_count < current_config.pixel_count_min) {
|
||||
continue;
|
||||
}
|
||||
// Cluster object limit reached
|
||||
if (next_state.object_count >= next_state.data.size()) {
|
||||
continue;
|
||||
}
|
||||
next_state.data[next_state.object_count] = cluster;
|
||||
next_state.object_count++;
|
||||
}
|
||||
}
|
||||
|
||||
next_state.sampling_number = camera_data.sample;
|
||||
next_state.timestamp = system.CoreTiming().GetGlobalTimeNs().count();
|
||||
next_state.ambient_noise_level = Core::IrSensor::CameraAmbientNoiseLevel::Low;
|
||||
shared_memory->clustering_lifo.WriteNextEntry(next_state);
|
||||
|
||||
if (!IsProcessorActive()) {
|
||||
StartProcessor();
|
||||
}
|
||||
}
|
||||
|
||||
void ClusteringProcessor::RemoveLowIntensityData(std::vector<u8>& data) {
|
||||
for (u8& pixel : data) {
|
||||
if (pixel < current_config.pixel_count_min) {
|
||||
pixel = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClusteringProcessor::ClusteringData ClusteringProcessor::GetClusterProperties(std::vector<u8>& data,
|
||||
std::size_t x,
|
||||
std::size_t y) {
|
||||
using DataPoint = Common::Point<std::size_t>;
|
||||
std::queue<DataPoint> search_points{};
|
||||
ClusteringData current_cluster = GetPixelProperties(data, x, y);
|
||||
SetPixel(data, x, y, 0);
|
||||
search_points.emplace<DataPoint>({x, y});
|
||||
|
||||
while (!search_points.empty()) {
|
||||
const auto point = search_points.front();
|
||||
search_points.pop();
|
||||
|
||||
// Avoid negative numbers
|
||||
if (point.x == 0 || point.y == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::array<DataPoint, 4> new_points{
|
||||
DataPoint{point.x - 1, point.y},
|
||||
{point.x, point.y - 1},
|
||||
{point.x + 1, point.y},
|
||||
{point.x, point.y + 1},
|
||||
};
|
||||
|
||||
for (const auto new_point : new_points) {
|
||||
if (new_point.x >= width) {
|
||||
continue;
|
||||
}
|
||||
if (new_point.y >= height) {
|
||||
continue;
|
||||
}
|
||||
if (GetPixel(data, new_point.x, new_point.y) < current_config.object_intensity_min) {
|
||||
continue;
|
||||
}
|
||||
const ClusteringData cluster = GetPixelProperties(data, new_point.x, new_point.y);
|
||||
current_cluster = MergeCluster(current_cluster, cluster);
|
||||
SetPixel(data, new_point.x, new_point.y, 0);
|
||||
search_points.emplace<DataPoint>({new_point.x, new_point.y});
|
||||
}
|
||||
}
|
||||
|
||||
return current_cluster;
|
||||
}
|
||||
|
||||
ClusteringProcessor::ClusteringData ClusteringProcessor::GetPixelProperties(
|
||||
const std::vector<u8>& data, std::size_t x, std::size_t y) const {
|
||||
return {
|
||||
.average_intensity = GetPixel(data, x, y) / 255.0f,
|
||||
.centroid =
|
||||
{
|
||||
.x = static_cast<f32>(x),
|
||||
.y = static_cast<f32>(y),
|
||||
|
||||
},
|
||||
.pixel_count = 1,
|
||||
.bound =
|
||||
{
|
||||
.x = static_cast<s16>(x),
|
||||
.y = static_cast<s16>(y),
|
||||
.width = 1,
|
||||
.height = 1,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
ClusteringProcessor::ClusteringData ClusteringProcessor::MergeCluster(
|
||||
const ClusteringData a, const ClusteringData b) const {
|
||||
const f32 a_pixel_count = static_cast<f32>(a.pixel_count);
|
||||
const f32 b_pixel_count = static_cast<f32>(b.pixel_count);
|
||||
const f32 pixel_count = a_pixel_count + b_pixel_count;
|
||||
const f32 average_intensity =
|
||||
(a.average_intensity * a_pixel_count + b.average_intensity * b_pixel_count) / pixel_count;
|
||||
const Core::IrSensor::IrsCentroid centroid = {
|
||||
.x = (a.centroid.x * a_pixel_count + b.centroid.x * b_pixel_count) / pixel_count,
|
||||
.y = (a.centroid.y * a_pixel_count + b.centroid.y * b_pixel_count) / pixel_count,
|
||||
};
|
||||
s16 bound_start_x = a.bound.x < b.bound.x ? a.bound.x : b.bound.x;
|
||||
s16 bound_start_y = a.bound.y < b.bound.y ? a.bound.y : b.bound.y;
|
||||
s16 a_bound_end_x = a.bound.x + a.bound.width;
|
||||
s16 a_bound_end_y = a.bound.y + a.bound.height;
|
||||
s16 b_bound_end_x = b.bound.x + b.bound.width;
|
||||
s16 b_bound_end_y = b.bound.y + b.bound.height;
|
||||
|
||||
const Core::IrSensor::IrsRect bound = {
|
||||
.x = bound_start_x,
|
||||
.y = bound_start_y,
|
||||
.width = a_bound_end_x > b_bound_end_x ? static_cast<s16>(a_bound_end_x - bound_start_x)
|
||||
: static_cast<s16>(b_bound_end_x - bound_start_x),
|
||||
.height = a_bound_end_y > b_bound_end_y ? static_cast<s16>(a_bound_end_y - bound_start_y)
|
||||
: static_cast<s16>(b_bound_end_y - bound_start_y),
|
||||
};
|
||||
|
||||
return {
|
||||
.average_intensity = average_intensity,
|
||||
.centroid = centroid,
|
||||
.pixel_count = static_cast<u32>(pixel_count),
|
||||
.bound = bound,
|
||||
};
|
||||
}
|
||||
|
||||
u8 ClusteringProcessor::GetPixel(const std::vector<u8>& data, std::size_t x, std::size_t y) const {
|
||||
if ((y * width) + x >= data.size()) {
|
||||
return 0;
|
||||
}
|
||||
return data[(y * width) + x];
|
||||
}
|
||||
|
||||
void ClusteringProcessor::SetPixel(std::vector<u8>& data, std::size_t x, std::size_t y, u8 value) {
|
||||
if ((y * width) + x >= data.size()) {
|
||||
return;
|
||||
}
|
||||
data[(y * width) + x] = value;
|
||||
}
|
||||
|
||||
void ClusteringProcessor::SetDefaultConfig() {
|
||||
using namespace std::literals::chrono_literals;
|
||||
current_config.camera_config.exposure_time = std::chrono::microseconds(200ms).count();
|
||||
current_config.camera_config.gain = 2;
|
||||
current_config.camera_config.is_negative_used = false;
|
||||
current_config.camera_config.light_target = Core::IrSensor::CameraLightTarget::BrightLeds;
|
||||
current_config.window_of_interest = {
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = width,
|
||||
.height = height,
|
||||
};
|
||||
current_config.pixel_count_min = 3;
|
||||
current_config.pixel_count_max = static_cast<u32>(GetDataSize(format));
|
||||
current_config.is_external_light_filter_enabled = true;
|
||||
current_config.object_intensity_min = 150;
|
||||
|
||||
npad_device->SetCameraFormat(format);
|
||||
}
|
||||
|
||||
void ClusteringProcessor::SetConfig(Core::IrSensor::PackedClusteringProcessorConfig config) {
|
||||
current_config.camera_config.exposure_time = config.camera_config.exposure_time;
|
||||
current_config.camera_config.gain = config.camera_config.gain;
|
||||
current_config.camera_config.is_negative_used = config.camera_config.is_negative_used;
|
||||
current_config.camera_config.light_target =
|
||||
static_cast<Core::IrSensor::CameraLightTarget>(config.camera_config.light_target);
|
||||
current_config.window_of_interest = config.window_of_interest;
|
||||
current_config.pixel_count_min = config.pixel_count_min;
|
||||
current_config.pixel_count_max = config.pixel_count_max;
|
||||
current_config.is_external_light_filter_enabled = config.is_external_light_filter_enabled;
|
||||
current_config.object_intensity_min = config.object_intensity_min;
|
||||
|
||||
LOG_INFO(Service_IRS,
|
||||
"Processor config, exposure_time={}, gain={}, is_negative_used={}, "
|
||||
"light_target={}, window_of_interest=({}, {}, {}, {}), pixel_count_min={}, "
|
||||
"pixel_count_max={}, is_external_light_filter_enabled={}, object_intensity_min={}",
|
||||
current_config.camera_config.exposure_time, current_config.camera_config.gain,
|
||||
current_config.camera_config.is_negative_used,
|
||||
current_config.camera_config.light_target, current_config.window_of_interest.x,
|
||||
current_config.window_of_interest.y, current_config.window_of_interest.width,
|
||||
current_config.window_of_interest.height, current_config.pixel_count_min,
|
||||
current_config.pixel_count_max, current_config.is_external_light_filter_enabled,
|
||||
current_config.object_intensity_min);
|
||||
|
||||
npad_device->SetCameraFormat(format);
|
||||
}
|
||||
|
||||
} // namespace Service::IRS
|
|
@ -1,115 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hid/irs_types.h"
|
||||
#include "core/hle/service/hid/irs_ring_lifo.h"
|
||||
#include "core/hle/service/hid/irsensor/processor_base.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Core::HID {
|
||||
class EmulatedController;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Service::IRS {
|
||||
class ClusteringProcessor final : public ProcessorBase {
|
||||
public:
|
||||
explicit ClusteringProcessor(Core::System& system_, Core::IrSensor::DeviceFormat& device_format,
|
||||
std::size_t npad_index);
|
||||
~ClusteringProcessor() override;
|
||||
|
||||
// Called when the processor is initialized
|
||||
void StartProcessor() override;
|
||||
|
||||
// Called when the processor is suspended
|
||||
void SuspendProcessor() override;
|
||||
|
||||
// Called when the processor is stopped
|
||||
void StopProcessor() override;
|
||||
|
||||
// Sets config parameters of the camera
|
||||
void SetConfig(Core::IrSensor::PackedClusteringProcessorConfig config);
|
||||
|
||||
private:
|
||||
static constexpr auto format = Core::IrSensor::ImageTransferProcessorFormat::Size320x240;
|
||||
static constexpr std::size_t width = 320;
|
||||
static constexpr std::size_t height = 240;
|
||||
|
||||
// This is nn::irsensor::ClusteringProcessorConfig
|
||||
struct ClusteringProcessorConfig {
|
||||
Core::IrSensor::CameraConfig camera_config;
|
||||
Core::IrSensor::IrsRect window_of_interest;
|
||||
u32 pixel_count_min;
|
||||
u32 pixel_count_max;
|
||||
u32 object_intensity_min;
|
||||
bool is_external_light_filter_enabled;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
};
|
||||
static_assert(sizeof(ClusteringProcessorConfig) == 0x30,
|
||||
"ClusteringProcessorConfig is an invalid size");
|
||||
|
||||
// This is nn::irsensor::AdaptiveClusteringProcessorConfig
|
||||
struct AdaptiveClusteringProcessorConfig {
|
||||
Core::IrSensor::AdaptiveClusteringMode mode;
|
||||
Core::IrSensor::AdaptiveClusteringTargetDistance target_distance;
|
||||
};
|
||||
static_assert(sizeof(AdaptiveClusteringProcessorConfig) == 0x8,
|
||||
"AdaptiveClusteringProcessorConfig is an invalid size");
|
||||
|
||||
// This is nn::irsensor::ClusteringData
|
||||
struct ClusteringData {
|
||||
f32 average_intensity;
|
||||
Core::IrSensor::IrsCentroid centroid;
|
||||
u32 pixel_count;
|
||||
Core::IrSensor::IrsRect bound;
|
||||
};
|
||||
static_assert(sizeof(ClusteringData) == 0x18, "ClusteringData is an invalid size");
|
||||
|
||||
// This is nn::irsensor::ClusteringProcessorState
|
||||
struct ClusteringProcessorState {
|
||||
s64 sampling_number;
|
||||
u64 timestamp;
|
||||
u8 object_count;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
Core::IrSensor::CameraAmbientNoiseLevel ambient_noise_level;
|
||||
std::array<ClusteringData, 0x10> data;
|
||||
};
|
||||
static_assert(sizeof(ClusteringProcessorState) == 0x198,
|
||||
"ClusteringProcessorState is an invalid size");
|
||||
|
||||
struct ClusteringSharedMemory {
|
||||
Service::IRS::Lifo<ClusteringProcessorState, 6> clustering_lifo;
|
||||
static_assert(sizeof(clustering_lifo) == 0x9A0, "clustering_lifo is an invalid size");
|
||||
INSERT_PADDING_WORDS(0x11F);
|
||||
};
|
||||
static_assert(sizeof(ClusteringSharedMemory) == 0xE20,
|
||||
"ClusteringSharedMemory is an invalid size");
|
||||
|
||||
void OnControllerUpdate(Core::HID::ControllerTriggerType type);
|
||||
void RemoveLowIntensityData(std::vector<u8>& data);
|
||||
ClusteringData GetClusterProperties(std::vector<u8>& data, std::size_t x, std::size_t y);
|
||||
ClusteringData GetPixelProperties(const std::vector<u8>& data, std::size_t x,
|
||||
std::size_t y) const;
|
||||
ClusteringData MergeCluster(const ClusteringData a, const ClusteringData b) const;
|
||||
u8 GetPixel(const std::vector<u8>& data, std::size_t x, std::size_t y) const;
|
||||
void SetPixel(std::vector<u8>& data, std::size_t x, std::size_t y, u8 value);
|
||||
|
||||
// Sets config parameters of the camera
|
||||
void SetDefaultConfig();
|
||||
|
||||
ClusteringSharedMemory* shared_memory = nullptr;
|
||||
ClusteringProcessorState next_state{};
|
||||
|
||||
ClusteringProcessorConfig current_config{};
|
||||
Core::IrSensor::DeviceFormat& device;
|
||||
Core::HID::EmulatedController* npad_device;
|
||||
int callback_key{};
|
||||
|
||||
Core::System& system;
|
||||
};
|
||||
} // namespace Service::IRS
|
|
@ -1,155 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/service/hid/irsensor/image_transfer_processor.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Service::IRS {
|
||||
ImageTransferProcessor::ImageTransferProcessor(Core::System& system_,
|
||||
Core::IrSensor::DeviceFormat& device_format,
|
||||
std::size_t npad_index)
|
||||
: device{device_format}, system{system_} {
|
||||
npad_device = system.HIDCore().GetEmulatedControllerByIndex(npad_index);
|
||||
|
||||
Core::HID::ControllerUpdateCallback engine_callback{
|
||||
.on_change = [this](Core::HID::ControllerTriggerType type) { OnControllerUpdate(type); },
|
||||
.is_npad_service = true,
|
||||
};
|
||||
callback_key = npad_device->SetCallback(engine_callback);
|
||||
|
||||
device.mode = Core::IrSensor::IrSensorMode::ImageTransferProcessor;
|
||||
device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected;
|
||||
device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped;
|
||||
}
|
||||
|
||||
ImageTransferProcessor::~ImageTransferProcessor() {
|
||||
npad_device->DeleteCallback(callback_key);
|
||||
};
|
||||
|
||||
void ImageTransferProcessor::StartProcessor() {
|
||||
is_active = true;
|
||||
device.camera_status = Core::IrSensor::IrCameraStatus::Available;
|
||||
device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Ready;
|
||||
processor_state.sampling_number = 0;
|
||||
processor_state.ambient_noise_level = Core::IrSensor::CameraAmbientNoiseLevel::Low;
|
||||
}
|
||||
|
||||
void ImageTransferProcessor::SuspendProcessor() {}
|
||||
|
||||
void ImageTransferProcessor::StopProcessor() {}
|
||||
|
||||
void ImageTransferProcessor::OnControllerUpdate(Core::HID::ControllerTriggerType type) {
|
||||
if (type != Core::HID::ControllerTriggerType::IrSensor) {
|
||||
return;
|
||||
}
|
||||
if (transfer_memory == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& camera_data = npad_device->GetCamera();
|
||||
|
||||
// This indicates how much ambient light is present
|
||||
processor_state.ambient_noise_level = Core::IrSensor::CameraAmbientNoiseLevel::Low;
|
||||
processor_state.sampling_number = camera_data.sample;
|
||||
|
||||
if (camera_data.format != current_config.origin_format) {
|
||||
LOG_WARNING(Service_IRS, "Wrong Input format {} expected {}", camera_data.format,
|
||||
current_config.origin_format);
|
||||
system.ApplicationMemory().ZeroBlock(transfer_memory,
|
||||
GetDataSize(current_config.trimming_format));
|
||||
return;
|
||||
}
|
||||
|
||||
if (current_config.origin_format > current_config.trimming_format) {
|
||||
LOG_WARNING(Service_IRS, "Origin format {} is smaller than trimming format {}",
|
||||
current_config.origin_format, current_config.trimming_format);
|
||||
system.ApplicationMemory().ZeroBlock(transfer_memory,
|
||||
GetDataSize(current_config.trimming_format));
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<u8> window_data{};
|
||||
const auto origin_width = GetDataWidth(current_config.origin_format);
|
||||
const auto origin_height = GetDataHeight(current_config.origin_format);
|
||||
const auto trimming_width = GetDataWidth(current_config.trimming_format);
|
||||
const auto trimming_height = GetDataHeight(current_config.trimming_format);
|
||||
window_data.resize(GetDataSize(current_config.trimming_format));
|
||||
|
||||
if (trimming_width + current_config.trimming_start_x > origin_width ||
|
||||
trimming_height + current_config.trimming_start_y > origin_height) {
|
||||
LOG_WARNING(Service_IRS,
|
||||
"Trimming area ({}, {}, {}, {}) is outside of origin area ({}, {})",
|
||||
current_config.trimming_start_x, current_config.trimming_start_y,
|
||||
trimming_width, trimming_height, origin_width, origin_height);
|
||||
system.ApplicationMemory().ZeroBlock(transfer_memory,
|
||||
GetDataSize(current_config.trimming_format));
|
||||
return;
|
||||
}
|
||||
|
||||
for (std::size_t y = 0; y < trimming_height; y++) {
|
||||
for (std::size_t x = 0; x < trimming_width; x++) {
|
||||
const std::size_t window_index = (y * trimming_width) + x;
|
||||
const std::size_t origin_index =
|
||||
((y + current_config.trimming_start_y) * origin_width) + x +
|
||||
current_config.trimming_start_x;
|
||||
window_data[window_index] = camera_data.data[origin_index];
|
||||
}
|
||||
}
|
||||
|
||||
system.ApplicationMemory().WriteBlock(transfer_memory, window_data.data(),
|
||||
GetDataSize(current_config.trimming_format));
|
||||
|
||||
if (!IsProcessorActive()) {
|
||||
StartProcessor();
|
||||
}
|
||||
}
|
||||
|
||||
void ImageTransferProcessor::SetConfig(Core::IrSensor::PackedImageTransferProcessorConfig config) {
|
||||
current_config.camera_config.exposure_time = config.camera_config.exposure_time;
|
||||
current_config.camera_config.gain = config.camera_config.gain;
|
||||
current_config.camera_config.is_negative_used = config.camera_config.is_negative_used;
|
||||
current_config.camera_config.light_target =
|
||||
static_cast<Core::IrSensor::CameraLightTarget>(config.camera_config.light_target);
|
||||
current_config.origin_format =
|
||||
static_cast<Core::IrSensor::ImageTransferProcessorFormat>(config.format);
|
||||
current_config.trimming_format =
|
||||
static_cast<Core::IrSensor::ImageTransferProcessorFormat>(config.format);
|
||||
current_config.trimming_start_x = 0;
|
||||
current_config.trimming_start_y = 0;
|
||||
|
||||
npad_device->SetCameraFormat(current_config.origin_format);
|
||||
}
|
||||
|
||||
void ImageTransferProcessor::SetConfig(
|
||||
Core::IrSensor::PackedImageTransferProcessorExConfig config) {
|
||||
current_config.camera_config.exposure_time = config.camera_config.exposure_time;
|
||||
current_config.camera_config.gain = config.camera_config.gain;
|
||||
current_config.camera_config.is_negative_used = config.camera_config.is_negative_used;
|
||||
current_config.camera_config.light_target =
|
||||
static_cast<Core::IrSensor::CameraLightTarget>(config.camera_config.light_target);
|
||||
current_config.origin_format =
|
||||
static_cast<Core::IrSensor::ImageTransferProcessorFormat>(config.origin_format);
|
||||
current_config.trimming_format =
|
||||
static_cast<Core::IrSensor::ImageTransferProcessorFormat>(config.trimming_format);
|
||||
current_config.trimming_start_x = config.trimming_start_x;
|
||||
current_config.trimming_start_y = config.trimming_start_y;
|
||||
|
||||
npad_device->SetCameraFormat(current_config.origin_format);
|
||||
}
|
||||
|
||||
void ImageTransferProcessor::SetTransferMemoryAddress(Common::ProcessAddress t_mem) {
|
||||
transfer_memory = t_mem;
|
||||
}
|
||||
|
||||
Core::IrSensor::ImageTransferProcessorState ImageTransferProcessor::GetState(
|
||||
std::vector<u8>& data) const {
|
||||
const auto size = GetDataSize(current_config.trimming_format);
|
||||
data.resize(size);
|
||||
system.ApplicationMemory().ReadBlock(transfer_memory, data.data(), size);
|
||||
return processor_state;
|
||||
}
|
||||
|
||||
} // namespace Service::IRS
|
|
@ -1,77 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/typed_address.h"
|
||||
#include "core/hid/irs_types.h"
|
||||
#include "core/hle/service/hid/irsensor/processor_base.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Core::HID {
|
||||
class EmulatedController;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Service::IRS {
|
||||
class ImageTransferProcessor final : public ProcessorBase {
|
||||
public:
|
||||
explicit ImageTransferProcessor(Core::System& system_,
|
||||
Core::IrSensor::DeviceFormat& device_format,
|
||||
std::size_t npad_index);
|
||||
~ImageTransferProcessor() override;
|
||||
|
||||
// Called when the processor is initialized
|
||||
void StartProcessor() override;
|
||||
|
||||
// Called when the processor is suspended
|
||||
void SuspendProcessor() override;
|
||||
|
||||
// Called when the processor is stopped
|
||||
void StopProcessor() override;
|
||||
|
||||
// Sets config parameters of the camera
|
||||
void SetConfig(Core::IrSensor::PackedImageTransferProcessorConfig config);
|
||||
void SetConfig(Core::IrSensor::PackedImageTransferProcessorExConfig config);
|
||||
|
||||
// Transfer memory where the image data will be stored
|
||||
void SetTransferMemoryAddress(Common::ProcessAddress t_mem);
|
||||
|
||||
Core::IrSensor::ImageTransferProcessorState GetState(std::vector<u8>& data) const;
|
||||
|
||||
private:
|
||||
// This is nn::irsensor::ImageTransferProcessorConfig
|
||||
struct ImageTransferProcessorConfig {
|
||||
Core::IrSensor::CameraConfig camera_config;
|
||||
Core::IrSensor::ImageTransferProcessorFormat format;
|
||||
};
|
||||
static_assert(sizeof(ImageTransferProcessorConfig) == 0x20,
|
||||
"ImageTransferProcessorConfig is an invalid size");
|
||||
|
||||
// This is nn::irsensor::ImageTransferProcessorExConfig
|
||||
struct ImageTransferProcessorExConfig {
|
||||
Core::IrSensor::CameraConfig camera_config;
|
||||
Core::IrSensor::ImageTransferProcessorFormat origin_format;
|
||||
Core::IrSensor::ImageTransferProcessorFormat trimming_format;
|
||||
u16 trimming_start_x;
|
||||
u16 trimming_start_y;
|
||||
bool is_external_light_filter_enabled;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
};
|
||||
static_assert(sizeof(ImageTransferProcessorExConfig) == 0x28,
|
||||
"ImageTransferProcessorExConfig is an invalid size");
|
||||
|
||||
void OnControllerUpdate(Core::HID::ControllerTriggerType type);
|
||||
|
||||
ImageTransferProcessorExConfig current_config{};
|
||||
Core::IrSensor::ImageTransferProcessorState processor_state{};
|
||||
Core::IrSensor::DeviceFormat& device;
|
||||
Core::HID::EmulatedController* npad_device;
|
||||
int callback_key{};
|
||||
|
||||
Core::System& system;
|
||||
Common::ProcessAddress transfer_memory{};
|
||||
};
|
||||
} // namespace Service::IRS
|
|
@ -1,27 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "core/hle/service/hid/irsensor/ir_led_processor.h"
|
||||
|
||||
namespace Service::IRS {
|
||||
IrLedProcessor::IrLedProcessor(Core::IrSensor::DeviceFormat& device_format)
|
||||
: device(device_format) {
|
||||
device.mode = Core::IrSensor::IrSensorMode::IrLedProcessor;
|
||||
device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected;
|
||||
device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped;
|
||||
}
|
||||
|
||||
IrLedProcessor::~IrLedProcessor() = default;
|
||||
|
||||
void IrLedProcessor::StartProcessor() {}
|
||||
|
||||
void IrLedProcessor::SuspendProcessor() {}
|
||||
|
||||
void IrLedProcessor::StopProcessor() {}
|
||||
|
||||
void IrLedProcessor::SetConfig(Core::IrSensor::PackedIrLedProcessorConfig config) {
|
||||
current_config.light_target =
|
||||
static_cast<Core::IrSensor::CameraLightTarget>(config.light_target);
|
||||
}
|
||||
|
||||
} // namespace Service::IRS
|
|
@ -1,47 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hid/irs_types.h"
|
||||
#include "core/hle/service/hid/irsensor/processor_base.h"
|
||||
|
||||
namespace Service::IRS {
|
||||
class IrLedProcessor final : public ProcessorBase {
|
||||
public:
|
||||
explicit IrLedProcessor(Core::IrSensor::DeviceFormat& device_format);
|
||||
~IrLedProcessor() override;
|
||||
|
||||
// Called when the processor is initialized
|
||||
void StartProcessor() override;
|
||||
|
||||
// Called when the processor is suspended
|
||||
void SuspendProcessor() override;
|
||||
|
||||
// Called when the processor is stopped
|
||||
void StopProcessor() override;
|
||||
|
||||
// Sets config parameters of the camera
|
||||
void SetConfig(Core::IrSensor::PackedIrLedProcessorConfig config);
|
||||
|
||||
private:
|
||||
// This is nn::irsensor::IrLedProcessorConfig
|
||||
struct IrLedProcessorConfig {
|
||||
Core::IrSensor::CameraLightTarget light_target;
|
||||
};
|
||||
static_assert(sizeof(IrLedProcessorConfig) == 0x4, "IrLedProcessorConfig is an invalid size");
|
||||
|
||||
struct IrLedProcessorState {
|
||||
s64 sampling_number;
|
||||
u64 timestamp;
|
||||
std::array<u8, 0x8> data;
|
||||
};
|
||||
static_assert(sizeof(IrLedProcessorState) == 0x18, "IrLedProcessorState is an invalid size");
|
||||
|
||||
IrLedProcessorConfig current_config{};
|
||||
Core::IrSensor::DeviceFormat& device;
|
||||
};
|
||||
|
||||
} // namespace Service::IRS
|
|
@ -1,149 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/service/hid/irsensor/moment_processor.h"
|
||||
|
||||
namespace Service::IRS {
|
||||
static constexpr auto format = Core::IrSensor::ImageTransferProcessorFormat::Size40x30;
|
||||
static constexpr std::size_t ImageWidth = 40;
|
||||
static constexpr std::size_t ImageHeight = 30;
|
||||
|
||||
MomentProcessor::MomentProcessor(Core::System& system_, Core::IrSensor::DeviceFormat& device_format,
|
||||
std::size_t npad_index)
|
||||
: device(device_format), system{system_} {
|
||||
npad_device = system.HIDCore().GetEmulatedControllerByIndex(npad_index);
|
||||
|
||||
device.mode = Core::IrSensor::IrSensorMode::MomentProcessor;
|
||||
device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected;
|
||||
device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped;
|
||||
|
||||
shared_memory = std::construct_at(
|
||||
reinterpret_cast<MomentSharedMemory*>(&device_format.state.processor_raw_data));
|
||||
|
||||
Core::HID::ControllerUpdateCallback engine_callback{
|
||||
.on_change = [this](Core::HID::ControllerTriggerType type) { OnControllerUpdate(type); },
|
||||
.is_npad_service = true,
|
||||
};
|
||||
callback_key = npad_device->SetCallback(engine_callback);
|
||||
}
|
||||
|
||||
MomentProcessor::~MomentProcessor() {
|
||||
npad_device->DeleteCallback(callback_key);
|
||||
};
|
||||
|
||||
void MomentProcessor::StartProcessor() {
|
||||
device.camera_status = Core::IrSensor::IrCameraStatus::Available;
|
||||
device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Ready;
|
||||
}
|
||||
|
||||
void MomentProcessor::SuspendProcessor() {}
|
||||
|
||||
void MomentProcessor::StopProcessor() {}
|
||||
|
||||
void MomentProcessor::OnControllerUpdate(Core::HID::ControllerTriggerType type) {
|
||||
if (type != Core::HID::ControllerTriggerType::IrSensor) {
|
||||
return;
|
||||
}
|
||||
|
||||
next_state = {};
|
||||
const auto& camera_data = npad_device->GetCamera();
|
||||
|
||||
const auto window_width = static_cast<std::size_t>(current_config.window_of_interest.width);
|
||||
const auto window_height = static_cast<std::size_t>(current_config.window_of_interest.height);
|
||||
const auto window_start_x = static_cast<std::size_t>(current_config.window_of_interest.x);
|
||||
const auto window_start_y = static_cast<std::size_t>(current_config.window_of_interest.y);
|
||||
|
||||
const std::size_t block_width = window_width / Columns;
|
||||
const std::size_t block_height = window_height / Rows;
|
||||
|
||||
for (std::size_t row = 0; row < Rows; row++) {
|
||||
for (std::size_t column = 0; column < Columns; column++) {
|
||||
const size_t x_pos = (column * block_width) + window_start_x;
|
||||
const size_t y_pos = (row * block_height) + window_start_y;
|
||||
auto& statistic = next_state.statistic[column + (row * Columns)];
|
||||
statistic = GetStatistic(camera_data.data, x_pos, y_pos, block_width, block_height);
|
||||
}
|
||||
}
|
||||
|
||||
next_state.sampling_number = camera_data.sample;
|
||||
next_state.timestamp = system.CoreTiming().GetGlobalTimeNs().count();
|
||||
next_state.ambient_noise_level = Core::IrSensor::CameraAmbientNoiseLevel::Low;
|
||||
shared_memory->moment_lifo.WriteNextEntry(next_state);
|
||||
|
||||
if (!IsProcessorActive()) {
|
||||
StartProcessor();
|
||||
}
|
||||
}
|
||||
|
||||
u8 MomentProcessor::GetPixel(const std::vector<u8>& data, std::size_t x, std::size_t y) const {
|
||||
if ((y * ImageWidth) + x >= data.size()) {
|
||||
return 0;
|
||||
}
|
||||
return data[(y * ImageWidth) + x];
|
||||
}
|
||||
|
||||
MomentProcessor::MomentStatistic MomentProcessor::GetStatistic(const std::vector<u8>& data,
|
||||
std::size_t start_x,
|
||||
std::size_t start_y,
|
||||
std::size_t width,
|
||||
std::size_t height) const {
|
||||
// The actual implementation is always 320x240
|
||||
static constexpr std::size_t RealWidth = 320;
|
||||
static constexpr std::size_t RealHeight = 240;
|
||||
static constexpr std::size_t Threshold = 30;
|
||||
MomentStatistic statistic{};
|
||||
std::size_t active_points{};
|
||||
|
||||
// Sum all data points on the block that meet with the threshold
|
||||
for (std::size_t y = 0; y < width; y++) {
|
||||
for (std::size_t x = 0; x < height; x++) {
|
||||
const size_t x_pos = x + start_x;
|
||||
const size_t y_pos = y + start_y;
|
||||
const auto pixel =
|
||||
GetPixel(data, x_pos * ImageWidth / RealWidth, y_pos * ImageHeight / RealHeight);
|
||||
|
||||
if (pixel < Threshold) {
|
||||
continue;
|
||||
}
|
||||
|
||||
statistic.average_intensity += pixel;
|
||||
|
||||
statistic.centroid.x += static_cast<float>(x_pos);
|
||||
statistic.centroid.y += static_cast<float>(y_pos);
|
||||
|
||||
active_points++;
|
||||
}
|
||||
}
|
||||
|
||||
// Return an empty field if no points were available
|
||||
if (active_points == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Finally calculate the actual centroid and average intensity
|
||||
statistic.centroid.x /= static_cast<float>(active_points);
|
||||
statistic.centroid.y /= static_cast<float>(active_points);
|
||||
statistic.average_intensity /= static_cast<f32>(width * height);
|
||||
|
||||
return statistic;
|
||||
}
|
||||
|
||||
void MomentProcessor::SetConfig(Core::IrSensor::PackedMomentProcessorConfig config) {
|
||||
current_config.camera_config.exposure_time = config.camera_config.exposure_time;
|
||||
current_config.camera_config.gain = config.camera_config.gain;
|
||||
current_config.camera_config.is_negative_used = config.camera_config.is_negative_used;
|
||||
current_config.camera_config.light_target =
|
||||
static_cast<Core::IrSensor::CameraLightTarget>(config.camera_config.light_target);
|
||||
current_config.window_of_interest = config.window_of_interest;
|
||||
current_config.preprocess =
|
||||
static_cast<Core::IrSensor::MomentProcessorPreprocess>(config.preprocess);
|
||||
current_config.preprocess_intensity_threshold = config.preprocess_intensity_threshold;
|
||||
|
||||
npad_device->SetCameraFormat(format);
|
||||
}
|
||||
|
||||
} // namespace Service::IRS
|
|
@ -1,91 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hid/irs_types.h"
|
||||
#include "core/hle/service/hid/irs_ring_lifo.h"
|
||||
#include "core/hle/service/hid/irsensor/processor_base.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Core::HID {
|
||||
class EmulatedController;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Service::IRS {
|
||||
class MomentProcessor final : public ProcessorBase {
|
||||
public:
|
||||
explicit MomentProcessor(Core::System& system_, Core::IrSensor::DeviceFormat& device_format,
|
||||
std::size_t npad_index);
|
||||
~MomentProcessor() override;
|
||||
|
||||
// Called when the processor is initialized
|
||||
void StartProcessor() override;
|
||||
|
||||
// Called when the processor is suspended
|
||||
void SuspendProcessor() override;
|
||||
|
||||
// Called when the processor is stopped
|
||||
void StopProcessor() override;
|
||||
|
||||
// Sets config parameters of the camera
|
||||
void SetConfig(Core::IrSensor::PackedMomentProcessorConfig config);
|
||||
|
||||
private:
|
||||
static constexpr std::size_t Columns = 8;
|
||||
static constexpr std::size_t Rows = 6;
|
||||
|
||||
// This is nn::irsensor::MomentProcessorConfig
|
||||
struct MomentProcessorConfig {
|
||||
Core::IrSensor::CameraConfig camera_config;
|
||||
Core::IrSensor::IrsRect window_of_interest;
|
||||
Core::IrSensor::MomentProcessorPreprocess preprocess;
|
||||
u32 preprocess_intensity_threshold;
|
||||
};
|
||||
static_assert(sizeof(MomentProcessorConfig) == 0x28,
|
||||
"MomentProcessorConfig is an invalid size");
|
||||
|
||||
// This is nn::irsensor::MomentStatistic
|
||||
struct MomentStatistic {
|
||||
f32 average_intensity;
|
||||
Core::IrSensor::IrsCentroid centroid;
|
||||
};
|
||||
static_assert(sizeof(MomentStatistic) == 0xC, "MomentStatistic is an invalid size");
|
||||
|
||||
// This is nn::irsensor::MomentProcessorState
|
||||
struct MomentProcessorState {
|
||||
s64 sampling_number;
|
||||
u64 timestamp;
|
||||
Core::IrSensor::CameraAmbientNoiseLevel ambient_noise_level;
|
||||
INSERT_PADDING_BYTES(4);
|
||||
std::array<MomentStatistic, Columns * Rows> statistic;
|
||||
};
|
||||
static_assert(sizeof(MomentProcessorState) == 0x258, "MomentProcessorState is an invalid size");
|
||||
|
||||
struct MomentSharedMemory {
|
||||
Service::IRS::Lifo<MomentProcessorState, 6> moment_lifo;
|
||||
};
|
||||
static_assert(sizeof(MomentSharedMemory) == 0xE20, "MomentSharedMemory is an invalid size");
|
||||
|
||||
void OnControllerUpdate(Core::HID::ControllerTriggerType type);
|
||||
u8 GetPixel(const std::vector<u8>& data, std::size_t x, std::size_t y) const;
|
||||
MomentStatistic GetStatistic(const std::vector<u8>& data, std::size_t start_x,
|
||||
std::size_t start_y, std::size_t width, std::size_t height) const;
|
||||
|
||||
MomentSharedMemory* shared_memory = nullptr;
|
||||
MomentProcessorState next_state{};
|
||||
|
||||
MomentProcessorConfig current_config{};
|
||||
Core::IrSensor::DeviceFormat& device;
|
||||
Core::HID::EmulatedController* npad_device;
|
||||
int callback_key{};
|
||||
|
||||
Core::System& system;
|
||||
};
|
||||
|
||||
} // namespace Service::IRS
|
|
@ -1,26 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "core/hle/service/hid/irsensor/pointing_processor.h"
|
||||
|
||||
namespace Service::IRS {
|
||||
PointingProcessor::PointingProcessor(Core::IrSensor::DeviceFormat& device_format)
|
||||
: device(device_format) {
|
||||
device.mode = Core::IrSensor::IrSensorMode::PointingProcessorMarker;
|
||||
device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected;
|
||||
device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped;
|
||||
}
|
||||
|
||||
PointingProcessor::~PointingProcessor() = default;
|
||||
|
||||
void PointingProcessor::StartProcessor() {}
|
||||
|
||||
void PointingProcessor::SuspendProcessor() {}
|
||||
|
||||
void PointingProcessor::StopProcessor() {}
|
||||
|
||||
void PointingProcessor::SetConfig(Core::IrSensor::PackedPointingProcessorConfig config) {
|
||||
current_config.window_of_interest = config.window_of_interest;
|
||||
}
|
||||
|
||||
} // namespace Service::IRS
|
|
@ -1,61 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hid/irs_types.h"
|
||||
#include "core/hle/service/hid/irsensor/processor_base.h"
|
||||
|
||||
namespace Service::IRS {
|
||||
class PointingProcessor final : public ProcessorBase {
|
||||
public:
|
||||
explicit PointingProcessor(Core::IrSensor::DeviceFormat& device_format);
|
||||
~PointingProcessor() override;
|
||||
|
||||
// Called when the processor is initialized
|
||||
void StartProcessor() override;
|
||||
|
||||
// Called when the processor is suspended
|
||||
void SuspendProcessor() override;
|
||||
|
||||
// Called when the processor is stopped
|
||||
void StopProcessor() override;
|
||||
|
||||
// Sets config parameters of the camera
|
||||
void SetConfig(Core::IrSensor::PackedPointingProcessorConfig config);
|
||||
|
||||
private:
|
||||
// This is nn::irsensor::PointingProcessorConfig
|
||||
struct PointingProcessorConfig {
|
||||
Core::IrSensor::IrsRect window_of_interest;
|
||||
};
|
||||
static_assert(sizeof(PointingProcessorConfig) == 0x8,
|
||||
"PointingProcessorConfig is an invalid size");
|
||||
|
||||
struct PointingProcessorMarkerData {
|
||||
u8 pointing_status;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
u32 unknown;
|
||||
float unknown_float1;
|
||||
float position_x;
|
||||
float position_y;
|
||||
float unknown_float2;
|
||||
Core::IrSensor::IrsRect window_of_interest;
|
||||
};
|
||||
static_assert(sizeof(PointingProcessorMarkerData) == 0x20,
|
||||
"PointingProcessorMarkerData is an invalid size");
|
||||
|
||||
struct PointingProcessorMarkerState {
|
||||
s64 sampling_number;
|
||||
u64 timestamp;
|
||||
std::array<PointingProcessorMarkerData, 0x3> data;
|
||||
};
|
||||
static_assert(sizeof(PointingProcessorMarkerState) == 0x70,
|
||||
"PointingProcessorMarkerState is an invalid size");
|
||||
|
||||
PointingProcessorConfig current_config{};
|
||||
Core::IrSensor::DeviceFormat& device;
|
||||
};
|
||||
|
||||
} // namespace Service::IRS
|
|
@ -1,67 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "core/hle/service/hid/irsensor/processor_base.h"
|
||||
|
||||
namespace Service::IRS {
|
||||
|
||||
ProcessorBase::ProcessorBase() {}
|
||||
ProcessorBase::~ProcessorBase() = default;
|
||||
|
||||
bool ProcessorBase::IsProcessorActive() const {
|
||||
return is_active;
|
||||
}
|
||||
|
||||
std::size_t ProcessorBase::GetDataSize(Core::IrSensor::ImageTransferProcessorFormat format) const {
|
||||
switch (format) {
|
||||
case Core::IrSensor::ImageTransferProcessorFormat::Size320x240:
|
||||
return 320 * 240;
|
||||
case Core::IrSensor::ImageTransferProcessorFormat::Size160x120:
|
||||
return 160 * 120;
|
||||
case Core::IrSensor::ImageTransferProcessorFormat::Size80x60:
|
||||
return 80 * 60;
|
||||
case Core::IrSensor::ImageTransferProcessorFormat::Size40x30:
|
||||
return 40 * 30;
|
||||
case Core::IrSensor::ImageTransferProcessorFormat::Size20x15:
|
||||
return 20 * 15;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t ProcessorBase::GetDataWidth(Core::IrSensor::ImageTransferProcessorFormat format) const {
|
||||
switch (format) {
|
||||
case Core::IrSensor::ImageTransferProcessorFormat::Size320x240:
|
||||
return 320;
|
||||
case Core::IrSensor::ImageTransferProcessorFormat::Size160x120:
|
||||
return 160;
|
||||
case Core::IrSensor::ImageTransferProcessorFormat::Size80x60:
|
||||
return 80;
|
||||
case Core::IrSensor::ImageTransferProcessorFormat::Size40x30:
|
||||
return 40;
|
||||
case Core::IrSensor::ImageTransferProcessorFormat::Size20x15:
|
||||
return 20;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t ProcessorBase::GetDataHeight(
|
||||
Core::IrSensor::ImageTransferProcessorFormat format) const {
|
||||
switch (format) {
|
||||
case Core::IrSensor::ImageTransferProcessorFormat::Size320x240:
|
||||
return 240;
|
||||
case Core::IrSensor::ImageTransferProcessorFormat::Size160x120:
|
||||
return 120;
|
||||
case Core::IrSensor::ImageTransferProcessorFormat::Size80x60:
|
||||
return 60;
|
||||
case Core::IrSensor::ImageTransferProcessorFormat::Size40x30:
|
||||
return 30;
|
||||
case Core::IrSensor::ImageTransferProcessorFormat::Size20x15:
|
||||
return 15;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Service::IRS
|
|
@ -1,33 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hid/irs_types.h"
|
||||
|
||||
namespace Service::IRS {
|
||||
class ProcessorBase {
|
||||
public:
|
||||
explicit ProcessorBase();
|
||||
virtual ~ProcessorBase();
|
||||
|
||||
virtual void StartProcessor() = 0;
|
||||
virtual void SuspendProcessor() = 0;
|
||||
virtual void StopProcessor() = 0;
|
||||
|
||||
bool IsProcessorActive() const;
|
||||
|
||||
protected:
|
||||
/// Returns the number of bytes the image uses
|
||||
std::size_t GetDataSize(Core::IrSensor::ImageTransferProcessorFormat format) const;
|
||||
|
||||
/// Returns the width of the image
|
||||
std::size_t GetDataWidth(Core::IrSensor::ImageTransferProcessorFormat format) const;
|
||||
|
||||
/// Returns the height of the image
|
||||
std::size_t GetDataHeight(Core::IrSensor::ImageTransferProcessorFormat format) const;
|
||||
|
||||
bool is_active{false};
|
||||
};
|
||||
} // namespace Service::IRS
|
|
@ -1,29 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "core/hle/service/hid/irsensor/tera_plugin_processor.h"
|
||||
|
||||
namespace Service::IRS {
|
||||
TeraPluginProcessor::TeraPluginProcessor(Core::IrSensor::DeviceFormat& device_format)
|
||||
: device(device_format) {
|
||||
device.mode = Core::IrSensor::IrSensorMode::TeraPluginProcessor;
|
||||
device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected;
|
||||
device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped;
|
||||
}
|
||||
|
||||
TeraPluginProcessor::~TeraPluginProcessor() = default;
|
||||
|
||||
void TeraPluginProcessor::StartProcessor() {}
|
||||
|
||||
void TeraPluginProcessor::SuspendProcessor() {}
|
||||
|
||||
void TeraPluginProcessor::StopProcessor() {}
|
||||
|
||||
void TeraPluginProcessor::SetConfig(Core::IrSensor::PackedTeraPluginProcessorConfig config) {
|
||||
current_config.mode = config.mode;
|
||||
current_config.unknown_1 = config.unknown_1;
|
||||
current_config.unknown_2 = config.unknown_2;
|
||||
current_config.unknown_3 = config.unknown_3;
|
||||
}
|
||||
|
||||
} // namespace Service::IRS
|
|
@ -1,53 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hid/irs_types.h"
|
||||
#include "core/hle/service/hid/irsensor/processor_base.h"
|
||||
|
||||
namespace Service::IRS {
|
||||
class TeraPluginProcessor final : public ProcessorBase {
|
||||
public:
|
||||
explicit TeraPluginProcessor(Core::IrSensor::DeviceFormat& device_format);
|
||||
~TeraPluginProcessor() override;
|
||||
|
||||
// Called when the processor is initialized
|
||||
void StartProcessor() override;
|
||||
|
||||
// Called when the processor is suspended
|
||||
void SuspendProcessor() override;
|
||||
|
||||
// Called when the processor is stopped
|
||||
void StopProcessor() override;
|
||||
|
||||
// Sets config parameters of the camera
|
||||
void SetConfig(Core::IrSensor::PackedTeraPluginProcessorConfig config);
|
||||
|
||||
private:
|
||||
// This is nn::irsensor::TeraPluginProcessorConfig
|
||||
struct TeraPluginProcessorConfig {
|
||||
u8 mode;
|
||||
u8 unknown_1;
|
||||
u8 unknown_2;
|
||||
u8 unknown_3;
|
||||
};
|
||||
static_assert(sizeof(TeraPluginProcessorConfig) == 0x4,
|
||||
"TeraPluginProcessorConfig is an invalid size");
|
||||
|
||||
struct TeraPluginProcessorState {
|
||||
s64 sampling_number;
|
||||
u64 timestamp;
|
||||
Core::IrSensor::CameraAmbientNoiseLevel ambient_noise_level;
|
||||
std::array<u8, 0x12c> data;
|
||||
};
|
||||
static_assert(sizeof(TeraPluginProcessorState) == 0x140,
|
||||
"TeraPluginProcessorState is an invalid size");
|
||||
|
||||
TeraPluginProcessorConfig current_config{};
|
||||
Core::IrSensor::DeviceFormat& device;
|
||||
};
|
||||
|
||||
} // namespace Service::IRS
|
|
@ -1,362 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/kernel/k_shared_memory.h"
|
||||
#include "core/hle/service/hid/resource_manager.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/capture_button.h"
|
||||
#include "core/hle/service/hid/controllers/console_six_axis.h"
|
||||
#include "core/hle/service/hid/controllers/debug_mouse.h"
|
||||
#include "core/hle/service/hid/controllers/debug_pad.h"
|
||||
#include "core/hle/service/hid/controllers/digitizer.h"
|
||||
#include "core/hle/service/hid/controllers/gesture.h"
|
||||
#include "core/hle/service/hid/controllers/home_button.h"
|
||||
#include "core/hle/service/hid/controllers/keyboard.h"
|
||||
#include "core/hle/service/hid/controllers/mouse.h"
|
||||
#include "core/hle/service/hid/controllers/npad.h"
|
||||
#include "core/hle/service/hid/controllers/palma.h"
|
||||
#include "core/hle/service/hid/controllers/seven_six_axis.h"
|
||||
#include "core/hle/service/hid/controllers/six_axis.h"
|
||||
#include "core/hle/service/hid/controllers/sleep_button.h"
|
||||
#include "core/hle/service/hid/controllers/touchscreen.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
#include "core/hle/service/hid/controllers/unique_pad.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
// Updating period for each HID device.
|
||||
// Period time is obtained by measuring the number of samples in a second on HW using a homebrew
|
||||
// Correct npad_update_ns is 4ms this is overclocked to lower input lag
|
||||
constexpr auto npad_update_ns = std::chrono::nanoseconds{1 * 1000 * 1000}; // (1ms, 1000Hz)
|
||||
constexpr auto default_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 1000Hz)
|
||||
constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz)
|
||||
constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz)
|
||||
|
||||
ResourceManager::ResourceManager(Core::System& system_)
|
||||
: system{system_}, service_context{system_, "hid"} {
|
||||
applet_resource = std::make_shared<AppletResource>(system);
|
||||
}
|
||||
|
||||
ResourceManager::~ResourceManager() = default;
|
||||
|
||||
void ResourceManager::Initialize() {
|
||||
if (is_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
system.HIDCore().ReloadInputDevices();
|
||||
|
||||
InitializeHidCommonSampler();
|
||||
InitializeTouchScreenSampler();
|
||||
InitializeConsoleSixAxisSampler();
|
||||
InitializeAHidSampler();
|
||||
|
||||
is_initialized = true;
|
||||
}
|
||||
|
||||
std::shared_ptr<AppletResource> ResourceManager::GetAppletResource() const {
|
||||
return applet_resource;
|
||||
}
|
||||
|
||||
std::shared_ptr<CaptureButton> ResourceManager::GetCaptureButton() const {
|
||||
return capture_button;
|
||||
}
|
||||
|
||||
std::shared_ptr<ConsoleSixAxis> ResourceManager::GetConsoleSixAxis() const {
|
||||
return console_six_axis;
|
||||
}
|
||||
|
||||
std::shared_ptr<DebugMouse> ResourceManager::GetDebugMouse() const {
|
||||
return debug_mouse;
|
||||
}
|
||||
|
||||
std::shared_ptr<DebugPad> ResourceManager::GetDebugPad() const {
|
||||
return debug_pad;
|
||||
}
|
||||
|
||||
std::shared_ptr<Digitizer> ResourceManager::GetDigitizer() const {
|
||||
return digitizer;
|
||||
}
|
||||
|
||||
std::shared_ptr<Gesture> ResourceManager::GetGesture() const {
|
||||
return gesture;
|
||||
}
|
||||
|
||||
std::shared_ptr<HomeButton> ResourceManager::GetHomeButton() const {
|
||||
return home_button;
|
||||
}
|
||||
|
||||
std::shared_ptr<Keyboard> ResourceManager::GetKeyboard() const {
|
||||
return keyboard;
|
||||
}
|
||||
|
||||
std::shared_ptr<Mouse> ResourceManager::GetMouse() const {
|
||||
return mouse;
|
||||
}
|
||||
|
||||
std::shared_ptr<NPad> ResourceManager::GetNpad() const {
|
||||
return npad;
|
||||
}
|
||||
|
||||
std::shared_ptr<Palma> ResourceManager::GetPalma() const {
|
||||
return palma;
|
||||
}
|
||||
|
||||
std::shared_ptr<SevenSixAxis> ResourceManager::GetSevenSixAxis() const {
|
||||
return seven_six_axis;
|
||||
}
|
||||
|
||||
std::shared_ptr<SixAxis> ResourceManager::GetSixAxis() const {
|
||||
return six_axis;
|
||||
}
|
||||
|
||||
std::shared_ptr<SleepButton> ResourceManager::GetSleepButton() const {
|
||||
return sleep_button;
|
||||
}
|
||||
|
||||
std::shared_ptr<TouchScreen> ResourceManager::GetTouchScreen() const {
|
||||
return touch_screen;
|
||||
}
|
||||
|
||||
std::shared_ptr<UniquePad> ResourceManager::GetUniquePad() const {
|
||||
return unique_pad;
|
||||
}
|
||||
|
||||
Result ResourceManager::CreateAppletResource(u64 aruid) {
|
||||
if (aruid == SystemAruid) {
|
||||
const auto result = RegisterCoreAppletResource();
|
||||
if (result.IsError()) {
|
||||
return result;
|
||||
}
|
||||
return GetNpad()->ActivateNpadResource();
|
||||
}
|
||||
|
||||
const auto result = CreateAppletResourceImpl(aruid);
|
||||
if (result.IsError()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Homebrew doesn't try to activate some controllers, so we activate them by default
|
||||
npad->Activate();
|
||||
six_axis->Activate();
|
||||
touch_screen->Activate();
|
||||
|
||||
return GetNpad()->ActivateNpadResource(aruid);
|
||||
}
|
||||
|
||||
Result ResourceManager::CreateAppletResourceImpl(u64 aruid) {
|
||||
std::scoped_lock lock{shared_mutex};
|
||||
return applet_resource->CreateAppletResource(aruid);
|
||||
}
|
||||
|
||||
void ResourceManager::InitializeHidCommonSampler() {
|
||||
debug_pad = std::make_shared<DebugPad>(system.HIDCore());
|
||||
mouse = std::make_shared<Mouse>(system.HIDCore());
|
||||
debug_mouse = std::make_shared<DebugMouse>(system.HIDCore());
|
||||
keyboard = std::make_shared<Keyboard>(system.HIDCore());
|
||||
unique_pad = std::make_shared<UniquePad>(system.HIDCore());
|
||||
npad = std::make_shared<NPad>(system.HIDCore(), service_context);
|
||||
gesture = std::make_shared<Gesture>(system.HIDCore());
|
||||
home_button = std::make_shared<HomeButton>(system.HIDCore());
|
||||
sleep_button = std::make_shared<SleepButton>(system.HIDCore());
|
||||
capture_button = std::make_shared<CaptureButton>(system.HIDCore());
|
||||
digitizer = std::make_shared<Digitizer>(system.HIDCore());
|
||||
|
||||
palma = std::make_shared<Palma>(system.HIDCore(), service_context);
|
||||
six_axis = std::make_shared<SixAxis>(system.HIDCore(), npad);
|
||||
|
||||
debug_pad->SetAppletResource(applet_resource, &shared_mutex);
|
||||
digitizer->SetAppletResource(applet_resource, &shared_mutex);
|
||||
keyboard->SetAppletResource(applet_resource, &shared_mutex);
|
||||
npad->SetNpadExternals(applet_resource, &shared_mutex);
|
||||
six_axis->SetAppletResource(applet_resource, &shared_mutex);
|
||||
mouse->SetAppletResource(applet_resource, &shared_mutex);
|
||||
debug_mouse->SetAppletResource(applet_resource, &shared_mutex);
|
||||
home_button->SetAppletResource(applet_resource, &shared_mutex);
|
||||
sleep_button->SetAppletResource(applet_resource, &shared_mutex);
|
||||
capture_button->SetAppletResource(applet_resource, &shared_mutex);
|
||||
}
|
||||
|
||||
void ResourceManager::InitializeTouchScreenSampler() {
|
||||
gesture = std::make_shared<Gesture>(system.HIDCore());
|
||||
touch_screen = std::make_shared<TouchScreen>(system.HIDCore());
|
||||
|
||||
touch_screen->SetAppletResource(applet_resource, &shared_mutex);
|
||||
gesture->SetAppletResource(applet_resource, &shared_mutex);
|
||||
}
|
||||
|
||||
void ResourceManager::InitializeConsoleSixAxisSampler() {
|
||||
console_six_axis = std::make_shared<ConsoleSixAxis>(system.HIDCore());
|
||||
seven_six_axis = std::make_shared<SevenSixAxis>(system);
|
||||
|
||||
console_six_axis->SetAppletResource(applet_resource, &shared_mutex);
|
||||
}
|
||||
|
||||
void ResourceManager::InitializeAHidSampler() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
Result ResourceManager::RegisterCoreAppletResource() {
|
||||
std::scoped_lock lock{shared_mutex};
|
||||
return applet_resource->RegisterCoreAppletResource();
|
||||
}
|
||||
|
||||
Result ResourceManager::UnregisterCoreAppletResource() {
|
||||
std::scoped_lock lock{shared_mutex};
|
||||
return applet_resource->UnregisterCoreAppletResource();
|
||||
}
|
||||
|
||||
Result ResourceManager::RegisterAppletResourceUserId(u64 aruid, bool bool_value) {
|
||||
std::scoped_lock lock{shared_mutex};
|
||||
auto result = applet_resource->RegisterAppletResourceUserId(aruid, bool_value);
|
||||
if (result.IsSuccess()) {
|
||||
result = npad->RegisterAppletResourceUserId(aruid);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void ResourceManager::UnregisterAppletResourceUserId(u64 aruid) {
|
||||
std::scoped_lock lock{shared_mutex};
|
||||
applet_resource->UnregisterAppletResourceUserId(aruid);
|
||||
}
|
||||
|
||||
Result ResourceManager::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid) {
|
||||
std::scoped_lock lock{shared_mutex};
|
||||
return applet_resource->GetSharedMemoryHandle(out_handle, aruid);
|
||||
}
|
||||
|
||||
void ResourceManager::FreeAppletResourceId(u64 aruid) {
|
||||
std::scoped_lock lock{shared_mutex};
|
||||
applet_resource->FreeAppletResourceId(aruid);
|
||||
}
|
||||
|
||||
void ResourceManager::EnableInput(u64 aruid, bool is_enabled) {
|
||||
std::scoped_lock lock{shared_mutex};
|
||||
applet_resource->EnableInput(aruid, is_enabled);
|
||||
}
|
||||
|
||||
void ResourceManager::EnableSixAxisSensor(u64 aruid, bool is_enabled) {
|
||||
std::scoped_lock lock{shared_mutex};
|
||||
applet_resource->EnableSixAxisSensor(aruid, is_enabled);
|
||||
}
|
||||
|
||||
void ResourceManager::EnablePadInput(u64 aruid, bool is_enabled) {
|
||||
std::scoped_lock lock{shared_mutex};
|
||||
applet_resource->EnablePadInput(aruid, is_enabled);
|
||||
}
|
||||
|
||||
void ResourceManager::EnableTouchScreen(u64 aruid, bool is_enabled) {
|
||||
std::scoped_lock lock{shared_mutex};
|
||||
applet_resource->EnableTouchScreen(aruid, is_enabled);
|
||||
}
|
||||
|
||||
void ResourceManager::UpdateControllers(std::chrono::nanoseconds ns_late) {
|
||||
auto& core_timing = system.CoreTiming();
|
||||
debug_pad->OnUpdate(core_timing);
|
||||
digitizer->OnUpdate(core_timing);
|
||||
unique_pad->OnUpdate(core_timing);
|
||||
gesture->OnUpdate(core_timing);
|
||||
touch_screen->OnUpdate(core_timing);
|
||||
palma->OnUpdate(core_timing);
|
||||
home_button->OnUpdate(core_timing);
|
||||
sleep_button->OnUpdate(core_timing);
|
||||
capture_button->OnUpdate(core_timing);
|
||||
}
|
||||
|
||||
void ResourceManager::UpdateNpad(std::chrono::nanoseconds ns_late) {
|
||||
auto& core_timing = system.CoreTiming();
|
||||
npad->OnUpdate(core_timing);
|
||||
}
|
||||
|
||||
void ResourceManager::UpdateMouseKeyboard(std::chrono::nanoseconds ns_late) {
|
||||
auto& core_timing = system.CoreTiming();
|
||||
mouse->OnUpdate(core_timing);
|
||||
debug_mouse->OnUpdate(core_timing);
|
||||
keyboard->OnUpdate(core_timing);
|
||||
}
|
||||
|
||||
void ResourceManager::UpdateMotion(std::chrono::nanoseconds ns_late) {
|
||||
auto& core_timing = system.CoreTiming();
|
||||
six_axis->OnUpdate(core_timing);
|
||||
seven_six_axis->OnUpdate(core_timing);
|
||||
console_six_axis->OnUpdate(core_timing);
|
||||
}
|
||||
|
||||
IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource,
|
||||
u64 applet_resource_user_id)
|
||||
: ServiceFramework{system_, "IAppletResource"}, aruid{applet_resource_user_id},
|
||||
resource_manager{resource} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
|
||||
// Register update callbacks
|
||||
npad_update_event = Core::Timing::CreateEvent(
|
||||
"HID::UpdatePadCallback",
|
||||
[this, resource](
|
||||
s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
||||
const auto guard = LockService();
|
||||
resource->UpdateNpad(ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
default_update_event = Core::Timing::CreateEvent(
|
||||
"HID::UpdateDefaultCallback",
|
||||
[this, resource](
|
||||
s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
||||
const auto guard = LockService();
|
||||
resource->UpdateControllers(ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
mouse_keyboard_update_event = Core::Timing::CreateEvent(
|
||||
"HID::UpdateMouseKeyboardCallback",
|
||||
[this, resource](
|
||||
s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
||||
const auto guard = LockService();
|
||||
resource->UpdateMouseKeyboard(ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
motion_update_event = Core::Timing::CreateEvent(
|
||||
"HID::UpdateMotionCallback",
|
||||
[this, resource](
|
||||
s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
||||
const auto guard = LockService();
|
||||
resource->UpdateMotion(ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
|
||||
system.CoreTiming().ScheduleLoopingEvent(npad_update_ns, npad_update_ns, npad_update_event);
|
||||
system.CoreTiming().ScheduleLoopingEvent(default_update_ns, default_update_ns,
|
||||
default_update_event);
|
||||
system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns,
|
||||
mouse_keyboard_update_event);
|
||||
system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns,
|
||||
motion_update_event);
|
||||
}
|
||||
|
||||
IAppletResource::~IAppletResource() {
|
||||
system.CoreTiming().UnscheduleEvent(npad_update_event);
|
||||
system.CoreTiming().UnscheduleEvent(default_update_event);
|
||||
system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event);
|
||||
system.CoreTiming().UnscheduleEvent(motion_update_event);
|
||||
resource_manager->FreeAppletResourceId(aruid);
|
||||
}
|
||||
|
||||
void IAppletResource::GetSharedMemoryHandle(HLERequestContext& ctx) {
|
||||
Kernel::KSharedMemory* handle;
|
||||
const auto result = resource_manager->GetSharedMemoryHandle(&handle, aruid);
|
||||
|
||||
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, result=0x{:X}", aruid, result.raw);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(result);
|
||||
rb.PushCopyObjects(handle);
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,149 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Core::Timing {
|
||||
struct EventType;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
class KSharedMemory;
|
||||
}
|
||||
|
||||
namespace Service::HID {
|
||||
class AppletResource;
|
||||
class CaptureButton;
|
||||
class Controller_Stubbed;
|
||||
class ConsoleSixAxis;
|
||||
class DebugMouse;
|
||||
class DebugPad;
|
||||
class Digitizer;
|
||||
class Gesture;
|
||||
class HomeButton;
|
||||
class Keyboard;
|
||||
class Mouse;
|
||||
class NPad;
|
||||
class Palma;
|
||||
class SevenSixAxis;
|
||||
class SixAxis;
|
||||
class SleepButton;
|
||||
class TouchScreen;
|
||||
class UniquePad;
|
||||
|
||||
class ResourceManager {
|
||||
|
||||
public:
|
||||
explicit ResourceManager(Core::System& system_);
|
||||
~ResourceManager();
|
||||
|
||||
void Initialize();
|
||||
|
||||
std::shared_ptr<AppletResource> GetAppletResource() const;
|
||||
std::shared_ptr<CaptureButton> GetCaptureButton() const;
|
||||
std::shared_ptr<ConsoleSixAxis> GetConsoleSixAxis() const;
|
||||
std::shared_ptr<DebugMouse> GetDebugMouse() const;
|
||||
std::shared_ptr<DebugPad> GetDebugPad() const;
|
||||
std::shared_ptr<Digitizer> GetDigitizer() const;
|
||||
std::shared_ptr<Gesture> GetGesture() const;
|
||||
std::shared_ptr<HomeButton> GetHomeButton() const;
|
||||
std::shared_ptr<Keyboard> GetKeyboard() const;
|
||||
std::shared_ptr<Mouse> GetMouse() const;
|
||||
std::shared_ptr<NPad> GetNpad() const;
|
||||
std::shared_ptr<Palma> GetPalma() const;
|
||||
std::shared_ptr<SevenSixAxis> GetSevenSixAxis() const;
|
||||
std::shared_ptr<SixAxis> GetSixAxis() const;
|
||||
std::shared_ptr<SleepButton> GetSleepButton() const;
|
||||
std::shared_ptr<TouchScreen> GetTouchScreen() const;
|
||||
std::shared_ptr<UniquePad> GetUniquePad() const;
|
||||
|
||||
Result CreateAppletResource(u64 aruid);
|
||||
|
||||
Result RegisterCoreAppletResource();
|
||||
Result UnregisterCoreAppletResource();
|
||||
Result RegisterAppletResourceUserId(u64 aruid, bool bool_value);
|
||||
void UnregisterAppletResourceUserId(u64 aruid);
|
||||
|
||||
Result GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid);
|
||||
void FreeAppletResourceId(u64 aruid);
|
||||
|
||||
void EnableInput(u64 aruid, bool is_enabled);
|
||||
void EnableSixAxisSensor(u64 aruid, bool is_enabled);
|
||||
void EnablePadInput(u64 aruid, bool is_enabled);
|
||||
void EnableTouchScreen(u64 aruid, bool is_enabled);
|
||||
|
||||
void UpdateControllers(std::chrono::nanoseconds ns_late);
|
||||
void UpdateNpad(std::chrono::nanoseconds ns_late);
|
||||
void UpdateMouseKeyboard(std::chrono::nanoseconds ns_late);
|
||||
void UpdateMotion(std::chrono::nanoseconds ns_late);
|
||||
|
||||
private:
|
||||
Result CreateAppletResourceImpl(u64 aruid);
|
||||
void InitializeHidCommonSampler();
|
||||
void InitializeTouchScreenSampler();
|
||||
void InitializeConsoleSixAxisSampler();
|
||||
void InitializeAHidSampler();
|
||||
|
||||
bool is_initialized{false};
|
||||
|
||||
mutable std::recursive_mutex shared_mutex;
|
||||
std::shared_ptr<AppletResource> applet_resource = nullptr;
|
||||
|
||||
std::shared_ptr<CaptureButton> capture_button = nullptr;
|
||||
std::shared_ptr<ConsoleSixAxis> console_six_axis = nullptr;
|
||||
std::shared_ptr<DebugMouse> debug_mouse = nullptr;
|
||||
std::shared_ptr<DebugPad> debug_pad = nullptr;
|
||||
std::shared_ptr<Digitizer> digitizer = nullptr;
|
||||
std::shared_ptr<Gesture> gesture = nullptr;
|
||||
std::shared_ptr<HomeButton> home_button = nullptr;
|
||||
std::shared_ptr<Keyboard> keyboard = nullptr;
|
||||
std::shared_ptr<Mouse> mouse = nullptr;
|
||||
std::shared_ptr<NPad> npad = nullptr;
|
||||
std::shared_ptr<Palma> palma = nullptr;
|
||||
std::shared_ptr<SevenSixAxis> seven_six_axis = nullptr;
|
||||
std::shared_ptr<SixAxis> six_axis = nullptr;
|
||||
std::shared_ptr<SleepButton> sleep_button = nullptr;
|
||||
std::shared_ptr<TouchScreen> touch_screen = nullptr;
|
||||
std::shared_ptr<UniquePad> unique_pad = nullptr;
|
||||
|
||||
// TODO: Create these resources
|
||||
// std::shared_ptr<AudioControl> audio_control = nullptr;
|
||||
// std::shared_ptr<ButtonConfig> button_config = nullptr;
|
||||
// std::shared_ptr<Config> config = nullptr;
|
||||
// std::shared_ptr<Connection> connection = nullptr;
|
||||
// std::shared_ptr<CustomConfig> custom_config = nullptr;
|
||||
// std::shared_ptr<Digitizer> digitizer = nullptr;
|
||||
// std::shared_ptr<Hdls> hdls = nullptr;
|
||||
// std::shared_ptr<PlayReport> play_report = nullptr;
|
||||
// std::shared_ptr<Rail> rail = nullptr;
|
||||
|
||||
Core::System& system;
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
};
|
||||
|
||||
class IAppletResource final : public ServiceFramework<IAppletResource> {
|
||||
public:
|
||||
explicit IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource,
|
||||
u64 applet_resource_user_id);
|
||||
~IAppletResource() override;
|
||||
|
||||
private:
|
||||
void GetSharedMemoryHandle(HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<Core::Timing::EventType> npad_update_event;
|
||||
std::shared_ptr<Core::Timing::EventType> default_update_event;
|
||||
std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event;
|
||||
std::shared_ptr<Core::Timing::EventType> motion_update_event;
|
||||
|
||||
u64 aruid;
|
||||
std::shared_ptr<ResourceManager> resource_manager;
|
||||
};
|
||||
|
||||
} // namespace Service::HID
|
|
@ -1,53 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
template <typename State>
|
||||
struct AtomicStorage {
|
||||
s64 sampling_number;
|
||||
State state;
|
||||
};
|
||||
|
||||
template <typename State, std::size_t max_buffer_size>
|
||||
struct Lifo {
|
||||
s64 timestamp{};
|
||||
s64 total_buffer_count = static_cast<s64>(max_buffer_size);
|
||||
s64 buffer_tail{};
|
||||
s64 buffer_count{};
|
||||
std::array<AtomicStorage<State>, max_buffer_size> entries{};
|
||||
|
||||
const AtomicStorage<State>& ReadCurrentEntry() const {
|
||||
return entries[buffer_tail];
|
||||
}
|
||||
|
||||
const AtomicStorage<State>& ReadPreviousEntry() const {
|
||||
return entries[GetPreviousEntryIndex()];
|
||||
}
|
||||
|
||||
std::size_t GetPreviousEntryIndex() const {
|
||||
return static_cast<size_t>((buffer_tail + max_buffer_size - 1) % max_buffer_size);
|
||||
}
|
||||
|
||||
std::size_t GetNextEntryIndex() const {
|
||||
return static_cast<size_t>((buffer_tail + 1) % max_buffer_size);
|
||||
}
|
||||
|
||||
void WriteNextEntry(const State& new_state) {
|
||||
if (buffer_count < static_cast<s64>(max_buffer_size) - 1) {
|
||||
buffer_count++;
|
||||
}
|
||||
buffer_tail = GetNextEntryIndex();
|
||||
const auto& previous_entry = ReadPreviousEntry();
|
||||
entries[buffer_tail].sampling_number = previous_entry.sampling_number + 1;
|
||||
entries[buffer_tail].state = new_state;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Service::HID
|
|
@ -22,9 +22,6 @@
|
|||
#include "common/string_util.h"
|
||||
#include "common/tiny_mt.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/mii/mii_manager.h"
|
||||
|
@ -33,6 +30,9 @@
|
|||
#include "core/hle/service/nfc/mifare_result.h"
|
||||
#include "core/hle/service/nfc/nfc_result.h"
|
||||
#include "core/hle/service/time/time_manager.h"
|
||||
#include "hid_core/frontend/emulated_controller.h"
|
||||
#include "hid_core/hid_core.h"
|
||||
#include "hid_core/hid_types.h"
|
||||
|
||||
namespace Service::NFC {
|
||||
NfcDevice::NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
|
||||
|
|
|
@ -5,15 +5,15 @@
|
|||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/service/hid/hid_util.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/nfc/common/device.h"
|
||||
#include "core/hle/service/nfc/common/device_manager.h"
|
||||
#include "core/hle/service/nfc/nfc_result.h"
|
||||
#include "core/hle/service/time/clock_types.h"
|
||||
#include "core/hle/service/time/time_manager.h"
|
||||
#include "hid_core/hid_types.h"
|
||||
#include "hid_core/hid_util.h"
|
||||
|
||||
namespace Service::NFC {
|
||||
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
#include <optional>
|
||||
#include <span>
|
||||
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/nfc/mifare_types.h"
|
||||
#include "core/hle/service/nfc/nfc_types.h"
|
||||
#include "core/hle/service/nfp/nfp_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/time/clock_types.h"
|
||||
#include "hid_core/hid_types.h"
|
||||
|
||||
namespace Service::NFC {
|
||||
class NfcDevice;
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/nfc/common/device.h"
|
||||
|
@ -15,6 +14,7 @@
|
|||
#include "core/hle/service/nfc/nfc_types.h"
|
||||
#include "core/hle/service/nfp/nfp_result.h"
|
||||
#include "core/hle/service/time/clock_types.h"
|
||||
#include "hid_core/hid_types.h"
|
||||
|
||||
namespace Service::NFC {
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/nfc/common/device.h"
|
||||
|
@ -12,6 +11,7 @@
|
|||
#include "core/hle/service/nfp/nfp_interface.h"
|
||||
#include "core/hle/service/nfp/nfp_result.h"
|
||||
#include "core/hle/service/nfp/nfp_types.h"
|
||||
#include "hid_core/hid_types.h"
|
||||
|
||||
namespace Service::NFP {
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue