service/hid: Update debug pad, xpad, stubbed and controller base to use ring lifo and the emulated controller
This commit is contained in:
parent
dbe0301102
commit
072559dede
@ -35,9 +35,6 @@ public:
|
|||||||
virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
|
virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
|
||||||
std::size_t size) {}
|
std::size_t size) {}
|
||||||
|
|
||||||
// Called when input devices should be loaded
|
|
||||||
virtual void OnLoadInputDevices() = 0;
|
|
||||||
|
|
||||||
void ActivateController();
|
void ActivateController();
|
||||||
|
|
||||||
void DeactivateController();
|
void DeactivateController();
|
||||||
@ -47,14 +44,6 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
bool is_activated{false};
|
bool is_activated{false};
|
||||||
|
|
||||||
struct CommonHeader {
|
|
||||||
s64_le timestamp;
|
|
||||||
s64_le total_entry_count;
|
|
||||||
s64_le last_entry_index;
|
|
||||||
s64_le entry_count;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size");
|
|
||||||
|
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
};
|
};
|
||||||
} // namespace Service::HID
|
} // namespace Service::HID
|
||||||
|
@ -5,7 +5,10 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
|
#include "core/hid/hid_core.h"
|
||||||
|
#include "core/hid/hid_types.h"
|
||||||
#include "core/hle/service/hid/controllers/debug_pad.h"
|
#include "core/hle/service/hid/controllers/debug_pad.h"
|
||||||
|
|
||||||
namespace Service::HID {
|
namespace Service::HID {
|
||||||
@ -14,7 +17,10 @@ constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
|
|||||||
[[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff;
|
[[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff;
|
||||||
enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right };
|
enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right };
|
||||||
|
|
||||||
Controller_DebugPad::Controller_DebugPad(Core::System& system_) : ControllerBase{system_} {}
|
Controller_DebugPad::Controller_DebugPad(Core::System& system_) : ControllerBase{system_} {
|
||||||
|
controller = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Other);
|
||||||
|
}
|
||||||
|
|
||||||
Controller_DebugPad::~Controller_DebugPad() = default;
|
Controller_DebugPad::~Controller_DebugPad() = default;
|
||||||
|
|
||||||
void Controller_DebugPad::OnInit() {}
|
void Controller_DebugPad::OnInit() {}
|
||||||
@ -23,63 +29,29 @@ void Controller_DebugPad::OnRelease() {}
|
|||||||
|
|
||||||
void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
|
void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
|
||||||
std::size_t size) {
|
std::size_t size) {
|
||||||
shared_memory.header.timestamp = core_timing.GetCPUTicks();
|
|
||||||
shared_memory.header.total_entry_count = 17;
|
|
||||||
|
|
||||||
if (!IsControllerActivated()) {
|
if (!IsControllerActivated()) {
|
||||||
shared_memory.header.entry_count = 0;
|
debug_pad_lifo.entry_count = 0;
|
||||||
shared_memory.header.last_entry_index = 0;
|
debug_pad_lifo.last_entry_index = 0;
|
||||||
|
std::memcpy(data, &debug_pad_lifo, sizeof(debug_pad_lifo));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
shared_memory.header.entry_count = 16;
|
|
||||||
|
|
||||||
const auto& last_entry = shared_memory.pad_states[shared_memory.header.last_entry_index];
|
const auto& last_entry = debug_pad_lifo.ReadCurrentEntry().state;
|
||||||
shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17;
|
next_state.sampling_number = last_entry.sampling_number + 1;
|
||||||
auto& cur_entry = shared_memory.pad_states[shared_memory.header.last_entry_index];
|
|
||||||
|
|
||||||
cur_entry.sampling_number = last_entry.sampling_number + 1;
|
|
||||||
cur_entry.sampling_number2 = cur_entry.sampling_number;
|
|
||||||
|
|
||||||
if (Settings::values.debug_pad_enabled) {
|
if (Settings::values.debug_pad_enabled) {
|
||||||
cur_entry.attribute.connected.Assign(1);
|
next_state.attribute.connected.Assign(1);
|
||||||
auto& pad = cur_entry.pad_state;
|
|
||||||
|
|
||||||
using namespace Settings::NativeButton;
|
const auto& button_state = controller->GetDebugPadButtons();
|
||||||
pad.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus());
|
const auto& stick_state = controller->GetSticks();
|
||||||
pad.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus());
|
|
||||||
pad.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus());
|
|
||||||
pad.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus());
|
|
||||||
pad.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus());
|
|
||||||
pad.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus());
|
|
||||||
pad.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus());
|
|
||||||
pad.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus());
|
|
||||||
pad.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus());
|
|
||||||
pad.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus());
|
|
||||||
pad.d_left.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus());
|
|
||||||
pad.d_up.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus());
|
|
||||||
pad.d_right.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus());
|
|
||||||
pad.d_down.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus());
|
|
||||||
|
|
||||||
const auto [stick_l_x_f, stick_l_y_f] =
|
next_state.pad_state = button_state;
|
||||||
analogs[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus();
|
next_state.l_stick = stick_state.left;
|
||||||
const auto [stick_r_x_f, stick_r_y_f] =
|
next_state.r_stick = stick_state.right;
|
||||||
analogs[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus();
|
|
||||||
cur_entry.l_stick.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
|
|
||||||
cur_entry.l_stick.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
|
|
||||||
cur_entry.r_stick.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
|
|
||||||
cur_entry.r_stick.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::memcpy(data, &shared_memory, sizeof(SharedMemory));
|
debug_pad_lifo.WriteNextEntry(next_state);
|
||||||
|
std::memcpy(data, &debug_pad_lifo, sizeof(debug_pad_lifo));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller_DebugPad::OnLoadInputDevices() {
|
|
||||||
std::transform(Settings::values.debug_pad_buttons.begin(),
|
|
||||||
Settings::values.debug_pad_buttons.begin() +
|
|
||||||
Settings::NativeButton::NUM_BUTTONS_HID,
|
|
||||||
buttons.begin(), Input::CreateDevice<Input::ButtonDevice>);
|
|
||||||
std::transform(Settings::values.debug_pad_analogs.begin(),
|
|
||||||
Settings::values.debug_pad_analogs.end(), analogs.begin(),
|
|
||||||
Input::CreateDevice<Input::AnalogDevice>);
|
|
||||||
}
|
|
||||||
} // namespace Service::HID
|
} // namespace Service::HID
|
||||||
|
@ -10,8 +10,14 @@
|
|||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
#include "core/frontend/input.h"
|
|
||||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||||
|
#include "core/hle/service/hid/ring_lifo.h"
|
||||||
|
|
||||||
|
namespace Core::HID {
|
||||||
|
class EmulatedController;
|
||||||
|
struct DebugPadButton;
|
||||||
|
struct AnalogStickState;
|
||||||
|
} // namespace Core::HID
|
||||||
|
|
||||||
namespace Service::HID {
|
namespace Service::HID {
|
||||||
class Controller_DebugPad final : public ControllerBase {
|
class Controller_DebugPad final : public ControllerBase {
|
||||||
@ -28,66 +34,31 @@ public:
|
|||||||
// When the controller is requesting an update for the shared memory
|
// When the controller is requesting an update for the shared memory
|
||||||
void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
|
void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
|
||||||
|
|
||||||
// Called when input devices should be loaded
|
|
||||||
void OnLoadInputDevices() override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct AnalogStick {
|
// This is nn::hid::DebugPadAttribute
|
||||||
s32_le x;
|
struct DebugPadAttribute {
|
||||||
s32_le y;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(AnalogStick) == 0x8);
|
|
||||||
|
|
||||||
struct PadState {
|
|
||||||
union {
|
|
||||||
u32_le raw{};
|
|
||||||
BitField<0, 1, u32> a;
|
|
||||||
BitField<1, 1, u32> b;
|
|
||||||
BitField<2, 1, u32> x;
|
|
||||||
BitField<3, 1, u32> y;
|
|
||||||
BitField<4, 1, u32> l;
|
|
||||||
BitField<5, 1, u32> r;
|
|
||||||
BitField<6, 1, u32> zl;
|
|
||||||
BitField<7, 1, u32> zr;
|
|
||||||
BitField<8, 1, u32> plus;
|
|
||||||
BitField<9, 1, u32> minus;
|
|
||||||
BitField<10, 1, u32> d_left;
|
|
||||||
BitField<11, 1, u32> d_up;
|
|
||||||
BitField<12, 1, u32> d_right;
|
|
||||||
BitField<13, 1, u32> d_down;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
static_assert(sizeof(PadState) == 0x4, "PadState is an invalid size");
|
|
||||||
|
|
||||||
struct Attributes {
|
|
||||||
union {
|
union {
|
||||||
u32_le raw{};
|
u32_le raw{};
|
||||||
BitField<0, 1, u32> connected;
|
BitField<0, 1, u32> connected;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size");
|
static_assert(sizeof(DebugPadAttribute) == 0x4, "DebugPadAttribute is an invalid size");
|
||||||
|
|
||||||
struct PadStates {
|
// This is nn::hid::DebugPadState
|
||||||
|
struct DebugPadState {
|
||||||
s64_le sampling_number;
|
s64_le sampling_number;
|
||||||
s64_le sampling_number2;
|
DebugPadAttribute attribute;
|
||||||
Attributes attribute;
|
Core::HID::DebugPadButton pad_state;
|
||||||
PadState pad_state;
|
Core::HID::AnalogStickState r_stick;
|
||||||
AnalogStick r_stick;
|
Core::HID::AnalogStickState l_stick;
|
||||||
AnalogStick l_stick;
|
|
||||||
};
|
};
|
||||||
static_assert(sizeof(PadStates) == 0x28, "PadStates is an invalid state");
|
static_assert(sizeof(DebugPadState) == 0x20, "DebugPadState is an invalid state");
|
||||||
|
|
||||||
struct SharedMemory {
|
// This is nn::hid::detail::DebugPadLifo
|
||||||
CommonHeader header;
|
Lifo<DebugPadState> debug_pad_lifo{};
|
||||||
std::array<PadStates, 17> pad_states;
|
static_assert(sizeof(debug_pad_lifo) == 0x2C8, "debug_pad_lifo is an invalid size");
|
||||||
INSERT_PADDING_BYTES(0x138);
|
DebugPadState next_state{};
|
||||||
};
|
|
||||||
static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size");
|
|
||||||
SharedMemory shared_memory{};
|
|
||||||
|
|
||||||
std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>
|
Core::HID::EmulatedController* controller;
|
||||||
buttons;
|
|
||||||
std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NumAnalogs>
|
|
||||||
analogs;
|
|
||||||
};
|
};
|
||||||
} // namespace Service::HID
|
} // namespace Service::HID
|
||||||
|
@ -31,10 +31,9 @@ void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing, u
|
|||||||
std::memcpy(data + common_offset, &header, sizeof(CommonHeader));
|
std::memcpy(data + common_offset, &header, sizeof(CommonHeader));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller_Stubbed::OnLoadInputDevices() {}
|
|
||||||
|
|
||||||
void Controller_Stubbed::SetCommonHeaderOffset(std::size_t off) {
|
void Controller_Stubbed::SetCommonHeaderOffset(std::size_t off) {
|
||||||
common_offset = off;
|
common_offset = off;
|
||||||
smart_update = true;
|
smart_update = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::HID
|
} // namespace Service::HID
|
||||||
|
@ -22,12 +22,17 @@ public:
|
|||||||
// When the controller is requesting an update for the shared memory
|
// When the controller is requesting an update for the shared memory
|
||||||
void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
|
void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
|
||||||
|
|
||||||
// Called when input devices should be loaded
|
|
||||||
void OnLoadInputDevices() override;
|
|
||||||
|
|
||||||
void SetCommonHeaderOffset(std::size_t off);
|
void SetCommonHeaderOffset(std::size_t off);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct CommonHeader {
|
||||||
|
s64_le timestamp;
|
||||||
|
s64_le total_entry_count;
|
||||||
|
s64_le last_entry_index;
|
||||||
|
s64_le entry_count;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size");
|
||||||
|
|
||||||
bool smart_update{};
|
bool smart_update{};
|
||||||
std::size_t common_offset{};
|
std::size_t common_offset{};
|
||||||
};
|
};
|
||||||
|
@ -19,28 +19,19 @@ void Controller_XPad::OnRelease() {}
|
|||||||
|
|
||||||
void Controller_XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
|
void Controller_XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
|
||||||
std::size_t size) {
|
std::size_t size) {
|
||||||
for (auto& xpad_entry : shared_memory.shared_memory_entries) {
|
if (!IsControllerActivated()) {
|
||||||
xpad_entry.header.timestamp = core_timing.GetCPUTicks();
|
basic_xpad_lifo.entry_count = 0;
|
||||||
xpad_entry.header.total_entry_count = 17;
|
basic_xpad_lifo.last_entry_index = 0;
|
||||||
|
std::memcpy(data, &basic_xpad_lifo, sizeof(basic_xpad_lifo));
|
||||||
if (!IsControllerActivated()) {
|
return;
|
||||||
xpad_entry.header.entry_count = 0;
|
|
||||||
xpad_entry.header.last_entry_index = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
xpad_entry.header.entry_count = 16;
|
|
||||||
|
|
||||||
const auto& last_entry = xpad_entry.pad_states[xpad_entry.header.last_entry_index];
|
|
||||||
xpad_entry.header.last_entry_index = (xpad_entry.header.last_entry_index + 1) % 17;
|
|
||||||
auto& cur_entry = xpad_entry.pad_states[xpad_entry.header.last_entry_index];
|
|
||||||
|
|
||||||
cur_entry.sampling_number = last_entry.sampling_number + 1;
|
|
||||||
cur_entry.sampling_number2 = cur_entry.sampling_number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto& last_entry = basic_xpad_lifo.ReadCurrentEntry().state;
|
||||||
|
next_state.sampling_number = last_entry.sampling_number + 1;
|
||||||
// TODO(ogniK): Update xpad states
|
// TODO(ogniK): Update xpad states
|
||||||
|
|
||||||
std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory));
|
basic_xpad_lifo.WriteNextEntry(next_state);
|
||||||
|
std::memcpy(data + SHARED_MEMORY_OFFSET, &basic_xpad_lifo, sizeof(basic_xpad_lifo));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller_XPad::OnLoadInputDevices() {}
|
|
||||||
} // namespace Service::HID
|
} // namespace Service::HID
|
||||||
|
@ -8,7 +8,9 @@
|
|||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
|
#include "core/hid/hid_types.h"
|
||||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||||
|
#include "core/hle/service/hid/ring_lifo.h"
|
||||||
|
|
||||||
namespace Service::HID {
|
namespace Service::HID {
|
||||||
class Controller_XPad final : public ControllerBase {
|
class Controller_XPad final : public ControllerBase {
|
||||||
@ -25,11 +27,9 @@ public:
|
|||||||
// When the controller is requesting an update for the shared memory
|
// When the controller is requesting an update for the shared memory
|
||||||
void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
|
void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
|
||||||
|
|
||||||
// Called when input devices should be loaded
|
|
||||||
void OnLoadInputDevices() override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Attributes {
|
// This is nn::hid::BasicXpadAttributeSet
|
||||||
|
struct BasicXpadAttributeSet {
|
||||||
union {
|
union {
|
||||||
u32_le raw{};
|
u32_le raw{};
|
||||||
BitField<0, 1, u32> is_connected;
|
BitField<0, 1, u32> is_connected;
|
||||||
@ -40,9 +40,10 @@ private:
|
|||||||
BitField<5, 1, u32> is_right_wired;
|
BitField<5, 1, u32> is_right_wired;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(Attributes) == 4, "Attributes is an invalid size");
|
static_assert(sizeof(BasicXpadAttributeSet) == 4, "BasicXpadAttributeSet is an invalid size");
|
||||||
|
|
||||||
struct Buttons {
|
// This is nn::hid::BasicXpadButtonSet
|
||||||
|
struct BasicXpadButtonSet {
|
||||||
union {
|
union {
|
||||||
u32_le raw{};
|
u32_le raw{};
|
||||||
// Button states
|
// Button states
|
||||||
@ -88,35 +89,21 @@ private:
|
|||||||
BitField<30, 1, u32> handheld_left_b;
|
BitField<30, 1, u32> handheld_left_b;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(Buttons) == 4, "Buttons is an invalid size");
|
static_assert(sizeof(BasicXpadButtonSet) == 4, "BasicXpadButtonSet is an invalid size");
|
||||||
|
|
||||||
struct AnalogStick {
|
// This is nn::hid::detail::BasicXpadState
|
||||||
s32_le x;
|
struct BasicXpadState {
|
||||||
s32_le y;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(AnalogStick) == 0x8, "AnalogStick is an invalid size");
|
|
||||||
|
|
||||||
struct XPadState {
|
|
||||||
s64_le sampling_number;
|
s64_le sampling_number;
|
||||||
s64_le sampling_number2;
|
BasicXpadAttributeSet attributes;
|
||||||
Attributes attributes;
|
BasicXpadButtonSet pad_states;
|
||||||
Buttons pad_states;
|
Core::HID::AnalogStickState l_stick;
|
||||||
AnalogStick l_stick;
|
Core::HID::AnalogStickState r_stick;
|
||||||
AnalogStick r_stick;
|
|
||||||
};
|
};
|
||||||
static_assert(sizeof(XPadState) == 0x28, "XPadState is an invalid size");
|
static_assert(sizeof(BasicXpadState) == 0x20, "BasicXpadState is an invalid size");
|
||||||
|
|
||||||
struct XPadEntry {
|
// This is nn::hid::detail::BasicXpadLifo
|
||||||
CommonHeader header;
|
Lifo<BasicXpadState> basic_xpad_lifo{};
|
||||||
std::array<XPadState, 17> pad_states{};
|
static_assert(sizeof(basic_xpad_lifo) == 0x2C8, "basic_xpad_lifo is an invalid size");
|
||||||
INSERT_PADDING_BYTES(0x138);
|
BasicXpadState next_state{};
|
||||||
};
|
|
||||||
static_assert(sizeof(XPadEntry) == 0x400, "XPadEntry is an invalid size");
|
|
||||||
|
|
||||||
struct SharedMemory {
|
|
||||||
std::array<XPadEntry, 4> shared_memory_entries{};
|
|
||||||
};
|
|
||||||
static_assert(sizeof(SharedMemory) == 0x1000, "SharedMemory is an invalid size");
|
|
||||||
SharedMemory shared_memory{};
|
|
||||||
};
|
};
|
||||||
} // namespace Service::HID
|
} // namespace Service::HID
|
||||||
|
Loading…
Reference in New Issue
Block a user