Compare commits
25 Commits
Author | SHA1 | Date |
---|---|---|
|
a18c584f83 | |
|
971f0a395b | |
|
7843915b71 | |
|
a7306fb589 | |
|
6a0ef7de68 | |
|
e33e38467c | |
|
ce39e0dd45 | |
|
600a02fe29 | |
|
4f5b1fe41f | |
|
c695166391 | |
|
3f5d6c115f | |
|
b7c7505aca | |
|
d669f7e15f | |
|
74a1fba8e0 | |
|
5f63b6aed0 | |
|
e195aa523b | |
|
520150c78a | |
|
62edb120c1 | |
|
bb6b22482f | |
|
c45078844c | |
|
e6f30ed8ee | |
|
b65efa5823 | |
|
5c6a5487c7 | |
|
69f5f567d2 | |
|
a13ece1ca5 |
|
@ -181,20 +181,10 @@ add_library(core STATIC
|
||||||
frontend/framebuffer_layout.cpp
|
frontend/framebuffer_layout.cpp
|
||||||
frontend/framebuffer_layout.h
|
frontend/framebuffer_layout.h
|
||||||
frontend/graphics_context.h
|
frontend/graphics_context.h
|
||||||
hid/emulated_console.cpp
|
|
||||||
hid/emulated_console.h
|
|
||||||
hid/emulated_controller.cpp
|
|
||||||
hid/emulated_controller.h
|
|
||||||
hid/emulated_devices.cpp
|
|
||||||
hid/emulated_devices.h
|
|
||||||
hid/hid_core.cpp
|
hid/hid_core.cpp
|
||||||
hid/hid_core.h
|
hid/hid_core.h
|
||||||
hid/hid_types.h
|
|
||||||
hid/input_converter.cpp
|
hid/input_converter.cpp
|
||||||
hid/input_converter.h
|
hid/input_converter.h
|
||||||
hid/input_interpreter.cpp
|
|
||||||
hid/input_interpreter.h
|
|
||||||
hid/irs_types.h
|
|
||||||
hid/motion_input.cpp
|
hid/motion_input.cpp
|
||||||
hid/motion_input.h
|
hid/motion_input.h
|
||||||
hle/api_version.h
|
hle/api_version.h
|
||||||
|
@ -521,59 +511,53 @@ add_library(core STATIC
|
||||||
hle/service/grc/grc.h
|
hle/service/grc/grc.h
|
||||||
hle/service/hid/hid.cpp
|
hle/service/hid/hid.cpp
|
||||||
hle/service/hid/hid.h
|
hle/service/hid/hid.h
|
||||||
|
hle/service/hid/hid_debug_server.cpp
|
||||||
|
hle/service/hid/hid_debug_server.h
|
||||||
|
hle/service/hid/hid_firmware_settings.cpp
|
||||||
|
hle/service/hid/hid_firmware_settings.h
|
||||||
|
hle/service/hid/hid_result.h
|
||||||
|
hle/service/hid/hid_server.cpp
|
||||||
|
hle/service/hid/hid_server.h
|
||||||
|
hle/service/hid/hid_system_server.cpp
|
||||||
|
hle/service/hid/hid_system_server.h
|
||||||
|
hle/service/hid/hid_types.h
|
||||||
|
hle/service/hid/hid_util.h
|
||||||
hle/service/hid/hidbus.cpp
|
hle/service/hid/hidbus.cpp
|
||||||
hle/service/hid/hidbus.h
|
hle/service/hid/hidbus.h
|
||||||
hle/service/hid/irs.cpp
|
hle/service/hid/irs.cpp
|
||||||
hle/service/hid/irs.h
|
hle/service/hid/irs.h
|
||||||
hle/service/hid/irs_ring_lifo.h
|
hle/service/hid/resource_manager.cpp
|
||||||
hle/service/hid/ring_lifo.h
|
hle/service/hid/resource_manager.h
|
||||||
hle/service/hid/xcd.cpp
|
hle/service/hid/xcd.cpp
|
||||||
hle/service/hid/xcd.h
|
hle/service/hid/xcd.h
|
||||||
hle/service/hid/errors.h
|
hle/service/hid/resource_manager/npad_resource/npad.cpp
|
||||||
hle/service/hid/controllers/console_sixaxis.cpp
|
hle/service/hid/resource_manager/npad_resource/npad.h
|
||||||
hle/service/hid/controllers/console_sixaxis.h
|
hle/service/hid/resource_manager/npad_resource/npad_controller_state.cpp
|
||||||
hle/service/hid/controllers/controller_base.cpp
|
hle/service/hid/resource_manager/npad_resource/npad_controller_state.h
|
||||||
hle/service/hid/controllers/controller_base.h
|
hle/service/hid/resource_manager/npad_resource/npad_state.cpp
|
||||||
hle/service/hid/controllers/debug_pad.cpp
|
hle/service/hid/resource_manager/npad_resource/npad_state.h
|
||||||
hle/service/hid/controllers/debug_pad.h
|
hle/service/hid/resource_manager/npad_resource/npad_shared_types.h
|
||||||
hle/service/hid/controllers/gesture.cpp
|
hle/service/hid/resource_manager/base_resource.cpp
|
||||||
hle/service/hid/controllers/gesture.h
|
hle/service/hid/resource_manager/base_resource.h
|
||||||
hle/service/hid/controllers/keyboard.cpp
|
hle/service/hid/resource_manager/debug_pad.cpp
|
||||||
hle/service/hid/controllers/keyboard.h
|
hle/service/hid/resource_manager/debug_pad.h
|
||||||
hle/service/hid/controllers/mouse.cpp
|
hle/service/hid/resource_manager/gesture.cpp
|
||||||
hle/service/hid/controllers/mouse.h
|
hle/service/hid/resource_manager/gesture.h
|
||||||
hle/service/hid/controllers/npad.cpp
|
hle/service/hid/resource_manager/keyboard.cpp
|
||||||
hle/service/hid/controllers/npad.h
|
hle/service/hid/resource_manager/keyboard.h
|
||||||
hle/service/hid/controllers/palma.cpp
|
hle/service/hid/resource_manager/mouse.cpp
|
||||||
hle/service/hid/controllers/palma.h
|
hle/service/hid/resource_manager/mouse.h
|
||||||
hle/service/hid/controllers/stubbed.cpp
|
hle/service/hid/resource_manager/palma.cpp
|
||||||
hle/service/hid/controllers/stubbed.h
|
hle/service/hid/resource_manager/palma.h
|
||||||
hle/service/hid/controllers/touchscreen.cpp
|
hle/service/hid/resource_manager/ring_lifo.h
|
||||||
hle/service/hid/controllers/touchscreen.h
|
hle/service/hid/resource_manager/sixaxis.cpp
|
||||||
hle/service/hid/controllers/xpad.cpp
|
hle/service/hid/resource_manager/sixaxis.h
|
||||||
hle/service/hid/controllers/xpad.h
|
hle/service/hid/resource_manager/touch_screen.cpp
|
||||||
hle/service/hid/hidbus/hidbus_base.cpp
|
hle/service/hid/resource_manager/touch_screen.h
|
||||||
hle/service/hid/hidbus/hidbus_base.h
|
hle/service/hid/hidbus/hidbus_result.h
|
||||||
hle/service/hid/hidbus/ringcon.cpp
|
hle/service/hid/hidbus/hidbus_types.h
|
||||||
hle/service/hid/hidbus/ringcon.h
|
hle/service/hid/irs/irs_result.h
|
||||||
hle/service/hid/hidbus/starlink.cpp
|
hle/service/hid/irs/irs_types.h
|
||||||
hle/service/hid/hidbus/starlink.h
|
|
||||||
hle/service/hid/hidbus/stubbed.cpp
|
|
||||||
hle/service/hid/hidbus/stubbed.h
|
|
||||||
hle/service/hid/irsensor/clustering_processor.cpp
|
|
||||||
hle/service/hid/irsensor/clustering_processor.h
|
|
||||||
hle/service/hid/irsensor/image_transfer_processor.cpp
|
|
||||||
hle/service/hid/irsensor/image_transfer_processor.h
|
|
||||||
hle/service/hid/irsensor/ir_led_processor.cpp
|
|
||||||
hle/service/hid/irsensor/ir_led_processor.h
|
|
||||||
hle/service/hid/irsensor/moment_processor.cpp
|
|
||||||
hle/service/hid/irsensor/moment_processor.h
|
|
||||||
hle/service/hid/irsensor/pointing_processor.cpp
|
|
||||||
hle/service/hid/irsensor/pointing_processor.h
|
|
||||||
hle/service/hid/irsensor/processor_base.cpp
|
|
||||||
hle/service/hid/irsensor/processor_base.h
|
|
||||||
hle/service/hid/irsensor/tera_plugin_processor.cpp
|
|
||||||
hle/service/hid/irsensor/tera_plugin_processor.h
|
|
||||||
hle/service/lbl/lbl.cpp
|
hle/service/lbl/lbl.cpp
|
||||||
hle/service/lbl/lbl.h
|
hle/service/lbl/lbl.h
|
||||||
hle/service/ldn/lan_discovery.cpp
|
hle/service/ldn/lan_discovery.cpp
|
||||||
|
|
|
@ -6,9 +6,7 @@
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "common/settings_enums.h"
|
#include "common/settings_enums.h"
|
||||||
#include "core/frontend/applets/controller.h"
|
#include "core/frontend/applets/controller.h"
|
||||||
#include "core/hid/emulated_controller.h"
|
|
||||||
#include "core/hid/hid_core.h"
|
#include "core/hid/hid_core.h"
|
||||||
#include "core/hid/hid_types.h"
|
|
||||||
|
|
||||||
namespace Core::Frontend {
|
namespace Core::Frontend {
|
||||||
|
|
||||||
|
@ -24,54 +22,54 @@ void DefaultControllerApplet::ReconfigureControllers(ReconfigureCallback callbac
|
||||||
const ControllerParameters& parameters) const {
|
const ControllerParameters& parameters) const {
|
||||||
LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!");
|
LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!");
|
||||||
|
|
||||||
const std::size_t min_supported_players =
|
//const std::size_t min_supported_players =
|
||||||
parameters.enable_single_mode ? 1 : parameters.min_players;
|
// parameters.enable_single_mode ? 1 : parameters.min_players;
|
||||||
|
|
||||||
// Disconnect Handheld first.
|
//// Disconnect Handheld first.
|
||||||
auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
|
//auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
|
||||||
handheld->Disconnect();
|
//handheld->Disconnect();
|
||||||
|
|
||||||
// Deduce the best configuration based on the input parameters.
|
//// Deduce the best configuration based on the input parameters.
|
||||||
for (std::size_t index = 0; index < hid_core.available_controllers - 2; ++index) {
|
//for (std::size_t index = 0; index < hid_core.available_controllers - 2; ++index) {
|
||||||
auto* controller = hid_core.GetEmulatedControllerByIndex(index);
|
// auto* controller = hid_core.GetEmulatedControllerByIndex(index);
|
||||||
|
|
||||||
// First, disconnect all controllers regardless of the value of keep_controllers_connected.
|
// // First, disconnect all controllers regardless of the value of keep_controllers_connected.
|
||||||
// This makes it easy to connect the desired controllers.
|
// // This makes it easy to connect the desired controllers.
|
||||||
controller->Disconnect();
|
// controller->Disconnect();
|
||||||
|
|
||||||
// Only connect the minimum number of required players.
|
// // Only connect the minimum number of required players.
|
||||||
if (index >= min_supported_players) {
|
// if (index >= min_supported_players) {
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Connect controllers based on the following priority list from highest to lowest priority:
|
// // Connect controllers based on the following priority list from highest to lowest priority:
|
||||||
// Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld
|
// // Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld
|
||||||
if (parameters.allow_pro_controller) {
|
// if (parameters.allow_pro_controller) {
|
||||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
|
// controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
|
||||||
controller->Connect(true);
|
// controller->Connect(true);
|
||||||
} else if (parameters.allow_dual_joycons) {
|
// } else if (parameters.allow_dual_joycons) {
|
||||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual);
|
// controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual);
|
||||||
controller->Connect(true);
|
// controller->Connect(true);
|
||||||
} else if (parameters.allow_left_joycon && parameters.allow_right_joycon) {
|
// } else if (parameters.allow_left_joycon && parameters.allow_right_joycon) {
|
||||||
// Assign left joycons to even player indices and right joycons to odd player indices.
|
// // Assign left joycons to even player indices and right joycons to odd player indices.
|
||||||
// We do this since Captain Toad Treasure Tracker expects a left joycon for Player 1 and
|
// // We do this since Captain Toad Treasure Tracker expects a left joycon for Player 1 and
|
||||||
// a right Joycon for Player 2 in 2 Player Assist mode.
|
// // a right Joycon for Player 2 in 2 Player Assist mode.
|
||||||
if (index % 2 == 0) {
|
// if (index % 2 == 0) {
|
||||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconLeft);
|
// controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconLeft);
|
||||||
controller->Connect(true);
|
// controller->Connect(true);
|
||||||
} else {
|
// } else {
|
||||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconRight);
|
// controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconRight);
|
||||||
controller->Connect(true);
|
// controller->Connect(true);
|
||||||
}
|
// }
|
||||||
} else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld &&
|
// } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld &&
|
||||||
!Settings::IsDockedMode()) {
|
// !Settings::values.use_docked_mode.GetValue()) {
|
||||||
// We should *never* reach here under any normal circumstances.
|
// // We should *never* reach here under any normal circumstances.
|
||||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
|
// controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
|
||||||
controller->Connect(true);
|
// controller->Connect(true);
|
||||||
} else {
|
// } else {
|
||||||
ASSERT_MSG(false, "Unable to add a new controller based on the given parameters!");
|
// ASSERT_MSG(false, "Unable to add a new controller based on the given parameters!");
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
callback(true);
|
callback(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,324 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include "common/settings.h"
|
|
||||||
#include "core/hid/emulated_console.h"
|
|
||||||
#include "core/hid/input_converter.h"
|
|
||||||
|
|
||||||
namespace Core::HID {
|
|
||||||
EmulatedConsole::EmulatedConsole() = default;
|
|
||||||
|
|
||||||
EmulatedConsole::~EmulatedConsole() = default;
|
|
||||||
|
|
||||||
void EmulatedConsole::ReloadFromSettings() {
|
|
||||||
// Using first motion device from player 1. No need to assign any unique config at the moment
|
|
||||||
const auto& player = Settings::values.players.GetValue()[0];
|
|
||||||
motion_params[0] = Common::ParamPackage(player.motions[0]);
|
|
||||||
|
|
||||||
ReloadInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmulatedConsole::SetTouchParams() {
|
|
||||||
std::size_t index = 0;
|
|
||||||
|
|
||||||
// We can't use mouse as touch if native mouse is enabled
|
|
||||||
if (!Settings::values.mouse_enabled) {
|
|
||||||
touch_params[index++] =
|
|
||||||
Common::ParamPackage{"engine:mouse,axis_x:0,axis_y:1,button:0,port:2"};
|
|
||||||
}
|
|
||||||
|
|
||||||
touch_params[index++] =
|
|
||||||
Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536"};
|
|
||||||
touch_params[index++] =
|
|
||||||
Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072"};
|
|
||||||
|
|
||||||
for (int i = 0; i < static_cast<int>(MaxActiveTouchInputs); i++) {
|
|
||||||
Common::ParamPackage touchscreen_param{};
|
|
||||||
touchscreen_param.Set("engine", "touch");
|
|
||||||
touchscreen_param.Set("axis_x", i * 2);
|
|
||||||
touchscreen_param.Set("axis_y", (i * 2) + 1);
|
|
||||||
touchscreen_param.Set("button", i);
|
|
||||||
touch_params[index++] = std::move(touchscreen_param);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Settings::values.touch_from_button_maps.empty()) {
|
|
||||||
LOG_WARNING(Input, "touch_from_button_maps is unset by frontend config");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto button_index =
|
|
||||||
static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue());
|
|
||||||
const auto& touch_buttons = Settings::values.touch_from_button_maps[button_index].buttons;
|
|
||||||
|
|
||||||
// Map the rest of the fingers from touch from button configuration
|
|
||||||
for (const auto& config_entry : touch_buttons) {
|
|
||||||
if (index >= MaxTouchDevices) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Common::ParamPackage params{config_entry};
|
|
||||||
Common::ParamPackage touch_button_params;
|
|
||||||
const int x = params.Get("x", 0);
|
|
||||||
const int y = params.Get("y", 0);
|
|
||||||
params.Erase("x");
|
|
||||||
params.Erase("y");
|
|
||||||
touch_button_params.Set("engine", "touch_from_button");
|
|
||||||
touch_button_params.Set("button", params.Serialize());
|
|
||||||
touch_button_params.Set("x", x);
|
|
||||||
touch_button_params.Set("y", y);
|
|
||||||
touch_params[index] = std::move(touch_button_params);
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmulatedConsole::ReloadInput() {
|
|
||||||
// If you load any device here add the equivalent to the UnloadInput() function
|
|
||||||
SetTouchParams();
|
|
||||||
|
|
||||||
motion_params[1] = Common::ParamPackage{"engine:virtual_gamepad,port:8,motion:0"};
|
|
||||||
|
|
||||||
for (std::size_t index = 0; index < motion_devices.size(); ++index) {
|
|
||||||
motion_devices[index] = Common::Input::CreateInputDevice(motion_params[index]);
|
|
||||||
if (!motion_devices[index]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
motion_devices[index]->SetCallback({
|
|
||||||
.on_change =
|
|
||||||
[this](const Common::Input::CallbackStatus& callback) { SetMotion(callback); },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore motion state
|
|
||||||
auto& emulated_motion = console.motion_values.emulated;
|
|
||||||
auto& motion = console.motion_state;
|
|
||||||
emulated_motion.ResetRotations();
|
|
||||||
emulated_motion.ResetQuaternion();
|
|
||||||
motion.accel = emulated_motion.GetAcceleration();
|
|
||||||
motion.gyro = emulated_motion.GetGyroscope();
|
|
||||||
motion.rotation = emulated_motion.GetRotations();
|
|
||||||
motion.orientation = emulated_motion.GetOrientation();
|
|
||||||
motion.is_at_rest = !emulated_motion.IsMoving(motion_sensitivity);
|
|
||||||
|
|
||||||
// Unique index for identifying touch device source
|
|
||||||
std::size_t index = 0;
|
|
||||||
for (auto& touch_device : touch_devices) {
|
|
||||||
touch_device = Common::Input::CreateInputDevice(touch_params[index]);
|
|
||||||
if (!touch_device) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
touch_device->SetCallback({
|
|
||||||
.on_change =
|
|
||||||
[this, index](const Common::Input::CallbackStatus& callback) {
|
|
||||||
SetTouch(callback, index);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmulatedConsole::UnloadInput() {
|
|
||||||
for (auto& motion : motion_devices) {
|
|
||||||
motion.reset();
|
|
||||||
}
|
|
||||||
for (auto& touch : touch_devices) {
|
|
||||||
touch.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmulatedConsole::EnableConfiguration() {
|
|
||||||
is_configuring = true;
|
|
||||||
SaveCurrentConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmulatedConsole::DisableConfiguration() {
|
|
||||||
is_configuring = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EmulatedConsole::IsConfiguring() const {
|
|
||||||
return is_configuring;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmulatedConsole::SaveCurrentConfig() {
|
|
||||||
if (!is_configuring) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmulatedConsole::RestoreConfig() {
|
|
||||||
if (!is_configuring) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ReloadFromSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
Common::ParamPackage EmulatedConsole::GetMotionParam() const {
|
|
||||||
return motion_params[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmulatedConsole::SetMotionParam(Common::ParamPackage param) {
|
|
||||||
motion_params[0] = std::move(param);
|
|
||||||
ReloadInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) {
|
|
||||||
std::unique_lock lock{mutex};
|
|
||||||
auto& raw_status = console.motion_values.raw_status;
|
|
||||||
auto& emulated = console.motion_values.emulated;
|
|
||||||
|
|
||||||
raw_status = TransformToMotion(callback);
|
|
||||||
emulated.SetAcceleration(Common::Vec3f{
|
|
||||||
raw_status.accel.x.value,
|
|
||||||
raw_status.accel.y.value,
|
|
||||||
raw_status.accel.z.value,
|
|
||||||
});
|
|
||||||
emulated.SetGyroscope(Common::Vec3f{
|
|
||||||
raw_status.gyro.x.value,
|
|
||||||
raw_status.gyro.y.value,
|
|
||||||
raw_status.gyro.z.value,
|
|
||||||
});
|
|
||||||
emulated.UpdateRotation(raw_status.delta_timestamp);
|
|
||||||
emulated.UpdateOrientation(raw_status.delta_timestamp);
|
|
||||||
|
|
||||||
if (is_configuring) {
|
|
||||||
lock.unlock();
|
|
||||||
TriggerOnChange(ConsoleTriggerType::Motion);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& motion = console.motion_state;
|
|
||||||
motion.accel = emulated.GetAcceleration();
|
|
||||||
motion.gyro = emulated.GetGyroscope();
|
|
||||||
motion.rotation = emulated.GetRotations();
|
|
||||||
motion.orientation = emulated.GetOrientation();
|
|
||||||
motion.quaternion = emulated.GetQuaternion();
|
|
||||||
motion.gyro_bias = emulated.GetGyroBias();
|
|
||||||
motion.is_at_rest = !emulated.IsMoving(motion_sensitivity);
|
|
||||||
// Find what is this value
|
|
||||||
motion.verticalization_error = 0.0f;
|
|
||||||
|
|
||||||
lock.unlock();
|
|
||||||
TriggerOnChange(ConsoleTriggerType::Motion);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index) {
|
|
||||||
if (index >= MaxTouchDevices) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::unique_lock lock{mutex};
|
|
||||||
|
|
||||||
const auto touch_input = TransformToTouch(callback);
|
|
||||||
auto touch_index = GetIndexFromFingerId(index);
|
|
||||||
bool is_new_input = false;
|
|
||||||
|
|
||||||
if (!touch_index.has_value() && touch_input.pressed.value) {
|
|
||||||
touch_index = GetNextFreeIndex();
|
|
||||||
is_new_input = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No free entries or invalid state. Ignore input
|
|
||||||
if (!touch_index.has_value()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& touch_value = console.touch_values[touch_index.value()];
|
|
||||||
|
|
||||||
if (is_new_input) {
|
|
||||||
touch_value.pressed.value = true;
|
|
||||||
touch_value.id = static_cast<int>(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
touch_value.x = touch_input.x;
|
|
||||||
touch_value.y = touch_input.y;
|
|
||||||
|
|
||||||
if (!touch_input.pressed.value) {
|
|
||||||
touch_value.pressed.value = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_configuring) {
|
|
||||||
lock.unlock();
|
|
||||||
TriggerOnChange(ConsoleTriggerType::Touch);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Touch outside allowed range. Ignore input
|
|
||||||
if (touch_index.value() >= MaxActiveTouchInputs) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.touch_state[touch_index.value()] = {
|
|
||||||
.position = {touch_value.x.value, touch_value.y.value},
|
|
||||||
.id = static_cast<u32>(touch_index.value()),
|
|
||||||
.pressed = touch_input.pressed.value,
|
|
||||||
};
|
|
||||||
|
|
||||||
lock.unlock();
|
|
||||||
TriggerOnChange(ConsoleTriggerType::Touch);
|
|
||||||
}
|
|
||||||
|
|
||||||
ConsoleMotionValues EmulatedConsole::GetMotionValues() const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
return console.motion_values;
|
|
||||||
}
|
|
||||||
|
|
||||||
TouchValues EmulatedConsole::GetTouchValues() const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
return console.touch_values;
|
|
||||||
}
|
|
||||||
|
|
||||||
ConsoleMotion EmulatedConsole::GetMotion() const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
return console.motion_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
TouchFingerState EmulatedConsole::GetTouch() const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
return console.touch_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<std::size_t> EmulatedConsole::GetIndexFromFingerId(std::size_t finger_id) const {
|
|
||||||
for (std::size_t index = 0; index < MaxTouchDevices; ++index) {
|
|
||||||
const auto& finger = console.touch_values[index];
|
|
||||||
if (!finger.pressed.value) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (finger.id == static_cast<int>(finger_id)) {
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<std::size_t> EmulatedConsole::GetNextFreeIndex() const {
|
|
||||||
for (std::size_t index = 0; index < MaxTouchDevices; ++index) {
|
|
||||||
if (!console.touch_values[index].pressed.value) {
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) {
|
|
||||||
std::scoped_lock lock{callback_mutex};
|
|
||||||
for (const auto& poller_pair : callback_list) {
|
|
||||||
const ConsoleUpdateCallback& poller = poller_pair.second;
|
|
||||||
if (poller.on_change) {
|
|
||||||
poller.on_change(type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int EmulatedConsole::SetCallback(ConsoleUpdateCallback update_callback) {
|
|
||||||
std::scoped_lock lock{callback_mutex};
|
|
||||||
callback_list.insert_or_assign(last_callback_key, std::move(update_callback));
|
|
||||||
return last_callback_key++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmulatedConsole::DeleteCallback(int key) {
|
|
||||||
std::scoped_lock lock{callback_mutex};
|
|
||||||
const auto& iterator = callback_list.find(key);
|
|
||||||
if (iterator == callback_list.end()) {
|
|
||||||
LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
callback_list.erase(iterator);
|
|
||||||
}
|
|
||||||
} // namespace Core::HID
|
|
|
@ -1,200 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <functional>
|
|
||||||
#include <memory>
|
|
||||||
#include <mutex>
|
|
||||||
#include <optional>
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
#include "common/common_funcs.h"
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "common/input.h"
|
|
||||||
#include "common/param_package.h"
|
|
||||||
#include "common/point.h"
|
|
||||||
#include "common/quaternion.h"
|
|
||||||
#include "common/vector_math.h"
|
|
||||||
#include "core/hid/hid_types.h"
|
|
||||||
#include "core/hid/motion_input.h"
|
|
||||||
|
|
||||||
namespace Core::HID {
|
|
||||||
static constexpr std::size_t MaxTouchDevices = 32;
|
|
||||||
static constexpr std::size_t MaxActiveTouchInputs = 16;
|
|
||||||
|
|
||||||
struct ConsoleMotionInfo {
|
|
||||||
Common::Input::MotionStatus raw_status{};
|
|
||||||
MotionInput emulated{};
|
|
||||||
};
|
|
||||||
|
|
||||||
using ConsoleMotionDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, 2>;
|
|
||||||
using TouchDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, MaxTouchDevices>;
|
|
||||||
|
|
||||||
using ConsoleMotionParams = std::array<Common::ParamPackage, 2>;
|
|
||||||
using TouchParams = std::array<Common::ParamPackage, MaxTouchDevices>;
|
|
||||||
|
|
||||||
using ConsoleMotionValues = ConsoleMotionInfo;
|
|
||||||
using TouchValues = std::array<Common::Input::TouchStatus, MaxTouchDevices>;
|
|
||||||
|
|
||||||
struct TouchFinger {
|
|
||||||
u64 last_touch{};
|
|
||||||
Common::Point<float> position{};
|
|
||||||
u32 id{};
|
|
||||||
TouchAttribute attribute{};
|
|
||||||
bool pressed{};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Contains all motion related data that is used on the services
|
|
||||||
struct ConsoleMotion {
|
|
||||||
Common::Vec3f accel{};
|
|
||||||
Common::Vec3f gyro{};
|
|
||||||
Common::Vec3f rotation{};
|
|
||||||
std::array<Common::Vec3f, 3> orientation{};
|
|
||||||
Common::Quaternion<f32> quaternion{};
|
|
||||||
Common::Vec3f gyro_bias{};
|
|
||||||
f32 verticalization_error{};
|
|
||||||
bool is_at_rest{};
|
|
||||||
};
|
|
||||||
|
|
||||||
using TouchFingerState = std::array<TouchFinger, MaxActiveTouchInputs>;
|
|
||||||
|
|
||||||
struct ConsoleStatus {
|
|
||||||
// Data from input_common
|
|
||||||
ConsoleMotionValues motion_values{};
|
|
||||||
TouchValues touch_values{};
|
|
||||||
|
|
||||||
// Data for HID services
|
|
||||||
ConsoleMotion motion_state{};
|
|
||||||
TouchFingerState touch_state{};
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class ConsoleTriggerType {
|
|
||||||
Motion,
|
|
||||||
Touch,
|
|
||||||
All,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ConsoleUpdateCallback {
|
|
||||||
std::function<void(ConsoleTriggerType)> on_change;
|
|
||||||
};
|
|
||||||
|
|
||||||
class EmulatedConsole {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Contains all input data within the emulated switch console tablet such as touch and motion
|
|
||||||
*/
|
|
||||||
explicit EmulatedConsole();
|
|
||||||
~EmulatedConsole();
|
|
||||||
|
|
||||||
YUZU_NON_COPYABLE(EmulatedConsole);
|
|
||||||
YUZU_NON_MOVEABLE(EmulatedConsole);
|
|
||||||
|
|
||||||
/// Removes all callbacks created from input devices
|
|
||||||
void UnloadInput();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the emulated console into configuring mode
|
|
||||||
* This prevents the modification of the HID state of the emulated console by input commands
|
|
||||||
*/
|
|
||||||
void EnableConfiguration();
|
|
||||||
|
|
||||||
/// Returns the emulated console into normal mode, allowing the modification of the HID state
|
|
||||||
void DisableConfiguration();
|
|
||||||
|
|
||||||
/// Returns true if the emulated console is in configuring mode
|
|
||||||
bool IsConfiguring() const;
|
|
||||||
|
|
||||||
/// Reload all input devices
|
|
||||||
void ReloadInput();
|
|
||||||
|
|
||||||
/// Overrides current mapped devices with the stored configuration and reloads all input devices
|
|
||||||
void ReloadFromSettings();
|
|
||||||
|
|
||||||
/// Saves the current mapped configuration
|
|
||||||
void SaveCurrentConfig();
|
|
||||||
|
|
||||||
/// Reverts any mapped changes made that weren't saved
|
|
||||||
void RestoreConfig();
|
|
||||||
|
|
||||||
// Returns the current mapped motion device
|
|
||||||
Common::ParamPackage GetMotionParam() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the current mapped motion device
|
|
||||||
* @param param ParamPackage with controller data to be mapped
|
|
||||||
*/
|
|
||||||
void SetMotionParam(Common::ParamPackage param);
|
|
||||||
|
|
||||||
/// Returns the latest status of motion input from the console with parameters
|
|
||||||
ConsoleMotionValues GetMotionValues() const;
|
|
||||||
|
|
||||||
/// Returns the latest status of touch input from the console with parameters
|
|
||||||
TouchValues GetTouchValues() const;
|
|
||||||
|
|
||||||
/// Returns the latest status of motion input from the console
|
|
||||||
ConsoleMotion GetMotion() const;
|
|
||||||
|
|
||||||
/// Returns the latest status of touch input from the console
|
|
||||||
TouchFingerState GetTouch() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a callback to the list of events
|
|
||||||
* @param update_callback A ConsoleUpdateCallback that will be triggered
|
|
||||||
* @return an unique key corresponding to the callback index in the list
|
|
||||||
*/
|
|
||||||
int SetCallback(ConsoleUpdateCallback update_callback);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes a callback from the list stopping any future events to this object
|
|
||||||
* @param key Key corresponding to the callback index in the list
|
|
||||||
*/
|
|
||||||
void DeleteCallback(int key);
|
|
||||||
|
|
||||||
private:
|
|
||||||
/// Creates and stores the touch params
|
|
||||||
void SetTouchParams();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the motion status of the console
|
|
||||||
* @param callback A CallbackStatus containing gyro and accelerometer data
|
|
||||||
*/
|
|
||||||
void SetMotion(const Common::Input::CallbackStatus& callback);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the touch status of the console
|
|
||||||
* @param callback A CallbackStatus containing the touch position
|
|
||||||
* @param index Finger ID to be updated
|
|
||||||
*/
|
|
||||||
void SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index);
|
|
||||||
|
|
||||||
std::optional<std::size_t> GetIndexFromFingerId(std::size_t finger_id) const;
|
|
||||||
|
|
||||||
std::optional<std::size_t> GetNextFreeIndex() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Triggers a callback that something has changed on the console status
|
|
||||||
* @param type Input type of the event to trigger
|
|
||||||
*/
|
|
||||||
void TriggerOnChange(ConsoleTriggerType type);
|
|
||||||
|
|
||||||
bool is_configuring{false};
|
|
||||||
f32 motion_sensitivity{0.01f};
|
|
||||||
|
|
||||||
ConsoleMotionParams motion_params;
|
|
||||||
TouchParams touch_params;
|
|
||||||
|
|
||||||
ConsoleMotionDevices motion_devices;
|
|
||||||
TouchDevices touch_devices;
|
|
||||||
|
|
||||||
mutable std::mutex mutex;
|
|
||||||
mutable std::mutex callback_mutex;
|
|
||||||
std::unordered_map<int, ConsoleUpdateCallback> callback_list;
|
|
||||||
int last_callback_key = 0;
|
|
||||||
|
|
||||||
// Stores the current status of all console input
|
|
||||||
ConsoleStatus console;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Core::HID
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,615 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <functional>
|
|
||||||
#include <memory>
|
|
||||||
#include <mutex>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "common/input.h"
|
|
||||||
#include "common/param_package.h"
|
|
||||||
#include "common/settings.h"
|
|
||||||
#include "common/vector_math.h"
|
|
||||||
#include "core/hid/hid_types.h"
|
|
||||||
#include "core/hid/irs_types.h"
|
|
||||||
#include "core/hid/motion_input.h"
|
|
||||||
|
|
||||||
namespace Core::HID {
|
|
||||||
const std::size_t max_emulated_controllers = 2;
|
|
||||||
const std::size_t output_devices_size = 4;
|
|
||||||
struct ControllerMotionInfo {
|
|
||||||
Common::Input::MotionStatus raw_status{};
|
|
||||||
MotionInput emulated{};
|
|
||||||
};
|
|
||||||
|
|
||||||
using ButtonDevices =
|
|
||||||
std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeButton::NumButtons>;
|
|
||||||
using StickDevices =
|
|
||||||
std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeAnalog::NumAnalogs>;
|
|
||||||
using ControllerMotionDevices =
|
|
||||||
std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeMotion::NumMotions>;
|
|
||||||
using TriggerDevices =
|
|
||||||
std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeTrigger::NumTriggers>;
|
|
||||||
using ColorDevices =
|
|
||||||
std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
|
|
||||||
using BatteryDevices =
|
|
||||||
std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
|
|
||||||
using CameraDevices =
|
|
||||||
std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
|
|
||||||
using RingAnalogDevices =
|
|
||||||
std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
|
|
||||||
using NfcDevices =
|
|
||||||
std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
|
|
||||||
using OutputDevices = std::array<std::unique_ptr<Common::Input::OutputDevice>, output_devices_size>;
|
|
||||||
|
|
||||||
using ButtonParams = std::array<Common::ParamPackage, Settings::NativeButton::NumButtons>;
|
|
||||||
using StickParams = std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs>;
|
|
||||||
using ControllerMotionParams = std::array<Common::ParamPackage, Settings::NativeMotion::NumMotions>;
|
|
||||||
using TriggerParams = std::array<Common::ParamPackage, Settings::NativeTrigger::NumTriggers>;
|
|
||||||
using ColorParams = std::array<Common::ParamPackage, max_emulated_controllers>;
|
|
||||||
using BatteryParams = std::array<Common::ParamPackage, max_emulated_controllers>;
|
|
||||||
using CameraParams = std::array<Common::ParamPackage, max_emulated_controllers>;
|
|
||||||
using RingAnalogParams = std::array<Common::ParamPackage, max_emulated_controllers>;
|
|
||||||
using NfcParams = std::array<Common::ParamPackage, max_emulated_controllers>;
|
|
||||||
using OutputParams = std::array<Common::ParamPackage, output_devices_size>;
|
|
||||||
|
|
||||||
using ButtonValues = std::array<Common::Input::ButtonStatus, Settings::NativeButton::NumButtons>;
|
|
||||||
using SticksValues = std::array<Common::Input::StickStatus, Settings::NativeAnalog::NumAnalogs>;
|
|
||||||
using TriggerValues =
|
|
||||||
std::array<Common::Input::TriggerStatus, Settings::NativeTrigger::NumTriggers>;
|
|
||||||
using ControllerMotionValues = std::array<ControllerMotionInfo, Settings::NativeMotion::NumMotions>;
|
|
||||||
using ColorValues = std::array<Common::Input::BodyColorStatus, max_emulated_controllers>;
|
|
||||||
using BatteryValues = std::array<Common::Input::BatteryStatus, max_emulated_controllers>;
|
|
||||||
using CameraValues = Common::Input::CameraStatus;
|
|
||||||
using RingAnalogValue = Common::Input::AnalogStatus;
|
|
||||||
using NfcValues = Common::Input::NfcStatus;
|
|
||||||
using VibrationValues = std::array<Common::Input::VibrationStatus, max_emulated_controllers>;
|
|
||||||
|
|
||||||
struct AnalogSticks {
|
|
||||||
AnalogStickState left{};
|
|
||||||
AnalogStickState right{};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ControllerColors {
|
|
||||||
NpadControllerColor fullkey{};
|
|
||||||
NpadControllerColor left{};
|
|
||||||
NpadControllerColor right{};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BatteryLevelState {
|
|
||||||
NpadPowerInfo dual{};
|
|
||||||
NpadPowerInfo left{};
|
|
||||||
NpadPowerInfo right{};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CameraState {
|
|
||||||
Core::IrSensor::ImageTransferProcessorFormat format{};
|
|
||||||
std::vector<u8> data{};
|
|
||||||
std::size_t sample{};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct RingSensorForce {
|
|
||||||
f32 force;
|
|
||||||
};
|
|
||||||
|
|
||||||
using NfcState = Common::Input::NfcStatus;
|
|
||||||
|
|
||||||
struct ControllerMotion {
|
|
||||||
Common::Vec3f accel{};
|
|
||||||
Common::Vec3f gyro{};
|
|
||||||
Common::Vec3f rotation{};
|
|
||||||
Common::Vec3f euler{};
|
|
||||||
std::array<Common::Vec3f, 3> orientation{};
|
|
||||||
bool is_at_rest{};
|
|
||||||
};
|
|
||||||
|
|
||||||
enum EmulatedDeviceIndex : u8 {
|
|
||||||
LeftIndex,
|
|
||||||
RightIndex,
|
|
||||||
DualIndex,
|
|
||||||
AllDevices,
|
|
||||||
};
|
|
||||||
|
|
||||||
using MotionState = std::array<ControllerMotion, 2>;
|
|
||||||
|
|
||||||
struct ControllerStatus {
|
|
||||||
// Data from input_common
|
|
||||||
ButtonValues button_values{};
|
|
||||||
SticksValues stick_values{};
|
|
||||||
ControllerMotionValues motion_values{};
|
|
||||||
TriggerValues trigger_values{};
|
|
||||||
ColorValues color_values{};
|
|
||||||
BatteryValues battery_values{};
|
|
||||||
VibrationValues vibration_values{};
|
|
||||||
CameraValues camera_values{};
|
|
||||||
RingAnalogValue ring_analog_value{};
|
|
||||||
NfcValues nfc_values{};
|
|
||||||
|
|
||||||
// Data for HID services
|
|
||||||
HomeButtonState home_button_state{};
|
|
||||||
CaptureButtonState capture_button_state{};
|
|
||||||
NpadButtonState npad_button_state{};
|
|
||||||
DebugPadButton debug_pad_button_state{};
|
|
||||||
AnalogSticks analog_stick_state{};
|
|
||||||
MotionState motion_state{};
|
|
||||||
NpadGcTriggerState gc_trigger_state{};
|
|
||||||
ControllerColors colors_state{};
|
|
||||||
BatteryLevelState battery_state{};
|
|
||||||
CameraState camera_state{};
|
|
||||||
RingSensorForce ring_analog_state{};
|
|
||||||
NfcState nfc_state{};
|
|
||||||
Common::Input::PollingMode left_polling_mode{};
|
|
||||||
Common::Input::PollingMode right_polling_mode{};
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class ControllerTriggerType {
|
|
||||||
Button,
|
|
||||||
Stick,
|
|
||||||
Trigger,
|
|
||||||
Motion,
|
|
||||||
Color,
|
|
||||||
Battery,
|
|
||||||
Vibration,
|
|
||||||
IrSensor,
|
|
||||||
RingController,
|
|
||||||
Nfc,
|
|
||||||
Connected,
|
|
||||||
Disconnected,
|
|
||||||
Type,
|
|
||||||
All,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ControllerUpdateCallback {
|
|
||||||
std::function<void(ControllerTriggerType)> on_change;
|
|
||||||
bool is_npad_service;
|
|
||||||
};
|
|
||||||
|
|
||||||
class EmulatedController {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Contains all input data (buttons, joysticks, vibration, and motion) within this controller.
|
|
||||||
* @param npad_id_type npad id type for this specific controller
|
|
||||||
*/
|
|
||||||
explicit EmulatedController(NpadIdType npad_id_type_);
|
|
||||||
~EmulatedController();
|
|
||||||
|
|
||||||
YUZU_NON_COPYABLE(EmulatedController);
|
|
||||||
YUZU_NON_MOVEABLE(EmulatedController);
|
|
||||||
|
|
||||||
/// Converts the controller type from settings to npad type
|
|
||||||
static NpadStyleIndex MapSettingsTypeToNPad(Settings::ControllerType type);
|
|
||||||
|
|
||||||
/// Converts npad type to the equivalent of controller type from settings
|
|
||||||
static Settings::ControllerType MapNPadToSettingsType(NpadStyleIndex type);
|
|
||||||
|
|
||||||
/// Gets the NpadIdType for this controller
|
|
||||||
NpadIdType GetNpadIdType() const;
|
|
||||||
|
|
||||||
/// Sets the NpadStyleIndex for this controller
|
|
||||||
void SetNpadStyleIndex(NpadStyleIndex npad_type_);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the NpadStyleIndex for this controller
|
|
||||||
* @param get_temporary_value If true tmp_npad_type will be returned
|
|
||||||
* @return NpadStyleIndex set on the controller
|
|
||||||
*/
|
|
||||||
NpadStyleIndex GetNpadStyleIndex(bool get_temporary_value = false) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the supported controller types. Disconnects the controller if current type is not
|
|
||||||
* supported
|
|
||||||
* @param supported_styles bitflag with supported types
|
|
||||||
*/
|
|
||||||
void SetSupportedNpadStyleTag(NpadStyleTag supported_styles);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the connected status to true
|
|
||||||
* @param use_temporary_value If true tmp_npad_type will be used
|
|
||||||
*/
|
|
||||||
void Connect(bool use_temporary_value = false);
|
|
||||||
|
|
||||||
/// Sets the connected status to false
|
|
||||||
void Disconnect();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is the emulated connected
|
|
||||||
* @param get_temporary_value If true tmp_is_connected will be returned
|
|
||||||
* @return true if the controller has the connected status
|
|
||||||
*/
|
|
||||||
bool IsConnected(bool get_temporary_value = false) const;
|
|
||||||
|
|
||||||
/// Removes all callbacks created from input devices
|
|
||||||
void UnloadInput();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the emulated controller into configuring mode
|
|
||||||
* This prevents the modification of the HID state of the emulated controller by input commands
|
|
||||||
*/
|
|
||||||
void EnableConfiguration();
|
|
||||||
|
|
||||||
/// Returns the emulated controller into normal mode, allowing the modification of the HID state
|
|
||||||
void DisableConfiguration();
|
|
||||||
|
|
||||||
/// Enables Home and Screenshot buttons
|
|
||||||
void EnableSystemButtons();
|
|
||||||
|
|
||||||
/// Disables Home and Screenshot buttons
|
|
||||||
void DisableSystemButtons();
|
|
||||||
|
|
||||||
/// Sets Home and Screenshot buttons to false
|
|
||||||
void ResetSystemButtons();
|
|
||||||
|
|
||||||
/// Returns true if the emulated controller is in configuring mode
|
|
||||||
bool IsConfiguring() const;
|
|
||||||
|
|
||||||
/// Reload all input devices
|
|
||||||
void ReloadInput();
|
|
||||||
|
|
||||||
/// Overrides current mapped devices with the stored configuration and reloads all input devices
|
|
||||||
void ReloadFromSettings();
|
|
||||||
|
|
||||||
/// Saves the current mapped configuration
|
|
||||||
void SaveCurrentConfig();
|
|
||||||
|
|
||||||
/// Reverts any mapped changes made that weren't saved
|
|
||||||
void RestoreConfig();
|
|
||||||
|
|
||||||
/// Returns a vector of mapped devices from the mapped button and stick parameters
|
|
||||||
std::vector<Common::ParamPackage> GetMappedDevices() const;
|
|
||||||
|
|
||||||
// Returns the current mapped button device
|
|
||||||
Common::ParamPackage GetButtonParam(std::size_t index) const;
|
|
||||||
|
|
||||||
// Returns the current mapped stick device
|
|
||||||
Common::ParamPackage GetStickParam(std::size_t index) const;
|
|
||||||
|
|
||||||
// Returns the current mapped motion device
|
|
||||||
Common::ParamPackage GetMotionParam(std::size_t index) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the current mapped button device
|
|
||||||
* @param param ParamPackage with controller data to be mapped
|
|
||||||
*/
|
|
||||||
void SetButtonParam(std::size_t index, Common::ParamPackage param);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the current mapped stick device
|
|
||||||
* @param param ParamPackage with controller data to be mapped
|
|
||||||
*/
|
|
||||||
void SetStickParam(std::size_t index, Common::ParamPackage param);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the current mapped motion device
|
|
||||||
* @param param ParamPackage with controller data to be mapped
|
|
||||||
*/
|
|
||||||
void SetMotionParam(std::size_t index, Common::ParamPackage param);
|
|
||||||
|
|
||||||
/// Auto calibrates the current motion devices
|
|
||||||
void StartMotionCalibration();
|
|
||||||
|
|
||||||
/// Returns the latest button status from the controller with parameters
|
|
||||||
ButtonValues GetButtonsValues() const;
|
|
||||||
|
|
||||||
/// Returns the latest analog stick status from the controller with parameters
|
|
||||||
SticksValues GetSticksValues() const;
|
|
||||||
|
|
||||||
/// Returns the latest trigger status from the controller with parameters
|
|
||||||
TriggerValues GetTriggersValues() const;
|
|
||||||
|
|
||||||
/// Returns the latest motion status from the controller with parameters
|
|
||||||
ControllerMotionValues GetMotionValues() const;
|
|
||||||
|
|
||||||
/// Returns the latest color status from the controller with parameters
|
|
||||||
ColorValues GetColorsValues() const;
|
|
||||||
|
|
||||||
/// Returns the latest battery status from the controller with parameters
|
|
||||||
BatteryValues GetBatteryValues() const;
|
|
||||||
|
|
||||||
/// Returns the latest camera status from the controller with parameters
|
|
||||||
CameraValues GetCameraValues() const;
|
|
||||||
|
|
||||||
/// Returns the latest status of analog input from the ring sensor with parameters
|
|
||||||
RingAnalogValue GetRingSensorValues() const;
|
|
||||||
|
|
||||||
/// Returns the latest status of button input for the hid::HomeButton service
|
|
||||||
HomeButtonState GetHomeButtons() const;
|
|
||||||
|
|
||||||
/// Returns the latest status of button input for the hid::CaptureButton service
|
|
||||||
CaptureButtonState GetCaptureButtons() const;
|
|
||||||
|
|
||||||
/// Returns the latest status of button input for the hid::Npad service
|
|
||||||
NpadButtonState GetNpadButtons() const;
|
|
||||||
|
|
||||||
/// Returns the latest status of button input for the debug pad service
|
|
||||||
DebugPadButton GetDebugPadButtons() const;
|
|
||||||
|
|
||||||
/// Returns the latest status of stick input from the mouse
|
|
||||||
AnalogSticks GetSticks() const;
|
|
||||||
|
|
||||||
/// Returns the latest status of trigger input from the mouse
|
|
||||||
NpadGcTriggerState GetTriggers() const;
|
|
||||||
|
|
||||||
/// Returns the latest status of motion input from the mouse
|
|
||||||
MotionState GetMotions() const;
|
|
||||||
|
|
||||||
/// Returns the latest color value from the controller
|
|
||||||
ControllerColors GetColors() const;
|
|
||||||
|
|
||||||
/// Returns the latest battery status from the controller
|
|
||||||
BatteryLevelState GetBattery() const;
|
|
||||||
|
|
||||||
/// Returns the latest camera status from the controller
|
|
||||||
const CameraState& GetCamera() const;
|
|
||||||
|
|
||||||
/// Returns the latest ringcon force sensor value
|
|
||||||
RingSensorForce GetRingSensorForce() const;
|
|
||||||
|
|
||||||
/// Returns the latest ntag status from the controller
|
|
||||||
const NfcState& GetNfc() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a specific vibration to the output device
|
|
||||||
* @return true if vibration had no errors
|
|
||||||
*/
|
|
||||||
bool SetVibration(std::size_t device_index, VibrationValue vibration);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a small vibration to the output device
|
|
||||||
* @return true if SetVibration was successful
|
|
||||||
*/
|
|
||||||
bool IsVibrationEnabled(std::size_t device_index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the desired data to be polled from a controller
|
|
||||||
* @param device_index index of the controller to set the polling mode
|
|
||||||
* @param polling_mode type of input desired buttons, gyro, nfc, ir, etc.
|
|
||||||
* @return driver result from this command
|
|
||||||
*/
|
|
||||||
Common::Input::DriverResult SetPollingMode(EmulatedDeviceIndex device_index,
|
|
||||||
Common::Input::PollingMode polling_mode);
|
|
||||||
/**
|
|
||||||
* Get the current polling mode from a controller
|
|
||||||
* @param device_index index of the controller to set the polling mode
|
|
||||||
* @return current polling mode
|
|
||||||
*/
|
|
||||||
Common::Input::PollingMode GetPollingMode(EmulatedDeviceIndex device_index) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the desired camera format to be polled from a controller
|
|
||||||
* @param camera_format size of each frame
|
|
||||||
* @return true if SetCameraFormat was successful
|
|
||||||
*/
|
|
||||||
bool SetCameraFormat(Core::IrSensor::ImageTransferProcessorFormat camera_format);
|
|
||||||
|
|
||||||
// Returns the current mapped ring device
|
|
||||||
Common::ParamPackage GetRingParam() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the current mapped ring device
|
|
||||||
* @param param ParamPackage with ring sensor data to be mapped
|
|
||||||
*/
|
|
||||||
void SetRingParam(Common::ParamPackage param);
|
|
||||||
|
|
||||||
/// Returns true if the device has nfc support
|
|
||||||
bool HasNfc() const;
|
|
||||||
|
|
||||||
/// Sets the joycon in nfc mode and increments the handle count
|
|
||||||
bool AddNfcHandle();
|
|
||||||
|
|
||||||
/// Decrements the handle count if zero sets the joycon in active mode
|
|
||||||
bool RemoveNfcHandle();
|
|
||||||
|
|
||||||
/// Start searching for nfc tags
|
|
||||||
bool StartNfcPolling();
|
|
||||||
|
|
||||||
/// Stop searching for nfc tags
|
|
||||||
bool StopNfcPolling();
|
|
||||||
|
|
||||||
/// Returns true if the nfc tag was readable
|
|
||||||
bool ReadAmiiboData(std::vector<u8>& data);
|
|
||||||
|
|
||||||
/// Returns true if the nfc tag was written
|
|
||||||
bool WriteNfc(const std::vector<u8>& data);
|
|
||||||
|
|
||||||
/// Returns true if the nfc tag was readable
|
|
||||||
bool ReadMifareData(const Common::Input::MifareRequest& request,
|
|
||||||
Common::Input::MifareRequest& out_data);
|
|
||||||
|
|
||||||
/// Returns true if the nfc tag was written
|
|
||||||
bool WriteMifareData(const Common::Input::MifareRequest& request);
|
|
||||||
|
|
||||||
/// Returns the led pattern corresponding to this emulated controller
|
|
||||||
LedPattern GetLedPattern() const;
|
|
||||||
|
|
||||||
/// Asks the output device to change the player led pattern
|
|
||||||
void SetLedPattern();
|
|
||||||
|
|
||||||
/// Changes sensitivity of the motion sensor
|
|
||||||
void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode mode);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a callback to the list of events
|
|
||||||
* @param update_callback A ConsoleUpdateCallback that will be triggered
|
|
||||||
* @return an unique key corresponding to the callback index in the list
|
|
||||||
*/
|
|
||||||
int SetCallback(ControllerUpdateCallback update_callback);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes a callback from the list stopping any future events to this object
|
|
||||||
* @param key Key corresponding to the callback index in the list
|
|
||||||
*/
|
|
||||||
void DeleteCallback(int key);
|
|
||||||
|
|
||||||
/// Swaps the state of the turbo buttons and updates motion input
|
|
||||||
void StatusUpdate();
|
|
||||||
|
|
||||||
private:
|
|
||||||
/// creates input devices from params
|
|
||||||
void LoadDevices();
|
|
||||||
|
|
||||||
/// Set the params for TAS devices
|
|
||||||
void LoadTASParams();
|
|
||||||
|
|
||||||
/// Set the params for virtual pad devices
|
|
||||||
void LoadVirtualGamepadParams();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param use_temporary_value If true tmp_npad_type will be used
|
|
||||||
* @return true if the controller style is fullkey
|
|
||||||
*/
|
|
||||||
bool IsControllerFullkey(bool use_temporary_value = false) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks the current controller type against the supported_style_tag
|
|
||||||
* @param use_temporary_value If true tmp_npad_type will be used
|
|
||||||
* @return true if the controller is supported
|
|
||||||
*/
|
|
||||||
bool IsControllerSupported(bool use_temporary_value = false) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the button status of the controller
|
|
||||||
* @param callback A CallbackStatus containing the button status
|
|
||||||
* @param index Button ID of the to be updated
|
|
||||||
*/
|
|
||||||
void SetButton(const Common::Input::CallbackStatus& callback, std::size_t index,
|
|
||||||
Common::UUID uuid);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the analog stick status of the controller
|
|
||||||
* @param callback A CallbackStatus containing the analog stick status
|
|
||||||
* @param index stick ID of the to be updated
|
|
||||||
*/
|
|
||||||
void SetStick(const Common::Input::CallbackStatus& callback, std::size_t index,
|
|
||||||
Common::UUID uuid);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the trigger status of the controller
|
|
||||||
* @param callback A CallbackStatus containing the trigger status
|
|
||||||
* @param index trigger ID of the to be updated
|
|
||||||
*/
|
|
||||||
void SetTrigger(const Common::Input::CallbackStatus& callback, std::size_t index,
|
|
||||||
Common::UUID uuid);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the motion status of the controller
|
|
||||||
* @param callback A CallbackStatus containing gyro and accelerometer data
|
|
||||||
* @param index motion ID of the to be updated
|
|
||||||
*/
|
|
||||||
void SetMotion(const Common::Input::CallbackStatus& callback, std::size_t index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the color status of the controller
|
|
||||||
* @param callback A CallbackStatus containing the color status
|
|
||||||
* @param index color ID of the to be updated
|
|
||||||
*/
|
|
||||||
void SetColors(const Common::Input::CallbackStatus& callback, std::size_t index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the battery status of the controller
|
|
||||||
* @param callback A CallbackStatus containing the battery status
|
|
||||||
* @param index battery ID of the to be updated
|
|
||||||
*/
|
|
||||||
void SetBattery(const Common::Input::CallbackStatus& callback, std::size_t index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the camera status of the controller
|
|
||||||
* @param callback A CallbackStatus containing the camera status
|
|
||||||
*/
|
|
||||||
void SetCamera(const Common::Input::CallbackStatus& callback);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the ring analog sensor status of the ring controller
|
|
||||||
* @param callback A CallbackStatus containing the force status
|
|
||||||
*/
|
|
||||||
void SetRingAnalog(const Common::Input::CallbackStatus& callback);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the nfc status of the controller
|
|
||||||
* @param callback A CallbackStatus containing the nfc status
|
|
||||||
*/
|
|
||||||
void SetNfc(const Common::Input::CallbackStatus& callback);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a color format from bgra to rgba
|
|
||||||
* @param color in bgra format
|
|
||||||
* @return NpadColor in rgba format
|
|
||||||
*/
|
|
||||||
NpadColor GetNpadColor(u32 color);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Triggers a callback that something has changed on the controller status
|
|
||||||
* @param type Input type of the event to trigger
|
|
||||||
* @param is_service_update indicates if this event should only be sent to HID services
|
|
||||||
*/
|
|
||||||
void TriggerOnChange(ControllerTriggerType type, bool is_service_update);
|
|
||||||
|
|
||||||
NpadButton GetTurboButtonMask() const;
|
|
||||||
|
|
||||||
const NpadIdType npad_id_type;
|
|
||||||
NpadStyleIndex npad_type{NpadStyleIndex::None};
|
|
||||||
NpadStyleIndex original_npad_type{NpadStyleIndex::None};
|
|
||||||
NpadStyleTag supported_style_tag{NpadStyleSet::All};
|
|
||||||
bool is_connected{false};
|
|
||||||
bool is_configuring{false};
|
|
||||||
bool system_buttons_enabled{true};
|
|
||||||
f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard};
|
|
||||||
u32 turbo_button_state{0};
|
|
||||||
std::size_t nfc_handles{0};
|
|
||||||
|
|
||||||
// Temporary values to avoid doing changes while the controller is in configuring mode
|
|
||||||
NpadStyleIndex tmp_npad_type{NpadStyleIndex::None};
|
|
||||||
bool tmp_is_connected{false};
|
|
||||||
|
|
||||||
ButtonParams button_params;
|
|
||||||
StickParams stick_params;
|
|
||||||
ControllerMotionParams motion_params;
|
|
||||||
TriggerParams trigger_params;
|
|
||||||
BatteryParams battery_params;
|
|
||||||
ColorParams color_params;
|
|
||||||
CameraParams camera_params;
|
|
||||||
RingAnalogParams ring_params;
|
|
||||||
NfcParams nfc_params;
|
|
||||||
OutputParams output_params;
|
|
||||||
|
|
||||||
ButtonDevices button_devices;
|
|
||||||
StickDevices stick_devices;
|
|
||||||
ControllerMotionDevices motion_devices;
|
|
||||||
TriggerDevices trigger_devices;
|
|
||||||
BatteryDevices battery_devices;
|
|
||||||
ColorDevices color_devices;
|
|
||||||
CameraDevices camera_devices;
|
|
||||||
RingAnalogDevices ring_analog_devices;
|
|
||||||
NfcDevices nfc_devices;
|
|
||||||
OutputDevices output_devices;
|
|
||||||
|
|
||||||
// TAS related variables
|
|
||||||
ButtonParams tas_button_params;
|
|
||||||
StickParams tas_stick_params;
|
|
||||||
ButtonDevices tas_button_devices;
|
|
||||||
StickDevices tas_stick_devices;
|
|
||||||
|
|
||||||
// Virtual gamepad related variables
|
|
||||||
ButtonParams virtual_button_params;
|
|
||||||
StickParams virtual_stick_params;
|
|
||||||
ControllerMotionParams virtual_motion_params;
|
|
||||||
ButtonDevices virtual_button_devices;
|
|
||||||
StickDevices virtual_stick_devices;
|
|
||||||
ControllerMotionDevices virtual_motion_devices;
|
|
||||||
|
|
||||||
mutable std::mutex mutex;
|
|
||||||
mutable std::mutex callback_mutex;
|
|
||||||
mutable std::mutex npad_mutex;
|
|
||||||
mutable std::mutex connect_mutex;
|
|
||||||
std::unordered_map<int, ControllerUpdateCallback> callback_list;
|
|
||||||
int last_callback_key = 0;
|
|
||||||
|
|
||||||
// Stores the current status of all controller input
|
|
||||||
ControllerStatus controller;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Core::HID
|
|
|
@ -1,483 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <fmt/format.h>
|
|
||||||
|
|
||||||
#include "core/hid/emulated_devices.h"
|
|
||||||
#include "core/hid/input_converter.h"
|
|
||||||
|
|
||||||
namespace Core::HID {
|
|
||||||
|
|
||||||
EmulatedDevices::EmulatedDevices() = default;
|
|
||||||
|
|
||||||
EmulatedDevices::~EmulatedDevices() = default;
|
|
||||||
|
|
||||||
void EmulatedDevices::ReloadFromSettings() {
|
|
||||||
ReloadInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmulatedDevices::ReloadInput() {
|
|
||||||
// If you load any device here add the equivalent to the UnloadInput() function
|
|
||||||
|
|
||||||
// Native Mouse is mapped on port 1, pad 0
|
|
||||||
const Common::ParamPackage mouse_params{"engine:mouse,port:1,pad:0"};
|
|
||||||
|
|
||||||
// Keyboard keys is mapped on port 1, pad 0 for normal keys, pad 1 for moddifier keys
|
|
||||||
const Common::ParamPackage keyboard_params{"engine:keyboard,port:1"};
|
|
||||||
|
|
||||||
std::size_t key_index = 0;
|
|
||||||
for (auto& mouse_device : mouse_button_devices) {
|
|
||||||
Common::ParamPackage mouse_button_params = mouse_params;
|
|
||||||
mouse_button_params.Set("button", static_cast<int>(key_index));
|
|
||||||
mouse_device = Common::Input::CreateInputDevice(mouse_button_params);
|
|
||||||
key_index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
Common::ParamPackage mouse_position_params = mouse_params;
|
|
||||||
mouse_position_params.Set("axis_x", 0);
|
|
||||||
mouse_position_params.Set("axis_y", 1);
|
|
||||||
mouse_position_params.Set("deadzone", 0.0f);
|
|
||||||
mouse_position_params.Set("range", 1.0f);
|
|
||||||
mouse_position_params.Set("threshold", 0.0f);
|
|
||||||
mouse_stick_device = Common::Input::CreateInputDevice(mouse_position_params);
|
|
||||||
|
|
||||||
// First two axis are reserved for mouse position
|
|
||||||
key_index = 2;
|
|
||||||
for (auto& mouse_device : mouse_wheel_devices) {
|
|
||||||
Common::ParamPackage mouse_wheel_params = mouse_params;
|
|
||||||
mouse_wheel_params.Set("axis", static_cast<int>(key_index));
|
|
||||||
mouse_device = Common::Input::CreateInputDevice(mouse_wheel_params);
|
|
||||||
key_index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
key_index = 0;
|
|
||||||
for (auto& keyboard_device : keyboard_devices) {
|
|
||||||
Common::ParamPackage keyboard_key_params = keyboard_params;
|
|
||||||
keyboard_key_params.Set("button", static_cast<int>(key_index));
|
|
||||||
keyboard_key_params.Set("pad", 0);
|
|
||||||
keyboard_device = Common::Input::CreateInputDevice(keyboard_key_params);
|
|
||||||
key_index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
key_index = 0;
|
|
||||||
for (auto& keyboard_device : keyboard_modifier_devices) {
|
|
||||||
Common::ParamPackage keyboard_moddifier_params = keyboard_params;
|
|
||||||
keyboard_moddifier_params.Set("button", static_cast<int>(key_index));
|
|
||||||
keyboard_moddifier_params.Set("pad", 1);
|
|
||||||
keyboard_device = Common::Input::CreateInputDevice(keyboard_moddifier_params);
|
|
||||||
key_index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::size_t index = 0; index < mouse_button_devices.size(); ++index) {
|
|
||||||
if (!mouse_button_devices[index]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
mouse_button_devices[index]->SetCallback({
|
|
||||||
.on_change =
|
|
||||||
[this, index](const Common::Input::CallbackStatus& callback) {
|
|
||||||
SetMouseButton(callback, index);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::size_t index = 0; index < mouse_wheel_devices.size(); ++index) {
|
|
||||||
if (!mouse_wheel_devices[index]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
mouse_wheel_devices[index]->SetCallback({
|
|
||||||
.on_change =
|
|
||||||
[this, index](const Common::Input::CallbackStatus& callback) {
|
|
||||||
SetMouseWheel(callback, index);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mouse_stick_device) {
|
|
||||||
mouse_stick_device->SetCallback({
|
|
||||||
.on_change =
|
|
||||||
[this](const Common::Input::CallbackStatus& callback) {
|
|
||||||
SetMousePosition(callback);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::size_t index = 0; index < keyboard_devices.size(); ++index) {
|
|
||||||
if (!keyboard_devices[index]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
keyboard_devices[index]->SetCallback({
|
|
||||||
.on_change =
|
|
||||||
[this, index](const Common::Input::CallbackStatus& callback) {
|
|
||||||
SetKeyboardButton(callback, index);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::size_t index = 0; index < keyboard_modifier_devices.size(); ++index) {
|
|
||||||
if (!keyboard_modifier_devices[index]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
keyboard_modifier_devices[index]->SetCallback({
|
|
||||||
.on_change =
|
|
||||||
[this, index](const Common::Input::CallbackStatus& callback) {
|
|
||||||
SetKeyboardModifier(callback, index);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmulatedDevices::UnloadInput() {
|
|
||||||
for (auto& button : mouse_button_devices) {
|
|
||||||
button.reset();
|
|
||||||
}
|
|
||||||
for (auto& analog : mouse_wheel_devices) {
|
|
||||||
analog.reset();
|
|
||||||
}
|
|
||||||
mouse_stick_device.reset();
|
|
||||||
for (auto& button : keyboard_devices) {
|
|
||||||
button.reset();
|
|
||||||
}
|
|
||||||
for (auto& button : keyboard_modifier_devices) {
|
|
||||||
button.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmulatedDevices::EnableConfiguration() {
|
|
||||||
is_configuring = true;
|
|
||||||
SaveCurrentConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmulatedDevices::DisableConfiguration() {
|
|
||||||
is_configuring = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EmulatedDevices::IsConfiguring() const {
|
|
||||||
return is_configuring;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmulatedDevices::SaveCurrentConfig() {
|
|
||||||
if (!is_configuring) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmulatedDevices::RestoreConfig() {
|
|
||||||
if (!is_configuring) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ReloadFromSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmulatedDevices::SetKeyboardButton(const Common::Input::CallbackStatus& callback,
|
|
||||||
std::size_t index) {
|
|
||||||
if (index >= device_status.keyboard_values.size()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::unique_lock lock{mutex};
|
|
||||||
bool value_changed = false;
|
|
||||||
const auto new_status = TransformToButton(callback);
|
|
||||||
auto& current_status = device_status.keyboard_values[index];
|
|
||||||
current_status.toggle = new_status.toggle;
|
|
||||||
|
|
||||||
// Update button status with current status
|
|
||||||
if (!current_status.toggle) {
|
|
||||||
current_status.locked = false;
|
|
||||||
if (current_status.value != new_status.value) {
|
|
||||||
current_status.value = new_status.value;
|
|
||||||
value_changed = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Toggle button and lock status
|
|
||||||
if (new_status.value && !current_status.locked) {
|
|
||||||
current_status.locked = true;
|
|
||||||
current_status.value = !current_status.value;
|
|
||||||
value_changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unlock button, ready for next press
|
|
||||||
if (!new_status.value && current_status.locked) {
|
|
||||||
current_status.locked = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!value_changed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_configuring) {
|
|
||||||
lock.unlock();
|
|
||||||
TriggerOnChange(DeviceTriggerType::Keyboard);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Index should be converted from NativeKeyboard to KeyboardKeyIndex
|
|
||||||
UpdateKey(index, current_status.value);
|
|
||||||
|
|
||||||
lock.unlock();
|
|
||||||
TriggerOnChange(DeviceTriggerType::Keyboard);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmulatedDevices::UpdateKey(std::size_t key_index, bool status) {
|
|
||||||
constexpr std::size_t KEYS_PER_BYTE = 8;
|
|
||||||
auto& entry = device_status.keyboard_state.key[key_index / KEYS_PER_BYTE];
|
|
||||||
const u8 mask = static_cast<u8>(1 << (key_index % KEYS_PER_BYTE));
|
|
||||||
if (status) {
|
|
||||||
entry = entry | mask;
|
|
||||||
} else {
|
|
||||||
entry = static_cast<u8>(entry & ~mask);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmulatedDevices::SetKeyboardModifier(const Common::Input::CallbackStatus& callback,
|
|
||||||
std::size_t index) {
|
|
||||||
if (index >= device_status.keyboard_moddifier_values.size()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::unique_lock lock{mutex};
|
|
||||||
bool value_changed = false;
|
|
||||||
const auto new_status = TransformToButton(callback);
|
|
||||||
auto& current_status = device_status.keyboard_moddifier_values[index];
|
|
||||||
current_status.toggle = new_status.toggle;
|
|
||||||
|
|
||||||
// Update button status with current
|
|
||||||
if (!current_status.toggle) {
|
|
||||||
current_status.locked = false;
|
|
||||||
if (current_status.value != new_status.value) {
|
|
||||||
current_status.value = new_status.value;
|
|
||||||
value_changed = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Toggle button and lock status
|
|
||||||
if (new_status.value && !current_status.locked) {
|
|
||||||
current_status.locked = true;
|
|
||||||
current_status.value = !current_status.value;
|
|
||||||
value_changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unlock button ready for next press
|
|
||||||
if (!new_status.value && current_status.locked) {
|
|
||||||
current_status.locked = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!value_changed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_configuring) {
|
|
||||||
lock.unlock();
|
|
||||||
TriggerOnChange(DeviceTriggerType::KeyboardModdifier);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (index) {
|
|
||||||
case Settings::NativeKeyboard::LeftControl:
|
|
||||||
case Settings::NativeKeyboard::RightControl:
|
|
||||||
device_status.keyboard_moddifier_state.control.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeKeyboard::LeftShift:
|
|
||||||
case Settings::NativeKeyboard::RightShift:
|
|
||||||
device_status.keyboard_moddifier_state.shift.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeKeyboard::LeftAlt:
|
|
||||||
device_status.keyboard_moddifier_state.left_alt.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeKeyboard::RightAlt:
|
|
||||||
device_status.keyboard_moddifier_state.right_alt.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeKeyboard::CapsLock:
|
|
||||||
device_status.keyboard_moddifier_state.caps_lock.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeKeyboard::ScrollLock:
|
|
||||||
device_status.keyboard_moddifier_state.scroll_lock.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeKeyboard::NumLock:
|
|
||||||
device_status.keyboard_moddifier_state.num_lock.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock.unlock();
|
|
||||||
TriggerOnChange(DeviceTriggerType::KeyboardModdifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmulatedDevices::SetMouseButton(const Common::Input::CallbackStatus& callback,
|
|
||||||
std::size_t index) {
|
|
||||||
if (index >= device_status.mouse_button_values.size()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::unique_lock lock{mutex};
|
|
||||||
bool value_changed = false;
|
|
||||||
const auto new_status = TransformToButton(callback);
|
|
||||||
auto& current_status = device_status.mouse_button_values[index];
|
|
||||||
current_status.toggle = new_status.toggle;
|
|
||||||
|
|
||||||
// Update button status with current
|
|
||||||
if (!current_status.toggle) {
|
|
||||||
current_status.locked = false;
|
|
||||||
if (current_status.value != new_status.value) {
|
|
||||||
current_status.value = new_status.value;
|
|
||||||
value_changed = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Toggle button and lock status
|
|
||||||
if (new_status.value && !current_status.locked) {
|
|
||||||
current_status.locked = true;
|
|
||||||
current_status.value = !current_status.value;
|
|
||||||
value_changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unlock button ready for next press
|
|
||||||
if (!new_status.value && current_status.locked) {
|
|
||||||
current_status.locked = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!value_changed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_configuring) {
|
|
||||||
lock.unlock();
|
|
||||||
TriggerOnChange(DeviceTriggerType::Mouse);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (index) {
|
|
||||||
case Settings::NativeMouseButton::Left:
|
|
||||||
device_status.mouse_button_state.left.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeMouseButton::Right:
|
|
||||||
device_status.mouse_button_state.right.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeMouseButton::Middle:
|
|
||||||
device_status.mouse_button_state.middle.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeMouseButton::Forward:
|
|
||||||
device_status.mouse_button_state.forward.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeMouseButton::Back:
|
|
||||||
device_status.mouse_button_state.back.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock.unlock();
|
|
||||||
TriggerOnChange(DeviceTriggerType::Mouse);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmulatedDevices::SetMouseWheel(const Common::Input::CallbackStatus& callback,
|
|
||||||
std::size_t index) {
|
|
||||||
if (index >= device_status.mouse_wheel_values.size()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::unique_lock lock{mutex};
|
|
||||||
const auto analog_value = TransformToAnalog(callback);
|
|
||||||
|
|
||||||
device_status.mouse_wheel_values[index] = analog_value;
|
|
||||||
|
|
||||||
if (is_configuring) {
|
|
||||||
device_status.mouse_wheel_state = {};
|
|
||||||
lock.unlock();
|
|
||||||
TriggerOnChange(DeviceTriggerType::Mouse);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (index) {
|
|
||||||
case Settings::NativeMouseWheel::X:
|
|
||||||
device_status.mouse_wheel_state.x = static_cast<s32>(analog_value.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeMouseWheel::Y:
|
|
||||||
device_status.mouse_wheel_state.y = static_cast<s32>(analog_value.value);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock.unlock();
|
|
||||||
TriggerOnChange(DeviceTriggerType::Mouse);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmulatedDevices::SetMousePosition(const Common::Input::CallbackStatus& callback) {
|
|
||||||
std::unique_lock lock{mutex};
|
|
||||||
const auto touch_value = TransformToTouch(callback);
|
|
||||||
|
|
||||||
device_status.mouse_stick_value = touch_value;
|
|
||||||
|
|
||||||
if (is_configuring) {
|
|
||||||
device_status.mouse_position_state = {};
|
|
||||||
lock.unlock();
|
|
||||||
TriggerOnChange(DeviceTriggerType::Mouse);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
device_status.mouse_position_state.x = touch_value.x.value;
|
|
||||||
device_status.mouse_position_state.y = touch_value.y.value;
|
|
||||||
|
|
||||||
lock.unlock();
|
|
||||||
TriggerOnChange(DeviceTriggerType::Mouse);
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyboardValues EmulatedDevices::GetKeyboardValues() const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
return device_status.keyboard_values;
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyboardModifierValues EmulatedDevices::GetKeyboardModdifierValues() const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
return device_status.keyboard_moddifier_values;
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseButtonValues EmulatedDevices::GetMouseButtonsValues() const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
return device_status.mouse_button_values;
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyboardKey EmulatedDevices::GetKeyboard() const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
return device_status.keyboard_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyboardModifier EmulatedDevices::GetKeyboardModifier() const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
return device_status.keyboard_moddifier_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseButton EmulatedDevices::GetMouseButtons() const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
return device_status.mouse_button_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
MousePosition EmulatedDevices::GetMousePosition() const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
return device_status.mouse_position_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
AnalogStickState EmulatedDevices::GetMouseWheel() const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
return device_status.mouse_wheel_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) {
|
|
||||||
std::scoped_lock lock{callback_mutex};
|
|
||||||
for (const auto& poller_pair : callback_list) {
|
|
||||||
const InterfaceUpdateCallback& poller = poller_pair.second;
|
|
||||||
if (poller.on_change) {
|
|
||||||
poller.on_change(type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int EmulatedDevices::SetCallback(InterfaceUpdateCallback update_callback) {
|
|
||||||
std::scoped_lock lock{callback_mutex};
|
|
||||||
callback_list.insert_or_assign(last_callback_key, std::move(update_callback));
|
|
||||||
return last_callback_key++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmulatedDevices::DeleteCallback(int key) {
|
|
||||||
std::scoped_lock lock{callback_mutex};
|
|
||||||
const auto& iterator = callback_list.find(key);
|
|
||||||
if (iterator == callback_list.end()) {
|
|
||||||
LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
callback_list.erase(iterator);
|
|
||||||
}
|
|
||||||
} // namespace Core::HID
|
|
|
@ -1,212 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <functional>
|
|
||||||
#include <memory>
|
|
||||||
#include <mutex>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "common/input.h"
|
|
||||||
#include "common/param_package.h"
|
|
||||||
#include "common/settings.h"
|
|
||||||
#include "core/hid/hid_types.h"
|
|
||||||
|
|
||||||
namespace Core::HID {
|
|
||||||
using KeyboardDevices = std::array<std::unique_ptr<Common::Input::InputDevice>,
|
|
||||||
Settings::NativeKeyboard::NumKeyboardKeys>;
|
|
||||||
using KeyboardModifierDevices = std::array<std::unique_ptr<Common::Input::InputDevice>,
|
|
||||||
Settings::NativeKeyboard::NumKeyboardMods>;
|
|
||||||
using MouseButtonDevices = std::array<std::unique_ptr<Common::Input::InputDevice>,
|
|
||||||
Settings::NativeMouseButton::NumMouseButtons>;
|
|
||||||
using MouseWheelDevices = std::array<std::unique_ptr<Common::Input::InputDevice>,
|
|
||||||
Settings::NativeMouseWheel::NumMouseWheels>;
|
|
||||||
using MouseStickDevice = std::unique_ptr<Common::Input::InputDevice>;
|
|
||||||
|
|
||||||
using MouseButtonParams =
|
|
||||||
std::array<Common::ParamPackage, Settings::NativeMouseButton::NumMouseButtons>;
|
|
||||||
|
|
||||||
using KeyboardValues =
|
|
||||||
std::array<Common::Input::ButtonStatus, Settings::NativeKeyboard::NumKeyboardKeys>;
|
|
||||||
using KeyboardModifierValues =
|
|
||||||
std::array<Common::Input::ButtonStatus, Settings::NativeKeyboard::NumKeyboardMods>;
|
|
||||||
using MouseButtonValues =
|
|
||||||
std::array<Common::Input::ButtonStatus, Settings::NativeMouseButton::NumMouseButtons>;
|
|
||||||
using MouseWheelValues =
|
|
||||||
std::array<Common::Input::AnalogStatus, Settings::NativeMouseWheel::NumMouseWheels>;
|
|
||||||
using MouseStickValue = Common::Input::TouchStatus;
|
|
||||||
|
|
||||||
struct MousePosition {
|
|
||||||
f32 x;
|
|
||||||
f32 y;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DeviceStatus {
|
|
||||||
// Data from input_common
|
|
||||||
KeyboardValues keyboard_values{};
|
|
||||||
KeyboardModifierValues keyboard_moddifier_values{};
|
|
||||||
MouseButtonValues mouse_button_values{};
|
|
||||||
MouseWheelValues mouse_wheel_values{};
|
|
||||||
MouseStickValue mouse_stick_value{};
|
|
||||||
|
|
||||||
// Data for HID services
|
|
||||||
KeyboardKey keyboard_state{};
|
|
||||||
KeyboardModifier keyboard_moddifier_state{};
|
|
||||||
MouseButton mouse_button_state{};
|
|
||||||
MousePosition mouse_position_state{};
|
|
||||||
AnalogStickState mouse_wheel_state{};
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class DeviceTriggerType {
|
|
||||||
Keyboard,
|
|
||||||
KeyboardModdifier,
|
|
||||||
Mouse,
|
|
||||||
RingController,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct InterfaceUpdateCallback {
|
|
||||||
std::function<void(DeviceTriggerType)> on_change;
|
|
||||||
};
|
|
||||||
|
|
||||||
class EmulatedDevices {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Contains all input data related to external devices that aren't necessarily a controller
|
|
||||||
* This includes devices such as the keyboard or mouse
|
|
||||||
*/
|
|
||||||
explicit EmulatedDevices();
|
|
||||||
~EmulatedDevices();
|
|
||||||
|
|
||||||
YUZU_NON_COPYABLE(EmulatedDevices);
|
|
||||||
YUZU_NON_MOVEABLE(EmulatedDevices);
|
|
||||||
|
|
||||||
/// Removes all callbacks created from input devices
|
|
||||||
void UnloadInput();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the emulated devices into configuring mode
|
|
||||||
* This prevents the modification of the HID state of the emulated devices by input commands
|
|
||||||
*/
|
|
||||||
void EnableConfiguration();
|
|
||||||
|
|
||||||
/// Returns the emulated devices into normal mode, allowing the modification of the HID state
|
|
||||||
void DisableConfiguration();
|
|
||||||
|
|
||||||
/// Returns true if the emulated device is in configuring mode
|
|
||||||
bool IsConfiguring() const;
|
|
||||||
|
|
||||||
/// Reload all input devices
|
|
||||||
void ReloadInput();
|
|
||||||
|
|
||||||
/// Overrides current mapped devices with the stored configuration and reloads all input devices
|
|
||||||
void ReloadFromSettings();
|
|
||||||
|
|
||||||
/// Saves the current mapped configuration
|
|
||||||
void SaveCurrentConfig();
|
|
||||||
|
|
||||||
/// Reverts any mapped changes made that weren't saved
|
|
||||||
void RestoreConfig();
|
|
||||||
|
|
||||||
/// Returns the latest status of button input from the keyboard with parameters
|
|
||||||
KeyboardValues GetKeyboardValues() const;
|
|
||||||
|
|
||||||
/// Returns the latest status of button input from the keyboard modifiers with parameters
|
|
||||||
KeyboardModifierValues GetKeyboardModdifierValues() const;
|
|
||||||
|
|
||||||
/// Returns the latest status of button input from the mouse with parameters
|
|
||||||
MouseButtonValues GetMouseButtonsValues() const;
|
|
||||||
|
|
||||||
/// Returns the latest status of button input from the keyboard
|
|
||||||
KeyboardKey GetKeyboard() const;
|
|
||||||
|
|
||||||
/// Returns the latest status of button input from the keyboard modifiers
|
|
||||||
KeyboardModifier GetKeyboardModifier() const;
|
|
||||||
|
|
||||||
/// Returns the latest status of button input from the mouse
|
|
||||||
MouseButton GetMouseButtons() const;
|
|
||||||
|
|
||||||
/// Returns the latest mouse coordinates
|
|
||||||
MousePosition GetMousePosition() const;
|
|
||||||
|
|
||||||
/// Returns the latest mouse wheel change
|
|
||||||
AnalogStickState GetMouseWheel() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a callback to the list of events
|
|
||||||
* @param update_callback InterfaceUpdateCallback that will be triggered
|
|
||||||
* @return an unique key corresponding to the callback index in the list
|
|
||||||
*/
|
|
||||||
int SetCallback(InterfaceUpdateCallback update_callback);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes a callback from the list stopping any future events to this object
|
|
||||||
* @param key Key corresponding to the callback index in the list
|
|
||||||
*/
|
|
||||||
void DeleteCallback(int key);
|
|
||||||
|
|
||||||
private:
|
|
||||||
/// Helps assigning a value to keyboard_state
|
|
||||||
void UpdateKey(std::size_t key_index, bool status);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the touch status of the keyboard device
|
|
||||||
* @param callback A CallbackStatus containing the key status
|
|
||||||
* @param index key ID to be updated
|
|
||||||
*/
|
|
||||||
void SetKeyboardButton(const Common::Input::CallbackStatus& callback, std::size_t index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the keyboard status of the keyboard device
|
|
||||||
* @param callback A CallbackStatus containing the modifier key status
|
|
||||||
* @param index modifier key ID to be updated
|
|
||||||
*/
|
|
||||||
void SetKeyboardModifier(const Common::Input::CallbackStatus& callback, std::size_t index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the mouse button status of the mouse device
|
|
||||||
* @param callback A CallbackStatus containing the button status
|
|
||||||
* @param index Button ID to be updated
|
|
||||||
*/
|
|
||||||
void SetMouseButton(const Common::Input::CallbackStatus& callback, std::size_t index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the mouse wheel status of the mouse device
|
|
||||||
* @param callback A CallbackStatus containing the wheel status
|
|
||||||
* @param index wheel ID to be updated
|
|
||||||
*/
|
|
||||||
void SetMouseWheel(const Common::Input::CallbackStatus& callback, std::size_t index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the mouse position status of the mouse device
|
|
||||||
* @param callback A CallbackStatus containing the position status
|
|
||||||
*/
|
|
||||||
void SetMousePosition(const Common::Input::CallbackStatus& callback);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Triggers a callback that something has changed on the device status
|
|
||||||
* @param type Input type of the event to trigger
|
|
||||||
*/
|
|
||||||
void TriggerOnChange(DeviceTriggerType type);
|
|
||||||
|
|
||||||
bool is_configuring{false};
|
|
||||||
|
|
||||||
KeyboardDevices keyboard_devices;
|
|
||||||
KeyboardModifierDevices keyboard_modifier_devices;
|
|
||||||
MouseButtonDevices mouse_button_devices;
|
|
||||||
MouseWheelDevices mouse_wheel_devices;
|
|
||||||
MouseStickDevice mouse_stick_device;
|
|
||||||
|
|
||||||
mutable std::mutex mutex;
|
|
||||||
mutable std::mutex callback_mutex;
|
|
||||||
std::unordered_map<int, InterfaceUpdateCallback> callback_list;
|
|
||||||
int last_callback_key = 0;
|
|
||||||
|
|
||||||
// Stores the current status of all external device input
|
|
||||||
DeviceStatus device_status;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Core::HID
|
|
|
@ -2,220 +2,12 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "core/hid/emulated_console.h"
|
|
||||||
#include "core/hid/emulated_controller.h"
|
|
||||||
#include "core/hid/emulated_devices.h"
|
|
||||||
#include "core/hid/hid_core.h"
|
#include "core/hid/hid_core.h"
|
||||||
|
|
||||||
namespace Core::HID {
|
namespace Core::HID {
|
||||||
|
|
||||||
HIDCore::HIDCore()
|
HIDCore::HIDCore() {}
|
||||||
: player_1{std::make_unique<EmulatedController>(NpadIdType::Player1)},
|
|
||||||
player_2{std::make_unique<EmulatedController>(NpadIdType::Player2)},
|
|
||||||
player_3{std::make_unique<EmulatedController>(NpadIdType::Player3)},
|
|
||||||
player_4{std::make_unique<EmulatedController>(NpadIdType::Player4)},
|
|
||||||
player_5{std::make_unique<EmulatedController>(NpadIdType::Player5)},
|
|
||||||
player_6{std::make_unique<EmulatedController>(NpadIdType::Player6)},
|
|
||||||
player_7{std::make_unique<EmulatedController>(NpadIdType::Player7)},
|
|
||||||
player_8{std::make_unique<EmulatedController>(NpadIdType::Player8)},
|
|
||||||
other{std::make_unique<EmulatedController>(NpadIdType::Other)},
|
|
||||||
handheld{std::make_unique<EmulatedController>(NpadIdType::Handheld)},
|
|
||||||
console{std::make_unique<EmulatedConsole>()}, devices{std::make_unique<EmulatedDevices>()} {}
|
|
||||||
|
|
||||||
HIDCore::~HIDCore() = default;
|
HIDCore::~HIDCore() = default;
|
||||||
|
|
||||||
EmulatedController* HIDCore::GetEmulatedController(NpadIdType npad_id_type) {
|
|
||||||
switch (npad_id_type) {
|
|
||||||
case NpadIdType::Player1:
|
|
||||||
return player_1.get();
|
|
||||||
case NpadIdType::Player2:
|
|
||||||
return player_2.get();
|
|
||||||
case NpadIdType::Player3:
|
|
||||||
return player_3.get();
|
|
||||||
case NpadIdType::Player4:
|
|
||||||
return player_4.get();
|
|
||||||
case NpadIdType::Player5:
|
|
||||||
return player_5.get();
|
|
||||||
case NpadIdType::Player6:
|
|
||||||
return player_6.get();
|
|
||||||
case NpadIdType::Player7:
|
|
||||||
return player_7.get();
|
|
||||||
case NpadIdType::Player8:
|
|
||||||
return player_8.get();
|
|
||||||
case NpadIdType::Other:
|
|
||||||
return other.get();
|
|
||||||
case NpadIdType::Handheld:
|
|
||||||
return handheld.get();
|
|
||||||
case NpadIdType::Invalid:
|
|
||||||
default:
|
|
||||||
ASSERT_MSG(false, "Invalid NpadIdType={}", npad_id_type);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const EmulatedController* HIDCore::GetEmulatedController(NpadIdType npad_id_type) const {
|
|
||||||
switch (npad_id_type) {
|
|
||||||
case NpadIdType::Player1:
|
|
||||||
return player_1.get();
|
|
||||||
case NpadIdType::Player2:
|
|
||||||
return player_2.get();
|
|
||||||
case NpadIdType::Player3:
|
|
||||||
return player_3.get();
|
|
||||||
case NpadIdType::Player4:
|
|
||||||
return player_4.get();
|
|
||||||
case NpadIdType::Player5:
|
|
||||||
return player_5.get();
|
|
||||||
case NpadIdType::Player6:
|
|
||||||
return player_6.get();
|
|
||||||
case NpadIdType::Player7:
|
|
||||||
return player_7.get();
|
|
||||||
case NpadIdType::Player8:
|
|
||||||
return player_8.get();
|
|
||||||
case NpadIdType::Other:
|
|
||||||
return other.get();
|
|
||||||
case NpadIdType::Handheld:
|
|
||||||
return handheld.get();
|
|
||||||
case NpadIdType::Invalid:
|
|
||||||
default:
|
|
||||||
ASSERT_MSG(false, "Invalid NpadIdType={}", npad_id_type);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EmulatedConsole* HIDCore::GetEmulatedConsole() {
|
|
||||||
return console.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
const EmulatedConsole* HIDCore::GetEmulatedConsole() const {
|
|
||||||
return console.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
EmulatedDevices* HIDCore::GetEmulatedDevices() {
|
|
||||||
return devices.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
const EmulatedDevices* HIDCore::GetEmulatedDevices() const {
|
|
||||||
return devices.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
EmulatedController* HIDCore::GetEmulatedControllerByIndex(std::size_t index) {
|
|
||||||
return GetEmulatedController(IndexToNpadIdType(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
const EmulatedController* HIDCore::GetEmulatedControllerByIndex(std::size_t index) const {
|
|
||||||
return GetEmulatedController(IndexToNpadIdType(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
void HIDCore::SetSupportedStyleTag(NpadStyleTag style_tag) {
|
|
||||||
supported_style_tag.raw = style_tag.raw;
|
|
||||||
player_1->SetSupportedNpadStyleTag(supported_style_tag);
|
|
||||||
player_2->SetSupportedNpadStyleTag(supported_style_tag);
|
|
||||||
player_3->SetSupportedNpadStyleTag(supported_style_tag);
|
|
||||||
player_4->SetSupportedNpadStyleTag(supported_style_tag);
|
|
||||||
player_5->SetSupportedNpadStyleTag(supported_style_tag);
|
|
||||||
player_6->SetSupportedNpadStyleTag(supported_style_tag);
|
|
||||||
player_7->SetSupportedNpadStyleTag(supported_style_tag);
|
|
||||||
player_8->SetSupportedNpadStyleTag(supported_style_tag);
|
|
||||||
other->SetSupportedNpadStyleTag(supported_style_tag);
|
|
||||||
handheld->SetSupportedNpadStyleTag(supported_style_tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
NpadStyleTag HIDCore::GetSupportedStyleTag() const {
|
|
||||||
return supported_style_tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
s8 HIDCore::GetPlayerCount() const {
|
|
||||||
s8 active_players = 0;
|
|
||||||
for (std::size_t player_index = 0; player_index < available_controllers - 2; ++player_index) {
|
|
||||||
const auto* const controller = GetEmulatedControllerByIndex(player_index);
|
|
||||||
if (controller->IsConnected()) {
|
|
||||||
active_players++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return active_players;
|
|
||||||
}
|
|
||||||
|
|
||||||
NpadIdType HIDCore::GetFirstNpadId() const {
|
|
||||||
for (std::size_t player_index = 0; player_index < available_controllers; ++player_index) {
|
|
||||||
const auto* const controller = GetEmulatedControllerByIndex(player_index);
|
|
||||||
if (controller->IsConnected()) {
|
|
||||||
return controller->GetNpadIdType();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NpadIdType::Player1;
|
|
||||||
}
|
|
||||||
|
|
||||||
NpadIdType HIDCore::GetFirstDisconnectedNpadId() const {
|
|
||||||
for (std::size_t player_index = 0; player_index < available_controllers; ++player_index) {
|
|
||||||
const auto* const controller = GetEmulatedControllerByIndex(player_index);
|
|
||||||
if (!controller->IsConnected()) {
|
|
||||||
return controller->GetNpadIdType();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NpadIdType::Player1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HIDCore::SetLastActiveController(NpadIdType npad_id) {
|
|
||||||
last_active_controller = npad_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
NpadIdType HIDCore::GetLastActiveController() const {
|
|
||||||
return last_active_controller;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HIDCore::EnableAllControllerConfiguration() {
|
|
||||||
player_1->EnableConfiguration();
|
|
||||||
player_2->EnableConfiguration();
|
|
||||||
player_3->EnableConfiguration();
|
|
||||||
player_4->EnableConfiguration();
|
|
||||||
player_5->EnableConfiguration();
|
|
||||||
player_6->EnableConfiguration();
|
|
||||||
player_7->EnableConfiguration();
|
|
||||||
player_8->EnableConfiguration();
|
|
||||||
other->EnableConfiguration();
|
|
||||||
handheld->EnableConfiguration();
|
|
||||||
}
|
|
||||||
|
|
||||||
void HIDCore::DisableAllControllerConfiguration() {
|
|
||||||
player_1->DisableConfiguration();
|
|
||||||
player_2->DisableConfiguration();
|
|
||||||
player_3->DisableConfiguration();
|
|
||||||
player_4->DisableConfiguration();
|
|
||||||
player_5->DisableConfiguration();
|
|
||||||
player_6->DisableConfiguration();
|
|
||||||
player_7->DisableConfiguration();
|
|
||||||
player_8->DisableConfiguration();
|
|
||||||
other->DisableConfiguration();
|
|
||||||
handheld->DisableConfiguration();
|
|
||||||
}
|
|
||||||
|
|
||||||
void HIDCore::ReloadInputDevices() {
|
|
||||||
player_1->ReloadFromSettings();
|
|
||||||
player_2->ReloadFromSettings();
|
|
||||||
player_3->ReloadFromSettings();
|
|
||||||
player_4->ReloadFromSettings();
|
|
||||||
player_5->ReloadFromSettings();
|
|
||||||
player_6->ReloadFromSettings();
|
|
||||||
player_7->ReloadFromSettings();
|
|
||||||
player_8->ReloadFromSettings();
|
|
||||||
other->ReloadFromSettings();
|
|
||||||
handheld->ReloadFromSettings();
|
|
||||||
console->ReloadFromSettings();
|
|
||||||
devices->ReloadFromSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
void HIDCore::UnloadInputDevices() {
|
|
||||||
player_1->UnloadInput();
|
|
||||||
player_2->UnloadInput();
|
|
||||||
player_3->UnloadInput();
|
|
||||||
player_4->UnloadInput();
|
|
||||||
player_5->UnloadInput();
|
|
||||||
player_6->UnloadInput();
|
|
||||||
player_7->UnloadInput();
|
|
||||||
player_8->UnloadInput();
|
|
||||||
other->UnloadInput();
|
|
||||||
handheld->UnloadInput();
|
|
||||||
console->UnloadInput();
|
|
||||||
devices->UnloadInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Core::HID
|
} // namespace Core::HID
|
||||||
|
|
|
@ -6,13 +6,6 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "core/hid/hid_types.h"
|
|
||||||
|
|
||||||
namespace Core::HID {
|
|
||||||
class EmulatedConsole;
|
|
||||||
class EmulatedController;
|
|
||||||
class EmulatedDevices;
|
|
||||||
} // namespace Core::HID
|
|
||||||
|
|
||||||
namespace Core::HID {
|
namespace Core::HID {
|
||||||
|
|
||||||
|
@ -23,67 +16,6 @@ public:
|
||||||
|
|
||||||
YUZU_NON_COPYABLE(HIDCore);
|
YUZU_NON_COPYABLE(HIDCore);
|
||||||
YUZU_NON_MOVEABLE(HIDCore);
|
YUZU_NON_MOVEABLE(HIDCore);
|
||||||
|
|
||||||
EmulatedController* GetEmulatedController(NpadIdType npad_id_type);
|
|
||||||
const EmulatedController* GetEmulatedController(NpadIdType npad_id_type) const;
|
|
||||||
|
|
||||||
EmulatedController* GetEmulatedControllerByIndex(std::size_t index);
|
|
||||||
const EmulatedController* GetEmulatedControllerByIndex(std::size_t index) const;
|
|
||||||
|
|
||||||
EmulatedConsole* GetEmulatedConsole();
|
|
||||||
const EmulatedConsole* GetEmulatedConsole() const;
|
|
||||||
|
|
||||||
EmulatedDevices* GetEmulatedDevices();
|
|
||||||
const EmulatedDevices* GetEmulatedDevices() const;
|
|
||||||
|
|
||||||
void SetSupportedStyleTag(NpadStyleTag style_tag);
|
|
||||||
NpadStyleTag GetSupportedStyleTag() const;
|
|
||||||
|
|
||||||
/// Counts the connected players from P1-P8
|
|
||||||
s8 GetPlayerCount() const;
|
|
||||||
|
|
||||||
/// Returns the first connected npad id
|
|
||||||
NpadIdType GetFirstNpadId() const;
|
|
||||||
|
|
||||||
/// Returns the first disconnected npad id
|
|
||||||
NpadIdType GetFirstDisconnectedNpadId() const;
|
|
||||||
|
|
||||||
/// Sets the npad id of the last active controller
|
|
||||||
void SetLastActiveController(NpadIdType npad_id);
|
|
||||||
|
|
||||||
/// Returns the npad id of the last controller that pushed a button
|
|
||||||
NpadIdType GetLastActiveController() const;
|
|
||||||
|
|
||||||
/// Sets all emulated controllers into configuring mode.
|
|
||||||
void EnableAllControllerConfiguration();
|
|
||||||
|
|
||||||
/// Sets all emulated controllers into normal mode.
|
|
||||||
void DisableAllControllerConfiguration();
|
|
||||||
|
|
||||||
/// Reloads all input devices from settings
|
|
||||||
void ReloadInputDevices();
|
|
||||||
|
|
||||||
/// Removes all callbacks from input common
|
|
||||||
void UnloadInputDevices();
|
|
||||||
|
|
||||||
/// Number of emulated controllers
|
|
||||||
static constexpr std::size_t available_controllers{10};
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::unique_ptr<EmulatedController> player_1;
|
|
||||||
std::unique_ptr<EmulatedController> player_2;
|
|
||||||
std::unique_ptr<EmulatedController> player_3;
|
|
||||||
std::unique_ptr<EmulatedController> player_4;
|
|
||||||
std::unique_ptr<EmulatedController> player_5;
|
|
||||||
std::unique_ptr<EmulatedController> player_6;
|
|
||||||
std::unique_ptr<EmulatedController> player_7;
|
|
||||||
std::unique_ptr<EmulatedController> player_8;
|
|
||||||
std::unique_ptr<EmulatedController> other;
|
|
||||||
std::unique_ptr<EmulatedController> handheld;
|
|
||||||
std::unique_ptr<EmulatedConsole> console;
|
|
||||||
std::unique_ptr<EmulatedDevices> devices;
|
|
||||||
NpadStyleTag supported_style_tag{NpadStyleSet::All};
|
|
||||||
NpadIdType last_active_controller{NpadIdType::Handheld};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Core::HID
|
} // namespace Core::HID
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include "core/core.h"
|
|
||||||
#include "core/hid/hid_types.h"
|
|
||||||
#include "core/hid/input_interpreter.h"
|
|
||||||
#include "core/hle/service/hid/controllers/npad.h"
|
|
||||||
#include "core/hle/service/hid/hid.h"
|
|
||||||
#include "core/hle/service/sm/sm.h"
|
|
||||||
|
|
||||||
InputInterpreter::InputInterpreter(Core::System& system)
|
|
||||||
: npad{system.ServiceManager()
|
|
||||||
.GetService<Service::HID::Hid>("hid")
|
|
||||||
->GetAppletResource()
|
|
||||||
->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad)} {
|
|
||||||
ResetButtonStates();
|
|
||||||
}
|
|
||||||
|
|
||||||
InputInterpreter::~InputInterpreter() = default;
|
|
||||||
|
|
||||||
void InputInterpreter::PollInput() {
|
|
||||||
const auto button_state = npad.GetAndResetPressState();
|
|
||||||
|
|
||||||
previous_index = current_index;
|
|
||||||
current_index = (current_index + 1) % button_states.size();
|
|
||||||
|
|
||||||
button_states[current_index] = button_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InputInterpreter::ResetButtonStates() {
|
|
||||||
previous_index = 0;
|
|
||||||
current_index = 0;
|
|
||||||
|
|
||||||
button_states[0] = Core::HID::NpadButton::All;
|
|
||||||
|
|
||||||
for (std::size_t i = 1; i < button_states.size(); ++i) {
|
|
||||||
button_states[i] = Core::HID::NpadButton::None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InputInterpreter::IsButtonPressed(Core::HID::NpadButton button) const {
|
|
||||||
return True(button_states[current_index] & button);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InputInterpreter::IsButtonPressedOnce(Core::HID::NpadButton button) const {
|
|
||||||
const bool current_press = True(button_states[current_index] & button);
|
|
||||||
const bool previous_press = True(button_states[previous_index] & button);
|
|
||||||
|
|
||||||
return current_press && !previous_press;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InputInterpreter::IsButtonHeld(Core::HID::NpadButton button) const {
|
|
||||||
Core::HID::NpadButton held_buttons{button_states[0]};
|
|
||||||
|
|
||||||
for (std::size_t i = 1; i < button_states.size(); ++i) {
|
|
||||||
held_buttons &= button_states[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return True(held_buttons & button);
|
|
||||||
}
|
|
|
@ -1,111 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
namespace Core {
|
|
||||||
class System;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Core::HID {
|
|
||||||
enum class NpadButton : u64;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Service::HID {
|
|
||||||
class Controller_NPad;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The InputInterpreter class interfaces with HID to retrieve button press states.
|
|
||||||
* Input is intended to be polled every 50ms so that a button is considered to be
|
|
||||||
* held down after 400ms has elapsed since the initial button press and subsequent
|
|
||||||
* repeated presses occur every 50ms.
|
|
||||||
*/
|
|
||||||
class InputInterpreter {
|
|
||||||
public:
|
|
||||||
explicit InputInterpreter(Core::System& system);
|
|
||||||
virtual ~InputInterpreter();
|
|
||||||
|
|
||||||
/// Gets a button state from HID and inserts it into the array of button states.
|
|
||||||
void PollInput();
|
|
||||||
|
|
||||||
/// Resets all the button states to their defaults.
|
|
||||||
void ResetButtonStates();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether the button is pressed.
|
|
||||||
*
|
|
||||||
* @param button The button to check.
|
|
||||||
*
|
|
||||||
* @returns True when the button is pressed.
|
|
||||||
*/
|
|
||||||
[[nodiscard]] bool IsButtonPressed(Core::HID::NpadButton button) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether any of the buttons in the parameter list is pressed.
|
|
||||||
*
|
|
||||||
* @tparam HIDButton The buttons to check.
|
|
||||||
*
|
|
||||||
* @returns True when at least one of the buttons is pressed.
|
|
||||||
*/
|
|
||||||
template <Core::HID::NpadButton... T>
|
|
||||||
[[nodiscard]] bool IsAnyButtonPressed() {
|
|
||||||
return (IsButtonPressed(T) || ...);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The specified button is considered to be pressed once
|
|
||||||
* if it is currently pressed and not pressed previously.
|
|
||||||
*
|
|
||||||
* @param button The button to check.
|
|
||||||
*
|
|
||||||
* @returns True when the button is pressed once.
|
|
||||||
*/
|
|
||||||
[[nodiscard]] bool IsButtonPressedOnce(Core::HID::NpadButton button) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether any of the buttons in the parameter list is pressed once.
|
|
||||||
*
|
|
||||||
* @tparam T The buttons to check.
|
|
||||||
*
|
|
||||||
* @returns True when at least one of the buttons is pressed once.
|
|
||||||
*/
|
|
||||||
template <Core::HID::NpadButton... T>
|
|
||||||
[[nodiscard]] bool IsAnyButtonPressedOnce() const {
|
|
||||||
return (IsButtonPressedOnce(T) || ...);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The specified button is considered to be held down if it is pressed in all 9 button states.
|
|
||||||
*
|
|
||||||
* @param button The button to check.
|
|
||||||
*
|
|
||||||
* @returns True when the button is held down.
|
|
||||||
*/
|
|
||||||
[[nodiscard]] bool IsButtonHeld(Core::HID::NpadButton button) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether any of the buttons in the parameter list is held down.
|
|
||||||
*
|
|
||||||
* @tparam T The buttons to check.
|
|
||||||
*
|
|
||||||
* @returns True when at least one of the buttons is held down.
|
|
||||||
*/
|
|
||||||
template <Core::HID::NpadButton... T>
|
|
||||||
[[nodiscard]] bool IsAnyButtonHeld() const {
|
|
||||||
return (IsButtonHeld(T) || ...);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Service::HID::Controller_NPad& npad;
|
|
||||||
|
|
||||||
/// Stores 9 consecutive button states polled from HID.
|
|
||||||
std::array<Core::HID::NpadButton, 9> button_states{};
|
|
||||||
|
|
||||||
std::size_t previous_index{};
|
|
||||||
std::size_t current_index{};
|
|
||||||
};
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "core/hle/service/am/applets/applet_cabinet.h"
|
#include "core/hle/service/am/applets/applet_cabinet.h"
|
||||||
#include "core/hle/service/mii/mii_manager.h"
|
#include "core/hle/service/mii/mii_manager.h"
|
||||||
#include "core/hle/service/nfc/common/device.h"
|
#include "core/hle/service/nfc/common/device.h"
|
||||||
|
#include "core/hle/service/hid/hid_types.h"
|
||||||
|
|
||||||
namespace Service::AM::Applets {
|
namespace Service::AM::Applets {
|
||||||
|
|
||||||
|
@ -73,7 +74,7 @@ void Cabinet::Execute() {
|
||||||
// TODO: listen on all controllers
|
// TODO: listen on all controllers
|
||||||
if (nfp_device == nullptr) {
|
if (nfp_device == nullptr) {
|
||||||
nfp_device = std::make_shared<Service::NFC::NfcDevice>(
|
nfp_device = std::make_shared<Service::NFC::NfcDevice>(
|
||||||
system.HIDCore().GetFirstNpadId(), system, service_context, availability_change_event);
|
Service::HID::NpadIdType::Player1, system, service_context, availability_change_event);
|
||||||
nfp_device->Initialize();
|
nfp_device->Initialize();
|
||||||
nfp_device->StartDetection(Service::NFC::NfcProtocol::All);
|
nfp_device->StartDetection(Service::NFC::NfcProtocol::All);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,13 +9,11 @@
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/frontend/applets/controller.h"
|
#include "core/frontend/applets/controller.h"
|
||||||
#include "core/hid/emulated_controller.h"
|
|
||||||
#include "core/hid/hid_core.h"
|
#include "core/hid/hid_core.h"
|
||||||
#include "core/hid/hid_types.h"
|
#include "core/hle/service/hid/hid_types.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
#include "core/hle/service/am/am.h"
|
#include "core/hle/service/am/am.h"
|
||||||
#include "core/hle/service/am/applets/applet_controller.h"
|
#include "core/hle/service/am/applets/applet_controller.h"
|
||||||
#include "core/hle/service/hid/controllers/npad.h"
|
|
||||||
|
|
||||||
namespace Service::AM::Applets {
|
namespace Service::AM::Applets {
|
||||||
|
|
||||||
|
@ -26,7 +24,7 @@ namespace Service::AM::Applets {
|
||||||
static Core::Frontend::ControllerParameters ConvertToFrontendParameters(
|
static Core::Frontend::ControllerParameters ConvertToFrontendParameters(
|
||||||
ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header, bool enable_text,
|
ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header, bool enable_text,
|
||||||
std::vector<IdentificationColor> identification_colors, std::vector<ExplainText> text) {
|
std::vector<IdentificationColor> identification_colors, std::vector<ExplainText> text) {
|
||||||
Core::HID::NpadStyleTag npad_style_set;
|
Service::HID::NpadStyleTag npad_style_set;
|
||||||
npad_style_set.raw = private_arg.style_set;
|
npad_style_set.raw = private_arg.style_set;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -247,9 +245,9 @@ void Controller::ConfigurationComplete(bool is_success) {
|
||||||
|
|
||||||
// If enable_single_mode is enabled, player_count is 1 regardless of any other parameters.
|
// If enable_single_mode is enabled, player_count is 1 regardless of any other parameters.
|
||||||
// Otherwise, only count connected players from P1-P8.
|
// Otherwise, only count connected players from P1-P8.
|
||||||
result_info.player_count = is_single_mode ? 1 : system.HIDCore().GetPlayerCount();
|
result_info.player_count = is_single_mode ? 1 : 0;
|
||||||
|
|
||||||
result_info.selected_id = static_cast<u32>(system.HIDCore().GetFirstNpadId());
|
result_info.selected_id = static_cast<u32>(Service::HID::NpadIdType::Player1);
|
||||||
|
|
||||||
result_info.result =
|
result_info.result =
|
||||||
is_success ? ControllerSupportResult::Success : ControllerSupportResult::Cancel;
|
is_success ? ControllerSupportResult::Success : ControllerSupportResult::Cancel;
|
||||||
|
|
|
@ -15,7 +15,7 @@ namespace Core {
|
||||||
class System;
|
class System;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Core::HID {
|
namespace Service::HID {
|
||||||
enum class NpadStyleSet : u32;
|
enum class NpadStyleSet : u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ struct ControllerSupportArgPrivate {
|
||||||
bool flag_1{};
|
bool flag_1{};
|
||||||
ControllerSupportMode mode{};
|
ControllerSupportMode mode{};
|
||||||
ControllerSupportCaller caller{};
|
ControllerSupportCaller caller{};
|
||||||
Core::HID::NpadStyleSet style_set{};
|
Service::HID::NpadStyleSet style_set{};
|
||||||
u32 joy_hold_type{};
|
u32 joy_hold_type{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(ControllerSupportArgPrivate) == 0x14,
|
static_assert(sizeof(ControllerSupportArgPrivate) == 0x14,
|
||||||
|
|
|
@ -67,6 +67,34 @@ enum class AppletId : u32 {
|
||||||
LoginShare = 0x18,
|
LoginShare = 0x18,
|
||||||
WebAuth = 0x19,
|
WebAuth = 0x19,
|
||||||
MyPage = 0x1A,
|
MyPage = 0x1A,
|
||||||
|
Gift = 0x1B,
|
||||||
|
UserMigration = 0x1C,
|
||||||
|
PreomiaSys = 0x1D,
|
||||||
|
Story = 0x1E,
|
||||||
|
PreomiaUsr = 0x1F,
|
||||||
|
PreomiaUsrDummy = 0x20,
|
||||||
|
Sample = 0x21,
|
||||||
|
PromoteQualification = 0x22,
|
||||||
|
Unknown35 = 0x35,
|
||||||
|
Unknown36 = 0x36,
|
||||||
|
Unknown37 = 0x37,
|
||||||
|
Unknown38 = 0x38,
|
||||||
|
|
||||||
|
DevlopmentTool = 0x3E8,
|
||||||
|
CombinationLA = 0x3F1,
|
||||||
|
AeSystemApplet = 0x3F2,
|
||||||
|
AeOverlayApplet = 0x3F3,
|
||||||
|
AeStarter = 0x3F4,
|
||||||
|
AeLibraryAppletAlone = 0x3F5,
|
||||||
|
AeLibraryApplet1 = 0x3F6,
|
||||||
|
AeLibraryApplet2 = 0x3F7,
|
||||||
|
AeLibraryApplet3 = 0x3F8,
|
||||||
|
AeLibraryApplet4 = 0x3F9,
|
||||||
|
AppletISA = 0x3FA,
|
||||||
|
AppletIOA = 0x3FB,
|
||||||
|
AppletISTA = 0x3FC,
|
||||||
|
AppletILA1 = 0x3FD,
|
||||||
|
AppletILA2 = 0x3FE,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class LibraryAppletMode : u32 {
|
enum class LibraryAppletMode : u32 {
|
||||||
|
|
|
@ -1,74 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include "core/core.h"
|
|
||||||
#include "core/core_timing.h"
|
|
||||||
#include "core/hid/emulated_console.h"
|
|
||||||
#include "core/hid/hid_core.h"
|
|
||||||
#include "core/hle/service/hid/controllers/console_sixaxis.h"
|
|
||||||
#include "core/memory.h"
|
|
||||||
|
|
||||||
namespace Service::HID {
|
|
||||||
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200;
|
|
||||||
|
|
||||||
Controller_ConsoleSixAxis::Controller_ConsoleSixAxis(Core::System& system_, u8* raw_shared_memory_)
|
|
||||||
: ControllerBase{system_.HIDCore()}, system{system_} {
|
|
||||||
console = hid_core.GetEmulatedConsole();
|
|
||||||
static_assert(SHARED_MEMORY_OFFSET + sizeof(ConsoleSharedMemory) < shared_memory_size,
|
|
||||||
"ConsoleSharedMemory is bigger than the shared memory");
|
|
||||||
shared_memory = std::construct_at(
|
|
||||||
reinterpret_cast<ConsoleSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
|
|
||||||
}
|
|
||||||
|
|
||||||
Controller_ConsoleSixAxis::~Controller_ConsoleSixAxis() = default;
|
|
||||||
|
|
||||||
void Controller_ConsoleSixAxis::OnInit() {}
|
|
||||||
|
|
||||||
void Controller_ConsoleSixAxis::OnRelease() {}
|
|
||||||
|
|
||||||
void Controller_ConsoleSixAxis::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,
|
|
||||||
};
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
// Update seven six axis transfer memory
|
|
||||||
seven_sixaxis_lifo.WriteNextEntry(next_seven_sixaxis_state);
|
|
||||||
system.ApplicationMemory().WriteBlock(transfer_memory, &seven_sixaxis_lifo,
|
|
||||||
sizeof(seven_sixaxis_lifo));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Controller_ConsoleSixAxis::SetTransferMemoryAddress(Common::ProcessAddress t_mem) {
|
|
||||||
transfer_memory = t_mem;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Controller_ConsoleSixAxis::ResetTimestamp() {
|
|
||||||
last_saved_timestamp = last_global_timestamp;
|
|
||||||
}
|
|
||||||
} // namespace Service::HID
|
|
|
@ -1,78 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
#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 Controller_ConsoleSixAxis final : public ControllerBase {
|
|
||||||
public:
|
|
||||||
explicit Controller_ConsoleSixAxis(Core::System& system_, u8* raw_shared_memory_);
|
|
||||||
~Controller_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;
|
|
||||||
|
|
||||||
// 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");
|
|
||||||
|
|
||||||
// This is nn::hid::detail::ConsoleSixAxisSensorSharedMemoryFormat
|
|
||||||
struct ConsoleSharedMemory {
|
|
||||||
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(ConsoleSharedMemory) == 0x20, "ConsoleSharedMemory is an invalid size");
|
|
||||||
|
|
||||||
Lifo<SevenSixAxisState, 0x21> seven_sixaxis_lifo{};
|
|
||||||
static_assert(sizeof(seven_sixaxis_lifo) == 0xA70, "SevenSixAxisState is an invalid size");
|
|
||||||
|
|
||||||
SevenSixAxisState next_seven_sixaxis_state{};
|
|
||||||
Common::ProcessAddress transfer_memory{};
|
|
||||||
ConsoleSharedMemory* shared_memory = nullptr;
|
|
||||||
Core::HID::EmulatedConsole* console = nullptr;
|
|
||||||
|
|
||||||
u64 last_saved_timestamp{};
|
|
||||||
u64 last_global_timestamp{};
|
|
||||||
|
|
||||||
Core::System& system;
|
|
||||||
};
|
|
||||||
} // namespace Service::HID
|
|
|
@ -1,29 +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;
|
|
||||||
|
|
||||||
void ControllerBase::ActivateController() {
|
|
||||||
if (is_activated) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
is_activated = true;
|
|
||||||
OnInit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ControllerBase::DeactivateController() {
|
|
||||||
if (is_activated) {
|
|
||||||
OnRelease();
|
|
||||||
}
|
|
||||||
is_activated = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ControllerBase::IsControllerActivated() const {
|
|
||||||
return is_activated;
|
|
||||||
}
|
|
||||||
} // namespace Service::HID
|
|
|
@ -1,48 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
namespace Core::Timing {
|
|
||||||
class CoreTiming;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Core::HID {
|
|
||||||
class HIDCore;
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {}
|
|
||||||
|
|
||||||
void ActivateController();
|
|
||||||
|
|
||||||
void DeactivateController();
|
|
||||||
|
|
||||||
bool IsControllerActivated() const;
|
|
||||||
|
|
||||||
static const std::size_t hid_entry_count = 17;
|
|
||||||
static const std::size_t shared_memory_size = 0x40000;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool is_activated{false};
|
|
||||||
|
|
||||||
Core::HID::HIDCore& hid_core;
|
|
||||||
};
|
|
||||||
} // namespace Service::HID
|
|
|
@ -1,55 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#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/debug_pad.h"
|
|
||||||
|
|
||||||
namespace Service::HID {
|
|
||||||
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x00000;
|
|
||||||
|
|
||||||
Controller_DebugPad::Controller_DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
|
|
||||||
: ControllerBase{hid_core_} {
|
|
||||||
static_assert(SHARED_MEMORY_OFFSET + sizeof(DebugPadSharedMemory) < shared_memory_size,
|
|
||||||
"DebugPadSharedMemory is bigger than the shared memory");
|
|
||||||
shared_memory = std::construct_at(
|
|
||||||
reinterpret_cast<DebugPadSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
|
|
||||||
controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other);
|
|
||||||
}
|
|
||||||
|
|
||||||
Controller_DebugPad::~Controller_DebugPad() = default;
|
|
||||||
|
|
||||||
void Controller_DebugPad::OnInit() {}
|
|
||||||
|
|
||||||
void Controller_DebugPad::OnRelease() {}
|
|
||||||
|
|
||||||
void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
|
||||||
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,64 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "common/bit_field.h"
|
|
||||||
#include "common/common_types.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 {
|
|
||||||
class Controller_DebugPad final : public ControllerBase {
|
|
||||||
public:
|
|
||||||
explicit Controller_DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
|
|
||||||
~Controller_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:
|
|
||||||
// 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");
|
|
||||||
|
|
||||||
struct DebugPadSharedMemory {
|
|
||||||
// This is nn::hid::detail::DebugPadLifo
|
|
||||||
Lifo<DebugPadState, hid_entry_count> debug_pad_lifo{};
|
|
||||||
static_assert(sizeof(debug_pad_lifo) == 0x2C8, "debug_pad_lifo is an invalid size");
|
|
||||||
INSERT_PADDING_WORDS(0x4E);
|
|
||||||
};
|
|
||||||
static_assert(sizeof(DebugPadSharedMemory) == 0x400, "DebugPadSharedMemory is an invalid size");
|
|
||||||
|
|
||||||
DebugPadState next_state{};
|
|
||||||
DebugPadSharedMemory* shared_memory = nullptr;
|
|
||||||
Core::HID::EmulatedController* controller = nullptr;
|
|
||||||
};
|
|
||||||
} // namespace Service::HID
|
|
|
@ -1,359 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include "common/logging/log.h"
|
|
||||||
#include "common/math_util.h"
|
|
||||||
#include "common/settings.h"
|
|
||||||
#include "core/core_timing.h"
|
|
||||||
#include "core/frontend/emu_window.h"
|
|
||||||
#include "core/hid/hid_core.h"
|
|
||||||
#include "core/hle/service/hid/controllers/gesture.h"
|
|
||||||
|
|
||||||
namespace Service::HID {
|
|
||||||
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00;
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
Controller_Gesture::Controller_Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
|
|
||||||
: ControllerBase(hid_core_) {
|
|
||||||
static_assert(SHARED_MEMORY_OFFSET + sizeof(GestureSharedMemory) < shared_memory_size,
|
|
||||||
"GestureSharedMemory is bigger than the shared memory");
|
|
||||||
shared_memory = std::construct_at(
|
|
||||||
reinterpret_cast<GestureSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
|
|
||||||
console = hid_core.GetEmulatedConsole();
|
|
||||||
}
|
|
||||||
Controller_Gesture::~Controller_Gesture() = default;
|
|
||||||
|
|
||||||
void Controller_Gesture::OnInit() {
|
|
||||||
shared_memory->gesture_lifo.buffer_count = 0;
|
|
||||||
shared_memory->gesture_lifo.buffer_tail = 0;
|
|
||||||
force_update = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Controller_Gesture::OnRelease() {}
|
|
||||||
|
|
||||||
void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
|
||||||
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 Controller_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 Controller_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 Controller_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 Controller_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 Controller_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 Controller_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 Controller_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 Controller_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 Controller_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 Controller_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 Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() const {
|
|
||||||
return shared_memory->gesture_lifo.ReadCurrentEntry().state;
|
|
||||||
}
|
|
||||||
|
|
||||||
Controller_Gesture::GestureProperties Controller_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,156 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include "common/bit_field.h"
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "common/point.h"
|
|
||||||
#include "core/hid/emulated_console.h"
|
|
||||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
|
||||||
#include "core/hle/service/hid/ring_lifo.h"
|
|
||||||
|
|
||||||
namespace Service::HID {
|
|
||||||
class Controller_Gesture final : public ControllerBase {
|
|
||||||
public:
|
|
||||||
explicit Controller_Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
|
|
||||||
~Controller_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:
|
|
||||||
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{};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct GestureSharedMemory {
|
|
||||||
// This is nn::hid::detail::GestureLifo
|
|
||||||
Lifo<GestureState, hid_entry_count> gesture_lifo{};
|
|
||||||
static_assert(sizeof(gesture_lifo) == 0x708, "gesture_lifo is an invalid size");
|
|
||||||
INSERT_PADDING_WORDS(0x3E);
|
|
||||||
};
|
|
||||||
static_assert(sizeof(GestureSharedMemory) == 0x800, "GestureSharedMemory is an invalid size");
|
|
||||||
|
|
||||||
// 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{};
|
|
||||||
GestureSharedMemory* shared_memory = nullptr;
|
|
||||||
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,52 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#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/keyboard.h"
|
|
||||||
|
|
||||||
namespace Service::HID {
|
|
||||||
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800;
|
|
||||||
|
|
||||||
Controller_Keyboard::Controller_Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
|
|
||||||
: ControllerBase{hid_core_} {
|
|
||||||
static_assert(SHARED_MEMORY_OFFSET + sizeof(KeyboardSharedMemory) < shared_memory_size,
|
|
||||||
"KeyboardSharedMemory is bigger than the shared memory");
|
|
||||||
shared_memory = std::construct_at(
|
|
||||||
reinterpret_cast<KeyboardSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
|
|
||||||
emulated_devices = hid_core.GetEmulatedDevices();
|
|
||||||
}
|
|
||||||
|
|
||||||
Controller_Keyboard::~Controller_Keyboard() = default;
|
|
||||||
|
|
||||||
void Controller_Keyboard::OnInit() {}
|
|
||||||
|
|
||||||
void Controller_Keyboard::OnRelease() {}
|
|
||||||
|
|
||||||
void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
|
||||||
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,53 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
|
||||||
#include "core/hle/service/hid/ring_lifo.h"
|
|
||||||
|
|
||||||
namespace Core::HID {
|
|
||||||
class EmulatedDevices;
|
|
||||||
struct KeyboardModifier;
|
|
||||||
struct KeyboardKey;
|
|
||||||
} // namespace Core::HID
|
|
||||||
|
|
||||||
namespace Service::HID {
|
|
||||||
class Controller_Keyboard final : public ControllerBase {
|
|
||||||
public:
|
|
||||||
explicit Controller_Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
|
|
||||||
~Controller_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:
|
|
||||||
// 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");
|
|
||||||
|
|
||||||
struct KeyboardSharedMemory {
|
|
||||||
// This is nn::hid::detail::KeyboardLifo
|
|
||||||
Lifo<KeyboardState, hid_entry_count> keyboard_lifo{};
|
|
||||||
static_assert(sizeof(keyboard_lifo) == 0x3D8, "keyboard_lifo is an invalid size");
|
|
||||||
INSERT_PADDING_WORDS(0xA);
|
|
||||||
};
|
|
||||||
static_assert(sizeof(KeyboardSharedMemory) == 0x400, "KeyboardSharedMemory is an invalid size");
|
|
||||||
|
|
||||||
KeyboardState next_state{};
|
|
||||||
KeyboardSharedMemory* shared_memory = nullptr;
|
|
||||||
Core::HID::EmulatedDevices* emulated_devices = nullptr;
|
|
||||||
};
|
|
||||||
} // namespace Service::HID
|
|
|
@ -1,60 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#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/mouse.h"
|
|
||||||
|
|
||||||
namespace Service::HID {
|
|
||||||
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400;
|
|
||||||
|
|
||||||
Controller_Mouse::Controller_Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
|
|
||||||
: ControllerBase{hid_core_} {
|
|
||||||
static_assert(SHARED_MEMORY_OFFSET + sizeof(MouseSharedMemory) < shared_memory_size,
|
|
||||||
"MouseSharedMemory is bigger than the shared memory");
|
|
||||||
shared_memory = std::construct_at(
|
|
||||||
reinterpret_cast<MouseSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
|
|
||||||
emulated_devices = hid_core.GetEmulatedDevices();
|
|
||||||
}
|
|
||||||
|
|
||||||
Controller_Mouse::~Controller_Mouse() = default;
|
|
||||||
|
|
||||||
void Controller_Mouse::OnInit() {}
|
|
||||||
void Controller_Mouse::OnRelease() {}
|
|
||||||
|
|
||||||
void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
|
||||||
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,45 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
|
||||||
#include "core/hle/service/hid/ring_lifo.h"
|
|
||||||
|
|
||||||
namespace Core::HID {
|
|
||||||
class EmulatedDevices;
|
|
||||||
struct MouseState;
|
|
||||||
struct AnalogStickState;
|
|
||||||
} // namespace Core::HID
|
|
||||||
|
|
||||||
namespace Service::HID {
|
|
||||||
class Controller_Mouse final : public ControllerBase {
|
|
||||||
public:
|
|
||||||
explicit Controller_Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
|
|
||||||
~Controller_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:
|
|
||||||
struct MouseSharedMemory {
|
|
||||||
// This is nn::hid::detail::MouseLifo
|
|
||||||
Lifo<Core::HID::MouseState, hid_entry_count> mouse_lifo{};
|
|
||||||
static_assert(sizeof(mouse_lifo) == 0x350, "mouse_lifo is an invalid size");
|
|
||||||
INSERT_PADDING_WORDS(0x2C);
|
|
||||||
};
|
|
||||||
static_assert(sizeof(MouseSharedMemory) == 0x400, "MouseSharedMemory is an invalid size");
|
|
||||||
|
|
||||||
Core::HID::MouseState next_state{};
|
|
||||||
Core::HID::AnalogStickState last_mouse_wheel_state{};
|
|
||||||
MouseSharedMemory* shared_memory = nullptr;
|
|
||||||
Core::HID::EmulatedDevices* emulated_devices = nullptr;
|
|
||||||
};
|
|
||||||
} // namespace Service::HID
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,555 +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/bit_field.h"
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "common/vector_math.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;
|
|
||||||
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 Controller_NPad final : public ControllerBase {
|
|
||||||
public:
|
|
||||||
explicit Controller_NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
|
|
||||||
KernelHelpers::ServiceContext& service_context_);
|
|
||||||
~Controller_NPad() 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;
|
|
||||||
|
|
||||||
// When the controller is requesting a motion update for the shared memory
|
|
||||||
void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) override;
|
|
||||||
|
|
||||||
// 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::NpadCommunicationMode
|
|
||||||
enum class NpadCommunicationMode : u64 {
|
|
||||||
Mode_5ms = 0,
|
|
||||||
Mode_10ms = 1,
|
|
||||||
Mode_15ms = 2,
|
|
||||||
Default = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set);
|
|
||||||
Core::HID::NpadStyleTag GetSupportedStyleSet() const;
|
|
||||||
|
|
||||||
Result SetSupportedNpadIdTypes(std::span<const u8> data);
|
|
||||||
void GetSupportedNpadIdTypes(u32* data, std::size_t max_length);
|
|
||||||
std::size_t GetSupportedNpadIdTypesSize() const;
|
|
||||||
|
|
||||||
void SetHoldType(NpadJoyHoldType joy_hold_type);
|
|
||||||
NpadJoyHoldType GetHoldType() const;
|
|
||||||
|
|
||||||
void SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode);
|
|
||||||
NpadHandheldActivationMode GetNpadHandheldActivationMode() const;
|
|
||||||
|
|
||||||
void SetNpadCommunicationMode(NpadCommunicationMode communication_mode_);
|
|
||||||
NpadCommunicationMode GetNpadCommunicationMode() const;
|
|
||||||
|
|
||||||
bool SetNpadMode(Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType npad_id,
|
|
||||||
NpadJoyDeviceType npad_device_type, NpadJoyAssignmentMode assignment_mode);
|
|
||||||
|
|
||||||
bool VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index,
|
|
||||||
const Core::HID::VibrationValue& vibration_value);
|
|
||||||
|
|
||||||
void VibrateController(const Core::HID::VibrationDeviceHandle& vibration_device_handle,
|
|
||||||
const Core::HID::VibrationValue& vibration_value);
|
|
||||||
|
|
||||||
void VibrateControllers(
|
|
||||||
std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles,
|
|
||||||
std::span<const Core::HID::VibrationValue> vibration_values);
|
|
||||||
|
|
||||||
Core::HID::VibrationValue GetLastVibration(
|
|
||||||
const Core::HID::VibrationDeviceHandle& vibration_device_handle) const;
|
|
||||||
|
|
||||||
void InitializeVibrationDevice(const Core::HID::VibrationDeviceHandle& vibration_device_handle);
|
|
||||||
|
|
||||||
void InitializeVibrationDeviceAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index);
|
|
||||||
|
|
||||||
void SetPermitVibrationSession(bool permit_vibration_session);
|
|
||||||
|
|
||||||
bool IsVibrationDeviceMounted(
|
|
||||||
const Core::HID::VibrationDeviceHandle& vibration_device_handle) const;
|
|
||||||
|
|
||||||
Kernel::KReadableEvent& GetStyleSetChangedEvent(Core::HID::NpadIdType npad_id);
|
|
||||||
void SignalStyleSetChangedEvent(Core::HID::NpadIdType npad_id) const;
|
|
||||||
|
|
||||||
// Adds a new controller at an index.
|
|
||||||
void AddNewControllerAt(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id);
|
|
||||||
// Adds a new controller at an index with connection status.
|
|
||||||
void UpdateControllerAt(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id,
|
|
||||||
bool connected);
|
|
||||||
|
|
||||||
Result DisconnectNpad(Core::HID::NpadIdType npad_id);
|
|
||||||
|
|
||||||
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 IsFirmwareUpdateAvailableForSixAxisSensor(
|
|
||||||
const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_firmware_available) 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 ResetIsSixAxisSensorDeviceNewlyAssigned(
|
|
||||||
const Core::HID::SixAxisSensorHandle& sixaxis_handle);
|
|
||||||
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;
|
|
||||||
Result GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const;
|
|
||||||
Result IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id,
|
|
||||||
bool& is_enabled) const;
|
|
||||||
Result SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled,
|
|
||||||
Core::HID::NpadIdType npad_id);
|
|
||||||
void SetAnalogStickUseCenterClamp(bool use_center_clamp);
|
|
||||||
void ClearAllConnectedControllers();
|
|
||||||
void DisconnectAllConnectedControllers();
|
|
||||||
void ConnectAllDisconnectedControllers();
|
|
||||||
void ClearAllControllers();
|
|
||||||
|
|
||||||
Result MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1,
|
|
||||||
Core::HID::NpadIdType npad_id_2);
|
|
||||||
void StartLRAssignmentMode();
|
|
||||||
void StopLRAssignmentMode();
|
|
||||||
Result SwapNpadAssignment(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();
|
|
||||||
|
|
||||||
void ApplyNpadSystemCommonPolicy();
|
|
||||||
|
|
||||||
static bool IsNpadIdValid(Core::HID::NpadIdType npad_id);
|
|
||||||
static Result IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle);
|
|
||||||
static Result VerifyValidSixAxisSensorHandle(
|
|
||||||
const Core::HID::SixAxisSensorHandle& device_handle);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static constexpr std::size_t NPAD_COUNT = 10;
|
|
||||||
|
|
||||||
// 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::SixAxisSensorAttribute
|
|
||||||
struct SixAxisSensorAttribute {
|
|
||||||
union {
|
|
||||||
u32 raw{};
|
|
||||||
BitField<0, 1, u32> is_connected;
|
|
||||||
BitField<1, 1, u32> is_interpolated;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
static_assert(sizeof(SixAxisSensorAttribute) == 4, "SixAxisSensorAttribute is an invalid size");
|
|
||||||
|
|
||||||
// This is nn::hid::SixAxisSensorState
|
|
||||||
struct SixAxisSensorState {
|
|
||||||
s64 delta_time{};
|
|
||||||
s64 sampling_number{};
|
|
||||||
Common::Vec3f accel{};
|
|
||||||
Common::Vec3f gyro{};
|
|
||||||
Common::Vec3f rotation{};
|
|
||||||
std::array<Common::Vec3f, 3> orientation{};
|
|
||||||
SixAxisSensorAttribute attribute{};
|
|
||||||
INSERT_PADDING_BYTES(4); // Reserved
|
|
||||||
};
|
|
||||||
static_assert(sizeof(SixAxisSensorState) == 0x60, "SixAxisSensorState 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::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,
|
|
||||||
};
|
|
||||||
|
|
||||||
// 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,
|
|
||||||
};
|
|
||||||
|
|
||||||
// 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, hid_entry_count> fullkey_lifo{};
|
|
||||||
Lifo<NPadGenericState, hid_entry_count> handheld_lifo{};
|
|
||||||
Lifo<NPadGenericState, hid_entry_count> joy_dual_lifo{};
|
|
||||||
Lifo<NPadGenericState, hid_entry_count> joy_left_lifo{};
|
|
||||||
Lifo<NPadGenericState, hid_entry_count> joy_right_lifo{};
|
|
||||||
Lifo<NPadGenericState, hid_entry_count> palma_lifo{};
|
|
||||||
Lifo<NPadGenericState, hid_entry_count> system_ext_lifo{};
|
|
||||||
Lifo<SixAxisSensorState, hid_entry_count> sixaxis_fullkey_lifo{};
|
|
||||||
Lifo<SixAxisSensorState, hid_entry_count> sixaxis_handheld_lifo{};
|
|
||||||
Lifo<SixAxisSensorState, hid_entry_count> sixaxis_dual_left_lifo{};
|
|
||||||
Lifo<SixAxisSensorState, hid_entry_count> sixaxis_dual_right_lifo{};
|
|
||||||
Lifo<SixAxisSensorState, hid_entry_count> sixaxis_left_lifo{};
|
|
||||||
Lifo<SixAxisSensorState, hid_entry_count> 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, hid_entry_count> gc_trigger_lifo{};
|
|
||||||
NpadLarkType lark_type_l_and_main{};
|
|
||||||
NpadLarkType lark_type_r{};
|
|
||||||
NpadLuciaType lucia_type{};
|
|
||||||
NpadLagonType lagon_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;
|
|
||||||
INSERT_PADDING_BYTES(0xc06); // Unknown
|
|
||||||
};
|
|
||||||
static_assert(sizeof(NpadInternalState) == 0x5000, "NpadInternalState is an invalid size");
|
|
||||||
|
|
||||||
struct VibrationData {
|
|
||||||
bool device_mounted{};
|
|
||||||
Core::HID::VibrationValue latest_vibration_value{};
|
|
||||||
std::chrono::steady_clock::time_point last_vibration_timepoint{};
|
|
||||||
};
|
|
||||||
|
|
||||||
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 {
|
|
||||||
Kernel::KEvent* styleset_changed_event{};
|
|
||||||
NpadInternalState* shared_memory = nullptr;
|
|
||||||
Core::HID::EmulatedController* device = nullptr;
|
|
||||||
|
|
||||||
std::array<VibrationData, 2> vibration{};
|
|
||||||
bool unintended_home_button_input_protection{};
|
|
||||||
bool is_connected{};
|
|
||||||
|
|
||||||
// Dual joycons can have only one side connected
|
|
||||||
bool is_dual_left_connected{true};
|
|
||||||
bool is_dual_right_connected{true};
|
|
||||||
|
|
||||||
// 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
|
|
||||||
NPadGenericState npad_pad_state{};
|
|
||||||
NPadGenericState npad_libnx_state{};
|
|
||||||
NpadGcTriggerState npad_trigger_state{};
|
|
||||||
SixAxisSensorState sixaxis_fullkey_state{};
|
|
||||||
SixAxisSensorState sixaxis_handheld_state{};
|
|
||||||
SixAxisSensorState sixaxis_dual_left_state{};
|
|
||||||
SixAxisSensorState sixaxis_dual_right_state{};
|
|
||||||
SixAxisSensorState sixaxis_left_lifo_state{};
|
|
||||||
SixAxisSensorState sixaxis_right_lifo_state{};
|
|
||||||
int callback_key{};
|
|
||||||
};
|
|
||||||
|
|
||||||
void ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t controller_idx);
|
|
||||||
void InitNewlyAddedController(Core::HID::NpadIdType npad_id);
|
|
||||||
bool IsControllerSupported(Core::HID::NpadStyleIndex controller) const;
|
|
||||||
void RequestPadStateUpdate(Core::HID::NpadIdType npad_id);
|
|
||||||
void WriteEmptyEntry(NpadInternalState* npad);
|
|
||||||
|
|
||||||
NpadControllerData& GetControllerFromHandle(
|
|
||||||
const Core::HID::SixAxisSensorHandle& device_handle);
|
|
||||||
const NpadControllerData& GetControllerFromHandle(
|
|
||||||
const Core::HID::SixAxisSensorHandle& device_handle) const;
|
|
||||||
NpadControllerData& GetControllerFromHandle(
|
|
||||||
const Core::HID::VibrationDeviceHandle& device_handle);
|
|
||||||
const NpadControllerData& GetControllerFromHandle(
|
|
||||||
const Core::HID::VibrationDeviceHandle& device_handle) const;
|
|
||||||
NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id);
|
|
||||||
const NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) const;
|
|
||||||
|
|
||||||
Core::HID::SixAxisSensorProperties& GetSixaxisProperties(
|
|
||||||
const Core::HID::SixAxisSensorHandle& device_handle);
|
|
||||||
const Core::HID::SixAxisSensorProperties& GetSixaxisProperties(
|
|
||||||
const Core::HID::SixAxisSensorHandle& device_handle) const;
|
|
||||||
SixaxisParameters& GetSixaxisState(const Core::HID::SixAxisSensorHandle& device_handle);
|
|
||||||
const SixaxisParameters& GetSixaxisState(
|
|
||||||
const Core::HID::SixAxisSensorHandle& device_handle) const;
|
|
||||||
|
|
||||||
std::atomic<u64> press_state{};
|
|
||||||
|
|
||||||
std::array<NpadControllerData, NPAD_COUNT> controller_data{};
|
|
||||||
KernelHelpers::ServiceContext& service_context;
|
|
||||||
std::mutex mutex;
|
|
||||||
std::vector<Core::HID::NpadIdType> supported_npad_id_types{};
|
|
||||||
NpadJoyHoldType hold_type{NpadJoyHoldType::Vertical};
|
|
||||||
NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual};
|
|
||||||
NpadCommunicationMode communication_mode{NpadCommunicationMode::Default};
|
|
||||||
bool permit_vibration_session_enabled{false};
|
|
||||||
bool analog_stick_use_center_clamp{false};
|
|
||||||
bool is_in_lr_assignment_mode{false};
|
|
||||||
bool is_controller_initialized{false};
|
|
||||||
};
|
|
||||||
} // namespace Service::HID
|
|
|
@ -1,229 +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 {
|
|
||||||
|
|
||||||
Controller_Palma::Controller_Palma(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
Controller_Palma::~Controller_Palma() = default;
|
|
||||||
|
|
||||||
void Controller_Palma::OnInit() {}
|
|
||||||
|
|
||||||
void Controller_Palma::OnRelease() {}
|
|
||||||
|
|
||||||
void Controller_Palma::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
|
||||||
if (!IsControllerActivated()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Result Controller_Palma::GetPalmaConnectionHandle(Core::HID::NpadIdType npad_id,
|
|
||||||
PalmaConnectionHandle& handle) {
|
|
||||||
active_handle.npad_id = npad_id;
|
|
||||||
handle = active_handle;
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result Controller_Palma::InitializePalma(const PalmaConnectionHandle& handle) {
|
|
||||||
if (handle.npad_id != active_handle.npad_id) {
|
|
||||||
return InvalidPalmaHandle;
|
|
||||||
}
|
|
||||||
ActivateController();
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
Kernel::KReadableEvent& Controller_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 Controller_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 Controller_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 Controller_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 Controller_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 Controller_Palma::EnablePalmaStep(const PalmaConnectionHandle& handle, bool is_enabled) {
|
|
||||||
if (handle.npad_id != active_handle.npad_id) {
|
|
||||||
return InvalidPalmaHandle;
|
|
||||||
}
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result Controller_Palma::ResetPalmaStep(const PalmaConnectionHandle& handle) {
|
|
||||||
if (handle.npad_id != active_handle.npad_id) {
|
|
||||||
return InvalidPalmaHandle;
|
|
||||||
}
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Controller_Palma::ReadPalmaApplicationSection() {}
|
|
||||||
|
|
||||||
void Controller_Palma::WritePalmaApplicationSection() {}
|
|
||||||
|
|
||||||
Result Controller_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 Controller_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 Controller_Palma::WritePalmaActivityEntry() {}
|
|
||||||
|
|
||||||
Result Controller_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 Controller_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 Controller_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 Controller_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 Controller_Palma::SuspendPalmaFeature() {}
|
|
||||||
|
|
||||||
Result Controller_Palma::GetPalmaOperationResult(const PalmaConnectionHandle& handle) const {
|
|
||||||
if (handle.npad_id != active_handle.npad_id) {
|
|
||||||
return InvalidPalmaHandle;
|
|
||||||
}
|
|
||||||
return operation.result;
|
|
||||||
}
|
|
||||||
void Controller_Palma::ReadPalmaPlayLog() {}
|
|
||||||
|
|
||||||
void Controller_Palma::ResetPalmaPlayLog() {}
|
|
||||||
|
|
||||||
void Controller_Palma::SetIsPalmaAllConnectable(bool is_all_connectable) {
|
|
||||||
// If true controllers are able to be paired
|
|
||||||
is_connectable = is_all_connectable;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Controller_Palma::SetIsPalmaPairedConnectable() {}
|
|
||||||
|
|
||||||
Result Controller_Palma::PairPalma(const PalmaConnectionHandle& handle) {
|
|
||||||
if (handle.npad_id != active_handle.npad_id) {
|
|
||||||
return InvalidPalmaHandle;
|
|
||||||
}
|
|
||||||
// TODO: Do something
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Controller_Palma::SetPalmaBoostMode(bool boost_mode) {}
|
|
||||||
|
|
||||||
void Controller_Palma::CancelWritePalmaWaveEntry() {}
|
|
||||||
|
|
||||||
void Controller_Palma::EnablePalmaBoostMode() {}
|
|
||||||
|
|
||||||
void Controller_Palma::GetPalmaBluetoothAddress() {}
|
|
||||||
|
|
||||||
void Controller_Palma::SetDisallowedPalmaConnection() {}
|
|
||||||
|
|
||||||
} // namespace Service::HID
|
|
|
@ -1,163 +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 Controller_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 Controller_Palma(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
|
|
||||||
KernelHelpers::ServiceContext& service_context_);
|
|
||||||
~Controller_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,42 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "core/core_timing.h"
|
|
||||||
#include "core/hid/hid_core.h"
|
|
||||||
#include "core/hle/service/hid/controllers/stubbed.h"
|
|
||||||
|
|
||||||
namespace Service::HID {
|
|
||||||
|
|
||||||
Controller_Stubbed::Controller_Stubbed(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
|
|
||||||
: ControllerBase{hid_core_} {
|
|
||||||
raw_shared_memory = raw_shared_memory_;
|
|
||||||
}
|
|
||||||
|
|
||||||
Controller_Stubbed::~Controller_Stubbed() = default;
|
|
||||||
|
|
||||||
void Controller_Stubbed::OnInit() {}
|
|
||||||
|
|
||||||
void Controller_Stubbed::OnRelease() {}
|
|
||||||
|
|
||||||
void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
|
||||||
if (!smart_update) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CommonHeader header{};
|
|
||||||
header.timestamp = core_timing.GetGlobalTimeNs().count();
|
|
||||||
header.total_entry_count = 17;
|
|
||||||
header.entry_count = 0;
|
|
||||||
header.last_entry_index = 0;
|
|
||||||
|
|
||||||
std::memcpy(raw_shared_memory + common_offset, &header, sizeof(CommonHeader));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Controller_Stubbed::SetCommonHeaderOffset(std::size_t off) {
|
|
||||||
common_offset = off;
|
|
||||||
smart_update = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Service::HID
|
|
|
@ -1,39 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
|
||||||
|
|
||||||
namespace Service::HID {
|
|
||||||
class Controller_Stubbed final : public ControllerBase {
|
|
||||||
public:
|
|
||||||
explicit Controller_Stubbed(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
|
|
||||||
~Controller_Stubbed() 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 SetCommonHeaderOffset(std::size_t off);
|
|
||||||
|
|
||||||
private:
|
|
||||||
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");
|
|
||||||
|
|
||||||
u8* raw_shared_memory = nullptr;
|
|
||||||
bool smart_update{};
|
|
||||||
std::size_t common_offset{};
|
|
||||||
};
|
|
||||||
} // namespace Service::HID
|
|
|
@ -1,124 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstring>
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "common/settings.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/hid_core.h"
|
|
||||||
#include "core/hle/service/hid/controllers/touchscreen.h"
|
|
||||||
|
|
||||||
namespace Service::HID {
|
|
||||||
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400;
|
|
||||||
|
|
||||||
Controller_Touchscreen::Controller_Touchscreen(Core::HID::HIDCore& hid_core_,
|
|
||||||
u8* raw_shared_memory_)
|
|
||||||
: ControllerBase{hid_core_} {
|
|
||||||
static_assert(SHARED_MEMORY_OFFSET + sizeof(TouchSharedMemory) < shared_memory_size,
|
|
||||||
"TouchSharedMemory is bigger than the shared memory");
|
|
||||||
shared_memory = std::construct_at(
|
|
||||||
reinterpret_cast<TouchSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
|
|
||||||
console = hid_core.GetEmulatedConsole();
|
|
||||||
}
|
|
||||||
|
|
||||||
Controller_Touchscreen::~Controller_Touchscreen() = default;
|
|
||||||
|
|
||||||
void Controller_Touchscreen::OnInit() {}
|
|
||||||
|
|
||||||
void Controller_Touchscreen::OnRelease() {}
|
|
||||||
|
|
||||||
void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
|
||||||
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 * Layout::ScreenUndocked::Width),
|
|
||||||
.y = static_cast<u16>(active_y * Layout::ScreenUndocked::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);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Service::HID
|
|
|
@ -1,57 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "common/common_funcs.h"
|
|
||||||
#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 EmulatedConsole;
|
|
||||||
} // namespace Core::HID
|
|
||||||
|
|
||||||
namespace Service::HID {
|
|
||||||
class Controller_Touchscreen final : public ControllerBase {
|
|
||||||
public:
|
|
||||||
explicit Controller_Touchscreen(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
|
|
||||||
~Controller_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;
|
|
||||||
|
|
||||||
private:
|
|
||||||
static constexpr std::size_t MAX_FINGERS = 16;
|
|
||||||
|
|
||||||
// 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");
|
|
||||||
|
|
||||||
struct TouchSharedMemory {
|
|
||||||
// This is nn::hid::detail::TouchScreenLifo
|
|
||||||
Lifo<TouchScreenState, hid_entry_count> touch_screen_lifo{};
|
|
||||||
static_assert(sizeof(touch_screen_lifo) == 0x2C38, "touch_screen_lifo is an invalid size");
|
|
||||||
INSERT_PADDING_WORDS(0xF2);
|
|
||||||
};
|
|
||||||
static_assert(sizeof(TouchSharedMemory) == 0x3000, "TouchSharedMemory is an invalid size");
|
|
||||||
|
|
||||||
TouchScreenState next_state{};
|
|
||||||
TouchSharedMemory* shared_memory = nullptr;
|
|
||||||
Core::HID::EmulatedConsole* console = nullptr;
|
|
||||||
|
|
||||||
std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers{};
|
|
||||||
};
|
|
||||||
} // namespace Service::HID
|
|
|
@ -1,40 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "core/core_timing.h"
|
|
||||||
#include "core/hid/hid_core.h"
|
|
||||||
#include "core/hle/service/hid/controllers/xpad.h"
|
|
||||||
|
|
||||||
namespace Service::HID {
|
|
||||||
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00;
|
|
||||||
|
|
||||||
Controller_XPad::Controller_XPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
|
|
||||||
: ControllerBase{hid_core_} {
|
|
||||||
static_assert(SHARED_MEMORY_OFFSET + sizeof(XpadSharedMemory) < shared_memory_size,
|
|
||||||
"XpadSharedMemory is bigger than the shared memory");
|
|
||||||
shared_memory = std::construct_at(
|
|
||||||
reinterpret_cast<XpadSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
|
|
||||||
}
|
|
||||||
Controller_XPad::~Controller_XPad() = default;
|
|
||||||
|
|
||||||
void Controller_XPad::OnInit() {}
|
|
||||||
|
|
||||||
void Controller_XPad::OnRelease() {}
|
|
||||||
|
|
||||||
void Controller_XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
|
||||||
if (!IsControllerActivated()) {
|
|
||||||
shared_memory->basic_xpad_lifo.buffer_count = 0;
|
|
||||||
shared_memory->basic_xpad_lifo.buffer_tail = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& last_entry = shared_memory->basic_xpad_lifo.ReadCurrentEntry().state;
|
|
||||||
next_state.sampling_number = last_entry.sampling_number + 1;
|
|
||||||
// TODO(ogniK): Update xpad states
|
|
||||||
|
|
||||||
shared_memory->basic_xpad_lifo.WriteNextEntry(next_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Service::HID
|
|
|
@ -1,112 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "common/bit_field.h"
|
|
||||||
#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 Service::HID {
|
|
||||||
class Controller_XPad final : public ControllerBase {
|
|
||||||
public:
|
|
||||||
explicit Controller_XPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
|
|
||||||
~Controller_XPad() 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:
|
|
||||||
// This is nn::hid::BasicXpadAttributeSet
|
|
||||||
struct BasicXpadAttributeSet {
|
|
||||||
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(BasicXpadAttributeSet) == 4, "BasicXpadAttributeSet is an invalid size");
|
|
||||||
|
|
||||||
// This is nn::hid::BasicXpadButtonSet
|
|
||||||
struct BasicXpadButtonSet {
|
|
||||||
union {
|
|
||||||
u32 raw{};
|
|
||||||
// Button states
|
|
||||||
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_stick;
|
|
||||||
BitField<5, 1, u32> r_stick;
|
|
||||||
BitField<6, 1, u32> l;
|
|
||||||
BitField<7, 1, u32> r;
|
|
||||||
BitField<8, 1, u32> zl;
|
|
||||||
BitField<9, 1, u32> zr;
|
|
||||||
BitField<10, 1, u32> plus;
|
|
||||||
BitField<11, 1, u32> minus;
|
|
||||||
|
|
||||||
// D-Pad
|
|
||||||
BitField<12, 1, u32> d_left;
|
|
||||||
BitField<13, 1, u32> d_up;
|
|
||||||
BitField<14, 1, u32> d_right;
|
|
||||||
BitField<15, 1, u32> d_down;
|
|
||||||
|
|
||||||
// Left JoyStick
|
|
||||||
BitField<16, 1, u32> l_stick_left;
|
|
||||||
BitField<17, 1, u32> l_stick_up;
|
|
||||||
BitField<18, 1, u32> l_stick_right;
|
|
||||||
BitField<19, 1, u32> l_stick_down;
|
|
||||||
|
|
||||||
// Right JoyStick
|
|
||||||
BitField<20, 1, u32> r_stick_left;
|
|
||||||
BitField<21, 1, u32> r_stick_up;
|
|
||||||
BitField<22, 1, u32> r_stick_right;
|
|
||||||
BitField<23, 1, u32> r_stick_down;
|
|
||||||
|
|
||||||
// Not always active?
|
|
||||||
BitField<24, 1, u32> left_sl;
|
|
||||||
BitField<25, 1, u32> left_sr;
|
|
||||||
|
|
||||||
BitField<26, 1, u32> right_sl;
|
|
||||||
BitField<27, 1, u32> right_sr;
|
|
||||||
|
|
||||||
BitField<28, 1, u32> palma;
|
|
||||||
BitField<30, 1, u32> handheld_left_b;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
static_assert(sizeof(BasicXpadButtonSet) == 4, "BasicXpadButtonSet is an invalid size");
|
|
||||||
|
|
||||||
// This is nn::hid::detail::BasicXpadState
|
|
||||||
struct BasicXpadState {
|
|
||||||
s64 sampling_number{};
|
|
||||||
BasicXpadAttributeSet attributes{};
|
|
||||||
BasicXpadButtonSet pad_states{};
|
|
||||||
Core::HID::AnalogStickState l_stick{};
|
|
||||||
Core::HID::AnalogStickState r_stick{};
|
|
||||||
};
|
|
||||||
static_assert(sizeof(BasicXpadState) == 0x20, "BasicXpadState is an invalid size");
|
|
||||||
|
|
||||||
struct XpadSharedMemory {
|
|
||||||
// This is nn::hid::detail::BasicXpadLifo
|
|
||||||
Lifo<BasicXpadState, hid_entry_count> basic_xpad_lifo{};
|
|
||||||
static_assert(sizeof(basic_xpad_lifo) == 0x2C8, "basic_xpad_lifo is an invalid size");
|
|
||||||
INSERT_PADDING_WORDS(0x4E);
|
|
||||||
};
|
|
||||||
static_assert(sizeof(XpadSharedMemory) == 0x400, "XpadSharedMemory is an invalid size");
|
|
||||||
|
|
||||||
BasicXpadState next_state{};
|
|
||||||
XpadSharedMemory* shared_memory = nullptr;
|
|
||||||
};
|
|
||||||
} // namespace Service::HID
|
|
|
@ -1,31 +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 VibrationInvalidStyleIndex{ErrorModule::HID, 122};
|
|
||||||
constexpr Result VibrationInvalidNpadId{ErrorModule::HID, 123};
|
|
||||||
constexpr Result VibrationDeviceIndexOutOfRange{ErrorModule::HID, 124};
|
|
||||||
constexpr Result InvalidSixAxisFusionRange{ErrorModule::HID, 423};
|
|
||||||
constexpr Result NpadIsDualJoycon{ErrorModule::HID, 601};
|
|
||||||
constexpr Result NpadIsSameType{ErrorModule::HID, 602};
|
|
||||||
constexpr Result InvalidNpadId{ErrorModule::HID, 709};
|
|
||||||
constexpr Result NpadNotConnected{ErrorModule::HID, 710};
|
|
||||||
constexpr Result InvalidArraySize{ErrorModule::HID, 715};
|
|
||||||
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
|
|
File diff suppressed because it is too large
Load Diff
|
@ -3,220 +3,14 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
|
|
||||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
|
||||||
#include "core/hle/service/kernel_helpers.h"
|
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
namespace Core::Timing {
|
namespace Core {
|
||||||
struct EventType;
|
class System;
|
||||||
}
|
|
||||||
|
|
||||||
namespace Service::SM {
|
|
||||||
class ServiceManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Service::HID {
|
namespace Service::HID {
|
||||||
|
|
||||||
enum class HidController : std::size_t {
|
|
||||||
DebugPad,
|
|
||||||
Touchscreen,
|
|
||||||
Mouse,
|
|
||||||
Keyboard,
|
|
||||||
XPad,
|
|
||||||
HomeButton,
|
|
||||||
SleepButton,
|
|
||||||
CaptureButton,
|
|
||||||
InputDetector,
|
|
||||||
UniquePad,
|
|
||||||
NPad,
|
|
||||||
Gesture,
|
|
||||||
ConsoleSixAxisSensor,
|
|
||||||
DebugMouse,
|
|
||||||
Palma,
|
|
||||||
|
|
||||||
MaxControllers,
|
|
||||||
};
|
|
||||||
|
|
||||||
class IAppletResource final : public ServiceFramework<IAppletResource> {
|
|
||||||
public:
|
|
||||||
explicit IAppletResource(Core::System& system_,
|
|
||||||
KernelHelpers::ServiceContext& service_context_);
|
|
||||||
~IAppletResource() override;
|
|
||||||
|
|
||||||
void ActivateController(HidController controller);
|
|
||||||
void DeactivateController(HidController controller);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T& GetController(HidController controller) {
|
|
||||||
return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
const T& GetController(HidController controller) const {
|
|
||||||
return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
template <typename T>
|
|
||||||
void MakeController(HidController controller, u8* shared_memory) {
|
|
||||||
if constexpr (std::is_constructible_v<T, Core::System&, u8*>) {
|
|
||||||
controllers[static_cast<std::size_t>(controller)] =
|
|
||||||
std::make_unique<T>(system, shared_memory);
|
|
||||||
} else {
|
|
||||||
controllers[static_cast<std::size_t>(controller)] =
|
|
||||||
std::make_unique<T>(system.HIDCore(), shared_memory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void MakeControllerWithServiceContext(HidController controller, u8* shared_memory) {
|
|
||||||
controllers[static_cast<std::size_t>(controller)] =
|
|
||||||
std::make_unique<T>(system.HIDCore(), shared_memory, service_context);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetSharedMemoryHandle(HLERequestContext& ctx);
|
|
||||||
void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
|
||||||
void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
|
||||||
void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
|
||||||
void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
|
||||||
|
|
||||||
KernelHelpers::ServiceContext& service_context;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
|
|
||||||
controllers{};
|
|
||||||
};
|
|
||||||
|
|
||||||
class Hid final : public ServiceFramework<Hid> {
|
|
||||||
public:
|
|
||||||
explicit Hid(Core::System& system_, std::shared_ptr<IAppletResource> applet_resource_);
|
|
||||||
~Hid() override;
|
|
||||||
|
|
||||||
std::shared_ptr<IAppletResource> GetAppletResource();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void CreateAppletResource(HLERequestContext& ctx);
|
|
||||||
void ActivateDebugPad(HLERequestContext& ctx);
|
|
||||||
void ActivateTouchScreen(HLERequestContext& ctx);
|
|
||||||
void ActivateMouse(HLERequestContext& ctx);
|
|
||||||
void ActivateKeyboard(HLERequestContext& ctx);
|
|
||||||
void SendKeyboardLockKeyEvent(HLERequestContext& ctx);
|
|
||||||
void ActivateXpad(HLERequestContext& ctx);
|
|
||||||
void GetXpadIDs(HLERequestContext& ctx);
|
|
||||||
void ActivateSixAxisSensor(HLERequestContext& ctx);
|
|
||||||
void DeactivateSixAxisSensor(HLERequestContext& ctx);
|
|
||||||
void StartSixAxisSensor(HLERequestContext& ctx);
|
|
||||||
void StopSixAxisSensor(HLERequestContext& ctx);
|
|
||||||
void IsSixAxisSensorFusionEnabled(HLERequestContext& ctx);
|
|
||||||
void EnableSixAxisSensorFusion(HLERequestContext& ctx);
|
|
||||||
void SetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
|
||||||
void GetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
|
||||||
void ResetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
|
||||||
void SetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
|
||||||
void GetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
|
||||||
void ResetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
|
||||||
void IsSixAxisSensorAtRest(HLERequestContext& ctx);
|
|
||||||
void IsFirmwareUpdateAvailableForSixAxisSensor(HLERequestContext& ctx);
|
|
||||||
void EnableSixAxisSensorUnalteredPassthrough(HLERequestContext& ctx);
|
|
||||||
void IsSixAxisSensorUnalteredPassthroughEnabled(HLERequestContext& ctx);
|
|
||||||
void LoadSixAxisSensorCalibrationParameter(HLERequestContext& ctx);
|
|
||||||
void GetSixAxisSensorIcInformation(HLERequestContext& ctx);
|
|
||||||
void ResetIsSixAxisSensorDeviceNewlyAssigned(HLERequestContext& ctx);
|
|
||||||
void ActivateGesture(HLERequestContext& ctx);
|
|
||||||
void SetSupportedNpadStyleSet(HLERequestContext& ctx);
|
|
||||||
void GetSupportedNpadStyleSet(HLERequestContext& ctx);
|
|
||||||
void SetSupportedNpadIdType(HLERequestContext& ctx);
|
|
||||||
void ActivateNpad(HLERequestContext& ctx);
|
|
||||||
void DeactivateNpad(HLERequestContext& ctx);
|
|
||||||
void AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx);
|
|
||||||
void DisconnectNpad(HLERequestContext& ctx);
|
|
||||||
void GetPlayerLedPattern(HLERequestContext& ctx);
|
|
||||||
void ActivateNpadWithRevision(HLERequestContext& ctx);
|
|
||||||
void SetNpadJoyHoldType(HLERequestContext& ctx);
|
|
||||||
void GetNpadJoyHoldType(HLERequestContext& ctx);
|
|
||||||
void SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx);
|
|
||||||
void SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx);
|
|
||||||
void SetNpadJoyAssignmentModeDual(HLERequestContext& ctx);
|
|
||||||
void MergeSingleJoyAsDualJoy(HLERequestContext& ctx);
|
|
||||||
void StartLrAssignmentMode(HLERequestContext& ctx);
|
|
||||||
void StopLrAssignmentMode(HLERequestContext& ctx);
|
|
||||||
void SetNpadHandheldActivationMode(HLERequestContext& ctx);
|
|
||||||
void GetNpadHandheldActivationMode(HLERequestContext& ctx);
|
|
||||||
void SwapNpadAssignment(HLERequestContext& ctx);
|
|
||||||
void IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& ctx);
|
|
||||||
void EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx);
|
|
||||||
void SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext& ctx);
|
|
||||||
void SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx);
|
|
||||||
void SetNpadCaptureButtonAssignment(HLERequestContext& ctx);
|
|
||||||
void ClearNpadCaptureButtonAssignment(HLERequestContext& ctx);
|
|
||||||
void GetVibrationDeviceInfo(HLERequestContext& ctx);
|
|
||||||
void SendVibrationValue(HLERequestContext& ctx);
|
|
||||||
void GetActualVibrationValue(HLERequestContext& ctx);
|
|
||||||
void CreateActiveVibrationDeviceList(HLERequestContext& ctx);
|
|
||||||
void PermitVibration(HLERequestContext& ctx);
|
|
||||||
void IsVibrationPermitted(HLERequestContext& ctx);
|
|
||||||
void SendVibrationValues(HLERequestContext& ctx);
|
|
||||||
void SendVibrationGcErmCommand(HLERequestContext& ctx);
|
|
||||||
void GetActualVibrationGcErmCommand(HLERequestContext& ctx);
|
|
||||||
void BeginPermitVibrationSession(HLERequestContext& ctx);
|
|
||||||
void EndPermitVibrationSession(HLERequestContext& ctx);
|
|
||||||
void IsVibrationDeviceMounted(HLERequestContext& ctx);
|
|
||||||
void ActivateConsoleSixAxisSensor(HLERequestContext& ctx);
|
|
||||||
void StartConsoleSixAxisSensor(HLERequestContext& ctx);
|
|
||||||
void StopConsoleSixAxisSensor(HLERequestContext& ctx);
|
|
||||||
void ActivateSevenSixAxisSensor(HLERequestContext& ctx);
|
|
||||||
void StartSevenSixAxisSensor(HLERequestContext& ctx);
|
|
||||||
void StopSevenSixAxisSensor(HLERequestContext& ctx);
|
|
||||||
void InitializeSevenSixAxisSensor(HLERequestContext& ctx);
|
|
||||||
void FinalizeSevenSixAxisSensor(HLERequestContext& ctx);
|
|
||||||
void ResetSevenSixAxisSensorTimestamp(HLERequestContext& ctx);
|
|
||||||
void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx);
|
|
||||||
void GetPalmaConnectionHandle(HLERequestContext& ctx);
|
|
||||||
void InitializePalma(HLERequestContext& ctx);
|
|
||||||
void AcquirePalmaOperationCompleteEvent(HLERequestContext& ctx);
|
|
||||||
void GetPalmaOperationInfo(HLERequestContext& ctx);
|
|
||||||
void PlayPalmaActivity(HLERequestContext& ctx);
|
|
||||||
void SetPalmaFrModeType(HLERequestContext& ctx);
|
|
||||||
void ReadPalmaStep(HLERequestContext& ctx);
|
|
||||||
void EnablePalmaStep(HLERequestContext& ctx);
|
|
||||||
void ResetPalmaStep(HLERequestContext& ctx);
|
|
||||||
void ReadPalmaApplicationSection(HLERequestContext& ctx);
|
|
||||||
void WritePalmaApplicationSection(HLERequestContext& ctx);
|
|
||||||
void ReadPalmaUniqueCode(HLERequestContext& ctx);
|
|
||||||
void SetPalmaUniqueCodeInvalid(HLERequestContext& ctx);
|
|
||||||
void WritePalmaActivityEntry(HLERequestContext& ctx);
|
|
||||||
void WritePalmaRgbLedPatternEntry(HLERequestContext& ctx);
|
|
||||||
void WritePalmaWaveEntry(HLERequestContext& ctx);
|
|
||||||
void SetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
|
|
||||||
void GetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
|
|
||||||
void SuspendPalmaFeature(HLERequestContext& ctx);
|
|
||||||
void GetPalmaOperationResult(HLERequestContext& ctx);
|
|
||||||
void ReadPalmaPlayLog(HLERequestContext& ctx);
|
|
||||||
void ResetPalmaPlayLog(HLERequestContext& ctx);
|
|
||||||
void SetIsPalmaAllConnectable(HLERequestContext& ctx);
|
|
||||||
void SetIsPalmaPairedConnectable(HLERequestContext& ctx);
|
|
||||||
void PairPalma(HLERequestContext& ctx);
|
|
||||||
void SetPalmaBoostMode(HLERequestContext& ctx);
|
|
||||||
void CancelWritePalmaWaveEntry(HLERequestContext& ctx);
|
|
||||||
void EnablePalmaBoostMode(HLERequestContext& ctx);
|
|
||||||
void GetPalmaBluetoothAddress(HLERequestContext& ctx);
|
|
||||||
void SetDisallowedPalmaConnection(HLERequestContext& ctx);
|
|
||||||
void SetNpadCommunicationMode(HLERequestContext& ctx);
|
|
||||||
void GetNpadCommunicationMode(HLERequestContext& ctx);
|
|
||||||
void SetTouchScreenConfiguration(HLERequestContext& ctx);
|
|
||||||
void IsFirmwareUpdateNeededForNotification(HLERequestContext& ctx);
|
|
||||||
|
|
||||||
std::shared_ptr<IAppletResource> applet_resource;
|
|
||||||
|
|
||||||
KernelHelpers::ServiceContext service_context;
|
|
||||||
};
|
|
||||||
|
|
||||||
void LoopProcess(Core::System& system);
|
void LoopProcess(Core::System& system);
|
||||||
|
|
||||||
} // namespace Service::HID
|
} // namespace Service::HID
|
||||||
|
|
|
@ -0,0 +1,650 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "core/hle/service/hid//hid_result.h"
|
||||||
|
#include "core/hle/service/hid//hid_types.h"
|
||||||
|
#include "core/hle/service/hid/hid_debug_server.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/debug_pad.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/gesture.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/keyboard.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/mouse.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/npad_resource/npad.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/palma.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/sixaxis.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/touch_screen.h"
|
||||||
|
#include "core/hle/service/hid/hid_firmware_settings.h"
|
||||||
|
#include "core/hle/service/ipc_helpers.h"
|
||||||
|
|
||||||
|
namespace Service::HID {
|
||||||
|
|
||||||
|
IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<ResourceManager> resource,
|
||||||
|
std::shared_ptr<HidFirmwareSettings> settings)
|
||||||
|
: ServiceFramework{system_, "hid:dbg"}, resource_manager{resource},
|
||||||
|
firmware_settings{settings} {
|
||||||
|
// clang-format off
|
||||||
|
static const FunctionInfo functions[] = {
|
||||||
|
{0, &IHidDebugServer::DeactivateDebugPad, "DeactivateDebugPad"},
|
||||||
|
{1, &IHidDebugServer::SetDebugPadAutoPilotState, "SetDebugPadAutoPilotState"},
|
||||||
|
{2, &IHidDebugServer::UnsetDebugPadAutoPilotState, "UnsetDebugPadAutoPilotState"},
|
||||||
|
{10, &IHidDebugServer::DeactivateTouchScreen, "DeactivateTouchScreen"},
|
||||||
|
{11, &IHidDebugServer::SetTouchScreenAutoPilotState, "SetTouchScreenAutoPilotState"},
|
||||||
|
{12, &IHidDebugServer::UnsetTouchScreenAutoPilotState, "UnsetTouchScreenAutoPilotState"},
|
||||||
|
{13, &IHidDebugServer::GetTouchScreenConfiguration, "GetTouchScreenConfiguration"},
|
||||||
|
{14, &IHidDebugServer::ProcessTouchScreenAutoTune, "ProcessTouchScreenAutoTune"},
|
||||||
|
{15, &IHidDebugServer::ForceStopTouchScreenManagement, "ForceStopTouchScreenManagement"},
|
||||||
|
{16, &IHidDebugServer::ForceRestartTouchScreenManagement, "ForceRestartTouchScreenManagement"},
|
||||||
|
{17, &IHidDebugServer::IsTouchScreenManaged, "IsTouchScreenManaged"},
|
||||||
|
{20, &IHidDebugServer::DeactivateMouse, "DeactivateMouse"},
|
||||||
|
{21, &IHidDebugServer::SetMouseAutoPilotState, "SetMouseAutoPilotState"},
|
||||||
|
{22, &IHidDebugServer::UnsetMouseAutoPilotState, "UnsetMouseAutoPilotState"},
|
||||||
|
{25, &IHidDebugServer::SetDebugMouseAutoPilotState, "SetDebugMouseAutoPilotState"},
|
||||||
|
{26, &IHidDebugServer::UnsetDebugMouseAutoPilotState, "UnsetDebugMouseAutoPilotState"},
|
||||||
|
{30, &IHidDebugServer::DeactivateKeyboard, "DeactivateKeyboard"},
|
||||||
|
{31, &IHidDebugServer::SetKeyboardAutoPilotState, "SetKeyboardAutoPilotState"},
|
||||||
|
{32, &IHidDebugServer::UnsetKeyboardAutoPilotState, "UnsetKeyboardAutoPilotState"},
|
||||||
|
{50, &IHidDebugServer::DeactivateXpad, "DeactivateXpad"},
|
||||||
|
{60, &IHidDebugServer::ClearNpadSystemCommonPolicy, "ClearNpadSystemCommonPolicy"},
|
||||||
|
{61, &IHidDebugServer::DeactivateNpad, "DeactivateNpad"},
|
||||||
|
{62, &IHidDebugServer::ForceDisconnectNpad, "ForceDisconnectNpad"},
|
||||||
|
{91, &IHidDebugServer::DeactivateGesture, "DeactivateGesture"},
|
||||||
|
{110, &IHidDebugServer::DeactivateHomeButton, "DeactivateHomeButton"},
|
||||||
|
{111, &IHidDebugServer::SetHomeButtonAutoPilotState, "SetHomeButtonAutoPilotState"},
|
||||||
|
{112, &IHidDebugServer::UnsetHomeButtonAutoPilotState, "UnsetHomeButtonAutoPilotState"},
|
||||||
|
{120, &IHidDebugServer::DeactivateSleepButton, "DeactivateSleepButton"},
|
||||||
|
{121, &IHidDebugServer::SetSleepButtonAutoPilotState, "SetSleepButtonAutoPilotState"},
|
||||||
|
{122, &IHidDebugServer::UnsetSleepButtonAutoPilotState, "UnsetSleepButtonAutoPilotState"},
|
||||||
|
{123, &IHidDebugServer::DeactivateInputDetector, "DeactivateInputDetector"},
|
||||||
|
{130, &IHidDebugServer::DeactivateCaptureButton, "DeactivateCaptureButton"},
|
||||||
|
{131, &IHidDebugServer::SetCaptureButtonAutoPilotState, "SetCaptureButtonAutoPilotState"},
|
||||||
|
{132, &IHidDebugServer::UnsetCaptureButtonAutoPilotState, "UnsetCaptureButtonAutoPilotState"},
|
||||||
|
{133, &IHidDebugServer::SetShiftAccelerometerCalibrationValue, "SetShiftAccelerometerCalibrationValue"},
|
||||||
|
{134, &IHidDebugServer::GetShiftAccelerometerCalibrationValue, "GetShiftAccelerometerCalibrationValue"},
|
||||||
|
{135, &IHidDebugServer::SetShiftGyroscopeCalibrationValue, "SetShiftGyroscopeCalibrationValue"},
|
||||||
|
{136, &IHidDebugServer::GetShiftGyroscopeCalibrationValue, "GetShiftGyroscopeCalibrationValue"},
|
||||||
|
{140, nullptr, "SetSixAxisSensorMode"},
|
||||||
|
{140, nullptr, "DeactivateConsoleSixAxisSensor"},
|
||||||
|
{141, nullptr, "GetConsoleSixAxisSensorSamplingFrequency"},
|
||||||
|
{142, nullptr, "DeactivateSevenSixAxisSensor"},
|
||||||
|
{143, nullptr, "GetConsoleSixAxisSensorCountStates"},
|
||||||
|
{144, &IHidDebugServer::GetAccelerometerFsr, "GetAccelerometerFsr"},
|
||||||
|
{145, &IHidDebugServer::SetAccelerometerFsr, "SetAccelerometerFsr"},
|
||||||
|
{146, &IHidDebugServer::GetAccelerometerOdr, "GetAccelerometerOdr"},
|
||||||
|
{147, &IHidDebugServer::SetAccelerometerOdr, "SetAccelerometerOdr"},
|
||||||
|
{148, &IHidDebugServer::GetGyroscopeFsr, "GetGyroscopeFsr"},
|
||||||
|
{149, &IHidDebugServer::SetGyroscopeFsr, "SetGyroscopeFsr"},
|
||||||
|
{150, &IHidDebugServer::GetGyroscopeOdr, "GetGyroscopeOdr"},
|
||||||
|
{151, &IHidDebugServer::SetGyroscopeOdr, "SetGyroscopeOdr"},
|
||||||
|
{152, nullptr, "GetWhoAmI"},
|
||||||
|
{201, nullptr, "ActivateFirmwareUpdate"},
|
||||||
|
{202, nullptr, "DeactivateFirmwareUpdate"},
|
||||||
|
{203, nullptr, "StartFirmwareUpdate"},
|
||||||
|
{204, nullptr, "GetFirmwareUpdateStage"},
|
||||||
|
{205, nullptr, "GetFirmwareVersion"},
|
||||||
|
{206, nullptr, "GetDestinationFirmwareVersion"},
|
||||||
|
{207, nullptr, "DiscardFirmwareInfoCacheForRevert"},
|
||||||
|
{208, nullptr, "StartFirmwareUpdateForRevert"},
|
||||||
|
{209, nullptr, "GetAvailableFirmwareVersionForRevert"},
|
||||||
|
{210, nullptr, "IsFirmwareUpdatingDevice"},
|
||||||
|
{211, nullptr, "StartFirmwareUpdateIndividual"},
|
||||||
|
{215, nullptr, "SetUsbFirmwareForceUpdateEnabled"},
|
||||||
|
{216, nullptr, "SetAllKuinaDevicesToFirmwareUpdateMode"},
|
||||||
|
{221, nullptr, "UpdateControllerColor"},
|
||||||
|
{222, nullptr, "ConnectUsbPadsAsync"},
|
||||||
|
{223, nullptr, "DisconnectUsbPadsAsync"},
|
||||||
|
{224, nullptr, "UpdateDesignInfo"},
|
||||||
|
{225, nullptr, "GetUniquePadDriverState"},
|
||||||
|
{226, nullptr, "GetSixAxisSensorDriverStates"},
|
||||||
|
{227, nullptr, "GetRxPacketHistory"},
|
||||||
|
{228, nullptr, "AcquireOperationEventHandle"},
|
||||||
|
{229, nullptr, "ReadSerialFlash"},
|
||||||
|
{230, nullptr, "WriteSerialFlash"},
|
||||||
|
{231, nullptr, "GetOperationResult"},
|
||||||
|
{232, nullptr, "EnableShipmentMode"},
|
||||||
|
{233, nullptr, "ClearPairingInfo"},
|
||||||
|
{234, nullptr, "GetUniquePadDeviceTypeSetInternal"},
|
||||||
|
{235, nullptr, "EnableAnalogStickPower"},
|
||||||
|
{236, nullptr, "RequestKuinaUartClockCal"},
|
||||||
|
{237, nullptr, "GetKuinaUartClockCal"},
|
||||||
|
{238, nullptr, "SetKuinaUartClockTrim"},
|
||||||
|
{239, nullptr, "KuinaLoopbackTest"},
|
||||||
|
{240, nullptr, "RequestBatteryVoltage"},
|
||||||
|
{241, nullptr, "GetBatteryVoltage"},
|
||||||
|
{242, nullptr, "GetUniquePadPowerInfo"},
|
||||||
|
{243, nullptr, "RebootUniquePad"},
|
||||||
|
{244, nullptr, "RequestKuinaFirmwareVersion"},
|
||||||
|
{245, nullptr, "GetKuinaFirmwareVersion"},
|
||||||
|
{246, nullptr, "GetVidPid"},
|
||||||
|
{247, nullptr, "GetAnalogStickCalibrationValue"},
|
||||||
|
{248, nullptr, "GetUniquePadIdsFull"},
|
||||||
|
{249, nullptr, "ConnectUniquePad"},
|
||||||
|
{250, nullptr, "IsVirtual"},
|
||||||
|
{251, nullptr, "GetAnalogStickModuleParam"},
|
||||||
|
{301, nullptr, "GetAbstractedPadHandles"},
|
||||||
|
{302, nullptr, "GetAbstractedPadState"},
|
||||||
|
{303, nullptr, "GetAbstractedPadsState"},
|
||||||
|
{321, nullptr, "SetAutoPilotVirtualPadState"},
|
||||||
|
{322, nullptr, "UnsetAutoPilotVirtualPadState"},
|
||||||
|
{323, nullptr, "UnsetAllAutoPilotVirtualPadState"},
|
||||||
|
{324, nullptr, "AttachHdlsWorkBuffer"},
|
||||||
|
{325, nullptr, "ReleaseHdlsWorkBuffer"},
|
||||||
|
{326, nullptr, "DumpHdlsNpadAssignmentState"},
|
||||||
|
{327, nullptr, "DumpHdlsStates"},
|
||||||
|
{328, nullptr, "ApplyHdlsNpadAssignmentState"},
|
||||||
|
{329, nullptr, "ApplyHdlsStateList"},
|
||||||
|
{330, nullptr, "AttachHdlsVirtualDevice"},
|
||||||
|
{331, nullptr, "DetachHdlsVirtualDevice"},
|
||||||
|
{332, nullptr, "SetHdlsState"},
|
||||||
|
{350, nullptr, "AddRegisteredDevice"},
|
||||||
|
{400, nullptr, "DisableExternalMcuOnNxDevice"},
|
||||||
|
{401, nullptr, "DisableRailDeviceFiltering"},
|
||||||
|
{402, nullptr, "EnableWiredPairing"},
|
||||||
|
{403, nullptr, "EnableShipmentModeAutoClear"},
|
||||||
|
{404, nullptr, "SetRailEnabled"},
|
||||||
|
{500, nullptr, "SetFactoryInt"},
|
||||||
|
{501, nullptr, "IsFactoryBootEnabled"},
|
||||||
|
{550, nullptr, "SetAnalogStickModelDataTemporarily"},
|
||||||
|
{551, nullptr, "GetAnalogStickModelData"},
|
||||||
|
{552, nullptr, "ResetAnalogStickModelData"},
|
||||||
|
{600, nullptr, "ConvertPadState"},
|
||||||
|
{650, nullptr, "AddButtonPlayData"},
|
||||||
|
{651, nullptr, "StartButtonPlayData"},
|
||||||
|
{652, nullptr, "StopButtonPlayData"},
|
||||||
|
{2000, nullptr, "DeactivateDigitizer"},
|
||||||
|
{2001, nullptr, "SetDigitizerAutoPilotState"},
|
||||||
|
{2002, nullptr, "UnsetDigitizerAutoPilotState"},
|
||||||
|
{3000, &IHidDebugServer::ReloadFirmwareDebugSettings, "ReloadFirmwareDebugSettings"},
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RegisterHandlers(functions);
|
||||||
|
}
|
||||||
|
|
||||||
|
IHidDebugServer::~IHidDebugServer() = default;
|
||||||
|
|
||||||
|
void IHidDebugServer::DeactivateDebugPad(HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_HID, "called");
|
||||||
|
|
||||||
|
Result result = ResultSuccess;
|
||||||
|
|
||||||
|
if (!firmware_settings->IsDeviceManaged()) {
|
||||||
|
result = GetResourceManager()->GetDebugPad()->Deactivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidDebugServer::SetDebugPadAutoPilotState(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto auto_pilot_state{rp.Pop<DebugPadAutoPilotState>()};
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_HID, "called");
|
||||||
|
|
||||||
|
const Result result =
|
||||||
|
GetResourceManager()->GetDebugPad()->SetAutoPilotState(auto_pilot_state);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidDebugServer::UnsetDebugPadAutoPilotState(HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_HID, "called");
|
||||||
|
|
||||||
|
const Result result =
|
||||||
|
GetResourceManager()->GetDebugPad()->UnsetAutoPilotState();
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidDebugServer::DeactivateTouchScreen(HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_HID, "called");
|
||||||
|
|
||||||
|
Result result = ResultSuccess;
|
||||||
|
|
||||||
|
if (!firmware_settings->IsDeviceManaged()) {
|
||||||
|
result = GetResourceManager()->GetTouchScreen()->Deactivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidDebugServer::SetTouchScreenAutoPilotState(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto touch_state_elements{ctx.GetReadBufferNumElements<TouchState>()};
|
||||||
|
const auto touch_state_buffer{ctx.ReadBuffer()};
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_HID, "called, touch_state_elements={}", touch_state_elements);
|
||||||
|
|
||||||
|
std::vector<TouchState> touch_states(touch_state_elements);
|
||||||
|
memcpy(touch_states.data(), touch_state_buffer.data(), touch_state_buffer.size());
|
||||||
|
const Result result = GetResourceManager()->GetTouchScreen()->SetAutoPilotState(touch_states);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidDebugServer::UnsetTouchScreenAutoPilotState(HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_HID, "called");
|
||||||
|
|
||||||
|
const Result result = GetResourceManager()->GetTouchScreen()->UnsetAutoPilotState();
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidDebugServer::GetTouchScreenConfiguration(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
|
||||||
|
LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
|
||||||
|
applet_resource_user_id);
|
||||||
|
|
||||||
|
TouchScreenConfigurationForNx touch_screen_configuration{};
|
||||||
|
const Result result =
|
||||||
|
GetResourceManager()->GetTouchScreen()->GetConfiguration(applet_resource_user_id);
|
||||||
|
|
||||||
|
switch (touch_screen_configuration.mode) {
|
||||||
|
case TouchScreenModeForNx::UseSystemSetting:
|
||||||
|
case TouchScreenModeForNx::Finger:
|
||||||
|
case TouchScreenModeForNx::Heat2:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
touch_screen_configuration.mode = TouchScreenModeForNx::UseSystemSetting;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 6};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.PushRaw(touch_screen_configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidDebugServer::ProcessTouchScreenAutoTune(HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_HID, "called");
|
||||||
|
|
||||||
|
const Result result = GetResourceManager()->GetTouchScreen()->ProcessAutoTune();
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidDebugServer::ForceStopTouchScreenManagement(HLERequestContext& ctx){
|
||||||
|
LOG_DEBUG(Service_HID, "called");
|
||||||
|
|
||||||
|
Result result = ResultSuccess;
|
||||||
|
auto touch_screen = GetResourceManager()->GetTouchScreen();
|
||||||
|
|
||||||
|
if (firmware_settings->IsDeviceManaged()) {
|
||||||
|
if (firmware_settings->IsTouchI2cManaged()) {
|
||||||
|
result=touch_screen->Something();
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
result = touch_screen->Somethingx2();
|
||||||
|
}
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
result = touch_screen->DeactivateTouchScreen();
|
||||||
|
}
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
result = touch_screen->DeactivateGesture();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidDebugServer::ForceRestartTouchScreenManagement(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
struct Parameters {
|
||||||
|
u32 basic_gesture_id;
|
||||||
|
INSERT_PADDING_WORDS_NOINIT(1);
|
||||||
|
u64 applet_resource_user_id;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
|
||||||
|
|
||||||
|
const auto parameters{rp.PopRaw<Parameters>()};
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_HID, "called, basic_gesture_id={}, applet_resource_user_id={}",
|
||||||
|
parameters.basic_gesture_id, parameters.applet_resource_user_id);
|
||||||
|
|
||||||
|
Result result = ResultSuccess;
|
||||||
|
auto touch_screen = GetResourceManager()->GetTouchScreen();
|
||||||
|
|
||||||
|
if (firmware_settings->IsDeviceManaged() && firmware_settings->IsTouchI2cManaged()) {
|
||||||
|
result = touch_screen->ActivateGestureUnmanaged();
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
result = touch_screen->ActivateGesture(basic_gesture_id, applet_resource_user_id);
|
||||||
|
}
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
result = touch_screen->ActivateTouchScreenUnmanaged();
|
||||||
|
}
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
result = touch_screen->ActivateTouchScreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidDebugServer::IsTouchScreenManaged(HLERequestContext& ctx){
|
||||||
|
LOG_DEBUG(Service_HID, "called");
|
||||||
|
|
||||||
|
bool is_managed{};
|
||||||
|
bool is_bool{};
|
||||||
|
bool is_baal{};
|
||||||
|
Result result = GetResourceManager()->GetTouchScreen()->SomeFunction(is_bool);
|
||||||
|
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
GetResourceManager()->GetTouchScreen()->SomeFunction2(is_baal);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
is_managed = is_bool | is_baal;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidDebugServer::DeactivateMouse(HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_HID, "called");
|
||||||
|
|
||||||
|
Result result = ResultSuccess;
|
||||||
|
|
||||||
|
if (!firmware_settings->IsDeviceManaged()) {
|
||||||
|
result = GetResourceManager()->GetMouse()->Deactivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidDebugServer::SetMouseAutoPilotState(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto auto_pilot_state{rp.Pop<MouseAutoPilotState>()};
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_HID, "called");
|
||||||
|
|
||||||
|
const Result result = GetResourceManager()->GetMouse()->SetAutoPilotState(auto_pilot_state);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidDebugServer::UnsetMouseAutoPilotState(HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_HID, "called");
|
||||||
|
|
||||||
|
const Result result = GetResourceManager()->GetMouse()->UnsetAutoPilotState();
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidDebugServer::SetDebugMouseAutoPilotState(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto auto_pilot_state{rp.Pop<MouseAutoPilotState>()};
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_HID, "called");
|
||||||
|
|
||||||
|
const Result result = GetResourceManager()->GetDebugMouse()->SetAutoPilotState(auto_pilot_state);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidDebugServer::UnsetDebugMouseAutoPilotState(HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_HID, "called");
|
||||||
|
|
||||||
|
const Result result = GetResourceManager()->GetDebugMouse()->UnsetAutoPilotState();
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidDebugServer::DeactivateKeyboard(HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_HID, "called");
|
||||||
|
|
||||||
|
Result result = ResultSuccess;
|
||||||
|
|
||||||
|
if (!firmware_settings->IsDeviceManaged()) {
|
||||||
|
result = GetResourceManager()->GetKeyboard()->Deactivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidDebugServer::SetKeyboardAutoPilotState(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto auto_pilot_state{rp.Pop<KeyboardAutoPilotState>()};
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_HID, "called");
|
||||||
|
|
||||||
|
const Result result =
|
||||||
|
GetResourceManager()->GetKeyboard()->SetAutoPilotState(auto_pilot_state);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidDebugServer::UnsetKeyboardAutoPilotState(HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_HID, "called");
|
||||||
|
|
||||||
|
const Result result = GetResourceManager()->GetKeyboard()->UnsetAutoPilotState();
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidDebugServer::DeactivateXpad(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto joy_xpad_id{rp.Pop<u32>()};
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_HID, "called, joy_xpad_id={}", joy_xpad_id);
|
||||||
|
|
||||||
|
// This function has been stubbed since 10.0.0+
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidDebugServer::ClearNpadSystemCommonPolicy(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
|
||||||
|
LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
|
||||||
|
|
||||||
|
const auto npad = GetResourceManager()->GetNpad();
|
||||||
|
const auto result = npad->ClearNpadSystemCommonPolicy(applet_resource_user_id);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidDebugServer::DeactivateNpad(HLERequestContext& ctx) {}
|
||||||
|
|
||||||
|
void IHidDebugServer::ForceDisconnectNpad(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto npad_id{rp.PopEnum<NpadIdType>()};
|
||||||
|
|
||||||
|
LOG_INFO(Service_HID, "called, npad_id={}", npad_id);
|
||||||
|
|
||||||
|
GetResourceManager()->GetNpad()->ForceDisconnectNpad(NpadIdType::Player1);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidDebugServer::DeactivateGesture(HLERequestContext& ctx) {}
|
||||||
|
void IHidDebugServer::DeactivateHomeButton(HLERequestContext& ctx) {}
|
||||||
|
void IHidDebugServer::SetHomeButtonAutoPilotState(HLERequestContext& ctx) {}
|
||||||
|
void IHidDebugServer::UnsetHomeButtonAutoPilotState(HLERequestContext& ctx) {}
|
||||||
|
void IHidDebugServer::DeactivateSleepButton(HLERequestContext& ctx) {}
|
||||||
|
void IHidDebugServer::SetSleepButtonAutoPilotState(HLERequestContext& ctx) {}
|
||||||
|
void IHidDebugServer::UnsetSleepButtonAutoPilotState(HLERequestContext& ctx) {}
|
||||||
|
void IHidDebugServer::DeactivateInputDetector(HLERequestContext& ctx) {}
|
||||||
|
void IHidDebugServer::DeactivateCaptureButton(HLERequestContext& ctx) {}
|
||||||
|
void IHidDebugServer::SetCaptureButtonAutoPilotState(HLERequestContext& ctx) {}
|
||||||
|
void IHidDebugServer::UnsetCaptureButtonAutoPilotState(HLERequestContext& ctx) {}
|
||||||
|
|
||||||
|
void IHidDebugServer::SetShiftAccelerometerCalibrationValue(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
struct Parameters {
|
||||||
|
SixAxisSensorHandle sixaxis_handle;
|
||||||
|
SixAxisSensorShiftAccelerometerCalibration accelerometer_calibration;
|
||||||
|
INSERT_PADDING_WORDS_NOINIT(1);
|
||||||
|
u64 applet_resource_user_id;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
|
||||||
|
|
||||||
|
const auto parameters{rp.PopRaw<Parameters>()};
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_HID,
|
||||||
|
"called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
|
||||||
|
parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
|
||||||
|
parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
|
||||||
|
|
||||||
|
Result result = ResultSuccess;
|
||||||
|
std::array<u64, ARUID_MAX> aruid_list{};
|
||||||
|
std::shared_ptr<SixAxisSensorState> state = nullptr;
|
||||||
|
|
||||||
|
const auto sixaxis = GetResourceManager()->GetSixAxis();
|
||||||
|
sixaxis->GetAruidList(aruid_list);
|
||||||
|
|
||||||
|
for (const auto& aruid : aruid_list) {
|
||||||
|
result = sixaxis->GetSensorState(state, aruid, parameters.sixaxis_handle);
|
||||||
|
if (result.IsError()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
state->SetShiftAccelerometerCalibrationValue(parameters.accelerometer_calibration);
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidDebugServer::GetShiftAccelerometerCalibrationValue(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
struct Parameters {
|
||||||
|
SixAxisSensorHandle sixaxis_handle;
|
||||||
|
INSERT_PADDING_WORDS_NOINIT(1);
|
||||||
|
u64 applet_resource_user_id;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
|
||||||
|
|
||||||
|
const auto parameters{rp.PopRaw<Parameters>()};
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_HID,
|
||||||
|
"called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
|
||||||
|
parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
|
||||||
|
parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
|
||||||
|
|
||||||
|
SixAxisSensorShiftAccelerometerCalibration accelerometer_calibration;
|
||||||
|
std::shared_ptr<SixAxisSensorState> state = nullptr;
|
||||||
|
const auto sixaxis = GetResourceManager()->GetSixAxis();
|
||||||
|
const auto result = sixaxis->GetSensorState(state, parameters.applet_resource_user_id,
|
||||||
|
parameters.sixaxis_handle);
|
||||||
|
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
accelerometer_calibration = state->GetShiftAccelerometerCalibrationValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
|
rb.Push(result);
|
||||||
|
rb.PushRaw(accelerometer_calibration);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidDebugServer::SetShiftGyroscopeCalibrationValue(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
struct Parameters {
|
||||||
|
SixAxisSensorHandle sixaxis_handle;
|
||||||
|
SixAxisSensorShiftGyroscopeCalibration gyroscope_calibration;
|
||||||
|
INSERT_PADDING_WORDS_NOINIT(1);
|
||||||
|
u64 applet_resource_user_id;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
|
||||||
|
|
||||||
|
const auto parameters{rp.PopRaw<Parameters>()};
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_HID,
|
||||||
|
"called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
|
||||||
|
parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
|
||||||
|
parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
|
||||||
|
|
||||||
|
Result result = ResultSuccess;
|
||||||
|
std::array<u64, ARUID_MAX> aruid_list{};
|
||||||
|
std::shared_ptr<SixAxisSensorState> state = nullptr;
|
||||||
|
|
||||||
|
const auto sixaxis = GetResourceManager()->GetSixAxis();
|
||||||
|
sixaxis->GetAruidList(aruid_list);
|
||||||
|
|
||||||
|
for (const auto& aruid : aruid_list) {
|
||||||
|
result = sixaxis->GetSensorState(state, aruid, parameters.sixaxis_handle);
|
||||||
|
if (result.IsError()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
state->SetShiftGyroscopeCalibrationValue(parameters.gyroscope_calibration);
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidDebugServer::GetShiftGyroscopeCalibrationValue(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
struct Parameters {
|
||||||
|
SixAxisSensorHandle sixaxis_handle;
|
||||||
|
INSERT_PADDING_WORDS_NOINIT(1);
|
||||||
|
u64 applet_resource_user_id;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
|
||||||
|
|
||||||
|
const auto parameters{rp.PopRaw<Parameters>()};
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_HID,
|
||||||
|
"called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
|
||||||
|
parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
|
||||||
|
parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
|
||||||
|
|
||||||
|
SixAxisSensorShiftGyroscopeCalibration gyroscope_calibration;
|
||||||
|
std::shared_ptr<SixAxisSensorState> state = nullptr;
|
||||||
|
const auto sixaxis = GetResourceManager()->GetSixAxis();
|
||||||
|
const auto result = sixaxis->GetSensorState(state, parameters.applet_resource_user_id,
|
||||||
|
parameters.sixaxis_handle);
|
||||||
|
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
gyroscope_calibration = state->GetShiftGyroscopeCalibrationValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
|
rb.Push(result);
|
||||||
|
rb.PushRaw(gyroscope_calibration);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidDebugServer::GetAccelerometerFsr(HLERequestContext& ctx) {}
|
||||||
|
void IHidDebugServer::SetAccelerometerFsr(HLERequestContext& ctx) {}
|
||||||
|
void IHidDebugServer::GetAccelerometerOdr(HLERequestContext& ctx) {}
|
||||||
|
void IHidDebugServer::SetAccelerometerOdr(HLERequestContext& ctx) {}
|
||||||
|
void IHidDebugServer::GetGyroscopeFsr(HLERequestContext& ctx) {}
|
||||||
|
void IHidDebugServer::SetGyroscopeFsr(HLERequestContext& ctx) {}
|
||||||
|
void IHidDebugServer::GetGyroscopeOdr(HLERequestContext& ctx) {}
|
||||||
|
void IHidDebugServer::SetGyroscopeOdr(HLERequestContext& ctx) {}
|
||||||
|
|
||||||
|
void IHidDebugServer::ReloadFirmwareDebugSettings(HLERequestContext& ctx) {
|
||||||
|
firmware_settings->Reload();
|
||||||
|
|
||||||
|
LOG_INFO(Service_HID, "called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<ResourceManager> IHidDebugServer::GetResourceManager() {
|
||||||
|
resource_manager->VerifiyInitalization();
|
||||||
|
return resource_manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::HID
|
|
@ -0,0 +1,78 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Service::HID {
|
||||||
|
class ResourceManager;
|
||||||
|
class HidFirmwareSettings;
|
||||||
|
|
||||||
|
class IHidDebugServer final : public ServiceFramework<IHidDebugServer> {
|
||||||
|
public:
|
||||||
|
explicit IHidDebugServer(Core::System& system_, std::shared_ptr<ResourceManager> resource,
|
||||||
|
std::shared_ptr<HidFirmwareSettings> settings);
|
||||||
|
~IHidDebugServer() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Service calls
|
||||||
|
void DeactivateDebugPad(HLERequestContext& ctx);
|
||||||
|
void SetDebugPadAutoPilotState(HLERequestContext& ctx);
|
||||||
|
void UnsetDebugPadAutoPilotState(HLERequestContext& ctx);
|
||||||
|
void DeactivateTouchScreen(HLERequestContext& ctx);
|
||||||
|
void SetTouchScreenAutoPilotState(HLERequestContext& ctx);
|
||||||
|
void UnsetTouchScreenAutoPilotState(HLERequestContext& ctx);
|
||||||
|
void GetTouchScreenConfiguration(HLERequestContext& ctx);
|
||||||
|
void ProcessTouchScreenAutoTune(HLERequestContext& ctx);
|
||||||
|
void ForceStopTouchScreenManagement(HLERequestContext& ctx);
|
||||||
|
void ForceRestartTouchScreenManagement(HLERequestContext& ctx);
|
||||||
|
void IsTouchScreenManaged(HLERequestContext& ctx);
|
||||||
|
void DeactivateMouse(HLERequestContext& ctx);
|
||||||
|
void SetMouseAutoPilotState(HLERequestContext& ctx);
|
||||||
|
void UnsetMouseAutoPilotState(HLERequestContext& ctx);
|
||||||
|
void SetDebugMouseAutoPilotState(HLERequestContext& ctx);
|
||||||
|
void UnsetDebugMouseAutoPilotState(HLERequestContext& ctx);
|
||||||
|
void DeactivateKeyboard(HLERequestContext& ctx);
|
||||||
|
void SetKeyboardAutoPilotState(HLERequestContext& ctx);
|
||||||
|
void UnsetKeyboardAutoPilotState(HLERequestContext& ctx);
|
||||||
|
void DeactivateXpad(HLERequestContext& ctx);
|
||||||
|
void ClearNpadSystemCommonPolicy(HLERequestContext& ctx);
|
||||||
|
void DeactivateNpad(HLERequestContext& ctx);
|
||||||
|
void ForceDisconnectNpad(HLERequestContext& ctx);
|
||||||
|
void DeactivateGesture(HLERequestContext& ctx);
|
||||||
|
void DeactivateHomeButton(HLERequestContext& ctx);
|
||||||
|
void SetHomeButtonAutoPilotState(HLERequestContext& ctx);
|
||||||
|
void UnsetHomeButtonAutoPilotState(HLERequestContext& ctx);
|
||||||
|
void DeactivateSleepButton(HLERequestContext& ctx);
|
||||||
|
void SetSleepButtonAutoPilotState(HLERequestContext& ctx);
|
||||||
|
void UnsetSleepButtonAutoPilotState(HLERequestContext& ctx);
|
||||||
|
void DeactivateInputDetector(HLERequestContext& ctx);
|
||||||
|
void DeactivateCaptureButton(HLERequestContext& ctx);
|
||||||
|
void SetCaptureButtonAutoPilotState(HLERequestContext& ctx);
|
||||||
|
void UnsetCaptureButtonAutoPilotState(HLERequestContext& ctx);
|
||||||
|
void SetShiftAccelerometerCalibrationValue(HLERequestContext& ctx);
|
||||||
|
void GetShiftAccelerometerCalibrationValue(HLERequestContext& ctx);
|
||||||
|
void SetShiftGyroscopeCalibrationValue(HLERequestContext& ctx);
|
||||||
|
void GetShiftGyroscopeCalibrationValue(HLERequestContext& ctx);
|
||||||
|
void GetAccelerometerFsr(HLERequestContext& ctx);
|
||||||
|
void SetAccelerometerFsr(HLERequestContext& ctx);
|
||||||
|
void GetAccelerometerOdr(HLERequestContext& ctx);
|
||||||
|
void SetAccelerometerOdr(HLERequestContext& ctx);
|
||||||
|
void GetGyroscopeFsr(HLERequestContext& ctx);
|
||||||
|
void SetGyroscopeFsr(HLERequestContext& ctx);
|
||||||
|
void GetGyroscopeOdr(HLERequestContext& ctx);
|
||||||
|
void SetGyroscopeOdr(HLERequestContext& ctx);
|
||||||
|
void ReloadFirmwareDebugSettings(HLERequestContext& ctx);
|
||||||
|
|
||||||
|
std::shared_ptr<ResourceManager> GetResourceManager();
|
||||||
|
|
||||||
|
std::shared_ptr<ResourceManager> resource_manager = nullptr;
|
||||||
|
std::shared_ptr<HidFirmwareSettings> firmware_settings = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::HID
|
|
@ -0,0 +1,148 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.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 should_initialize) {
|
||||||
|
// TODO: uncomment this code when we can talk between services
|
||||||
|
|
||||||
|
if (is_debug_settings_initalized && !should_initialize) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
is_debugpad_enabled = true;
|
||||||
|
// nn::settings::fwdbg::GetSettingsItemValue(&is_debugpad_enabled, 1, "hid_debug",
|
||||||
|
// "enables_debugpad")
|
||||||
|
|
||||||
|
is_device_managed = true;
|
||||||
|
// nn::settings::fwdbg::GetSettingsItemValue(&is_device_managed, 1, "hid_debug",
|
||||||
|
// "manages_devices");
|
||||||
|
|
||||||
|
is_touch_i2c_managed = is_device_managed;
|
||||||
|
if (is_device_managed) {
|
||||||
|
// nn::settings::fwdbg::GetSettingsItemValue(&setting_hid_debug_manages_touch_ic_i2c, 1,
|
||||||
|
// "hid_debug", "manages_touch_ic_i2c");
|
||||||
|
}
|
||||||
|
|
||||||
|
is_future_devices_emulated = false;
|
||||||
|
// nn::settings::fwdbg::GetSettingsItemValue(&setting_hid_debug_emulate_future_device, 1,
|
||||||
|
// "hid_debug", "emulate_future_device");
|
||||||
|
|
||||||
|
is_mcu_hardware_error_emulated = false;
|
||||||
|
// nn::settings::fwdbg::GetSettingsItemValue(&setting_hid_debug_emulate_mcu_hardware_error, 1,
|
||||||
|
// "hid_debug", "emulate_mcu_hardware_error");
|
||||||
|
|
||||||
|
is_rail_enabled = true;
|
||||||
|
// nn::settings::fwdbg::GetSettingsItemValue(&setting_hid_debug_enables_rail, 1, "hid_debug",
|
||||||
|
// "enables_rail");
|
||||||
|
|
||||||
|
is_firmware_update_failure_emulated = false;
|
||||||
|
// nn::settings::fwdbg::GetSettingsItemValue(setting_hid_debug_emulate_firmware_update_failure,
|
||||||
|
// 1, "hid_debug", "emulate_firmware_update_failure");
|
||||||
|
|
||||||
|
is_firmware_update_failure = {};
|
||||||
|
if (is_firmware_update_failure_emulated) {
|
||||||
|
const std::size_t size = 0; // GetSettingsItemValueSize("hid_debug",
|
||||||
|
// "firmware_update_failure"); if (size != 0) {
|
||||||
|
[[maybe_unused]] const std::size_t setting_size =
|
||||||
|
std::min(size, is_firmware_update_failure.size());
|
||||||
|
// nn::settings::fwdbg::GetSettingsItemValue(&is_firmware_update_failure, setting_size,
|
||||||
|
// "hid_debug", "firmware_update_failure");
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
is_ble_disabled = false;
|
||||||
|
// nn::settings::fwdbg::GetSettingsItemValue(&setting_hid_debug_ble_disabled, 1, "hid_debug",
|
||||||
|
// "ble_disabled");
|
||||||
|
|
||||||
|
is_dscale_disabled = false;
|
||||||
|
// nn::settings::fwdbg::GetSettingsItemValue(&setting_hid_debug_dscale_disabled, 1, "hid_debug",
|
||||||
|
// "dscale_disabled");
|
||||||
|
|
||||||
|
is_handheld_forced = true;
|
||||||
|
// nn::settings::fwdbg::GetSettingsItemValue(&force_handheld, 1, "hid_debug", "force_handheld");
|
||||||
|
|
||||||
|
features_per_id_disabled = {};
|
||||||
|
// nn::settings::fwdbg::GetSettingsItemValue(&disabled_features_per_id,
|
||||||
|
// is_features_per_id_disabled.size(), "hid_debug",
|
||||||
|
// "disabled_features_per_id");
|
||||||
|
|
||||||
|
is_touch_firmware_auto_update_disabled = false;
|
||||||
|
// nn::settings::fwdbg::GetSettingsItemValue(
|
||||||
|
// &setting_hid_debug_touch_firmware_auto_update_disabled, 1, "hid_debug",
|
||||||
|
// "touch_firmware_auto_update_disabled");
|
||||||
|
|
||||||
|
is_debug_settings_initalized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HidFirmwareSettings::IsDebugPadEnabled() {
|
||||||
|
LoadSettings(false);
|
||||||
|
return is_debugpad_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
|
|
@ -0,0 +1,54 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.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 should_initialize);
|
||||||
|
|
||||||
|
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_debug_settings_initalized{};
|
||||||
|
|
||||||
|
// Debug settings
|
||||||
|
bool is_debugpad_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
|
|
@ -0,0 +1,41 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
|
namespace Service::HID {
|
||||||
|
|
||||||
|
constexpr Result ResultPalmaResultSuccess{ErrorModule::HID, 0};
|
||||||
|
constexpr Result ResultNpadInvalidHandle{ErrorModule::HID, 100};
|
||||||
|
constexpr Result ResultNpadDeviceIndexOutOfRange{ErrorModule::HID, 107};
|
||||||
|
constexpr Result ResultVibrationInvalidStyleIndex{ErrorModule::HID, 122};
|
||||||
|
constexpr Result ResultVibrationInvalidNpadId{ErrorModule::HID, 123};
|
||||||
|
constexpr Result ResultVibrationVolumeOutOfRange{ErrorModule::HID, 126};
|
||||||
|
constexpr Result ResultVibrationDeviceIndexOutOfRange{ErrorModule::HID, 124};
|
||||||
|
constexpr Result ResultVibrationArraySizeMismatch{ErrorModule::HID, 131};
|
||||||
|
|
||||||
|
constexpr Result ResultInvalidSixAxisFusionRange{ErrorModule::HID, 423};
|
||||||
|
constexpr Result ResultNpadIsDualJoycon{ErrorModule::HID, 601};
|
||||||
|
constexpr Result ResultNpadIsSameType{ErrorModule::HID, 602};
|
||||||
|
constexpr Result ResultInvalidNpadId{ErrorModule::HID, 709};
|
||||||
|
constexpr Result ResultNpadNotConnected{ErrorModule::HID, 710};
|
||||||
|
constexpr Result ResultInvalidArraySize{ErrorModule::HID, 715};
|
||||||
|
constexpr Result ResultUndefinedStyleSet{ErrorModule::HID, 716};
|
||||||
|
constexpr Result ResultInvalidStyleSet{ErrorModule::HID, 717};
|
||||||
|
|
||||||
|
constexpr Result ResultUnknown108{ErrorModule::HID, 108};
|
||||||
|
|
||||||
|
constexpr Result ResultInvalidPalmaNpadId{ErrorModule::HID, 3301};
|
||||||
|
constexpr Result ResultInvalidPalmaHandle{ErrorModule::HID, 3302};
|
||||||
|
constexpr Result ResultOperationFailed{ErrorModule::HID, 3304};
|
||||||
|
|
||||||
|
} // namespace Service::HID
|
||||||
|
|
||||||
|
namespace Service::XCD {
|
||||||
|
|
||||||
|
constexpr Result ResultUnknown1{ErrorModule::XCD, 1};
|
||||||
|
constexpr Result ResultUnknown365{ErrorModule::XCD, 365};
|
||||||
|
|
||||||
|
} // namespace Service::XCD
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,198 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Service::HID {
|
||||||
|
struct VibrationDeviceHandle;
|
||||||
|
struct VibrationValue;
|
||||||
|
|
||||||
|
class ResourceManager;
|
||||||
|
class HidFirmwareSettings;
|
||||||
|
|
||||||
|
class IAppletResource final : public ServiceFramework<IAppletResource> {
|
||||||
|
public:
|
||||||
|
explicit IAppletResource(Core::System& system_);
|
||||||
|
~IAppletResource() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void GetSharedMemoryHandle(HLERequestContext& ctx);
|
||||||
|
};
|
||||||
|
|
||||||
|
class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
|
||||||
|
public:
|
||||||
|
explicit IActiveVibrationDeviceList(Core::System& system_,
|
||||||
|
std::shared_ptr<ResourceManager> resource);
|
||||||
|
~IActiveVibrationDeviceList() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void InitializeVibrationDevice(HLERequestContext& ctx);
|
||||||
|
|
||||||
|
std::shared_ptr<ResourceManager> resource_manager = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IHidServer final : public ServiceFramework<IHidServer> {
|
||||||
|
public:
|
||||||
|
explicit IHidServer(Core::System& system_, std::shared_ptr<ResourceManager> resource,
|
||||||
|
std::shared_ptr<HidFirmwareSettings> settings);
|
||||||
|
~IHidServer() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void CreateAppletResource(HLERequestContext& ctx);
|
||||||
|
void ActivateDebugPad(HLERequestContext& ctx);
|
||||||
|
void ActivateTouchScreen(HLERequestContext& ctx);
|
||||||
|
void ActivateMouse(HLERequestContext& ctx);
|
||||||
|
void ActivateDebugMouse(HLERequestContext& ctx);
|
||||||
|
void ActivateKeyboard(HLERequestContext& ctx);
|
||||||
|
void SendKeyboardLockKeyEvent(HLERequestContext& ctx);
|
||||||
|
void AcquireXpadIdEventHandle(HLERequestContext& ctx);
|
||||||
|
void ReleaseXpadIdEventHandle(HLERequestContext& ctx);
|
||||||
|
void ActivateXpad(HLERequestContext& ctx);
|
||||||
|
void GetXpadIds(HLERequestContext& ctx);
|
||||||
|
void ActivateJoyXpad(HLERequestContext& ctx);
|
||||||
|
void GetJoyXpadLifoHandle(HLERequestContext& ctx);
|
||||||
|
void GetJoyXpadIds(HLERequestContext& ctx);
|
||||||
|
void ActivateSixAxisSensor(HLERequestContext& ctx);
|
||||||
|
void DeactivateSixAxisSensor(HLERequestContext& ctx);
|
||||||
|
void GetSixAxisSensorLifoHandle(HLERequestContext& ctx);
|
||||||
|
void ActivateJoySixAxisSensor(HLERequestContext& ctx);
|
||||||
|
void DeactivateJoySixAxisSensor(HLERequestContext& ctx);
|
||||||
|
void GetJoySixAxisSensorLifoHandle(HLERequestContext& ctx);
|
||||||
|
void StartSixAxisSensor(HLERequestContext& ctx);
|
||||||
|
void StopSixAxisSensor(HLERequestContext& ctx);
|
||||||
|
void IsSixAxisSensorFusionEnabled(HLERequestContext& ctx);
|
||||||
|
void EnableSixAxisSensorFusion(HLERequestContext& ctx);
|
||||||
|
void SetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
||||||
|
void GetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
||||||
|
void ResetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
||||||
|
void SetAccelerometerParameters(HLERequestContext& ctx);
|
||||||
|
void GetAccelerometerParameters(HLERequestContext& ctx);
|
||||||
|
void ResetAccelerometerParameters(HLERequestContext& ctx);
|
||||||
|
void SetAccelerometerPlayMode(HLERequestContext& ctx);
|
||||||
|
void GetAccelerometerPlayMode(HLERequestContext& ctx);
|
||||||
|
void ResetAccelerometerPlayMode(HLERequestContext& ctx);
|
||||||
|
void SetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
||||||
|
void GetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
||||||
|
void ResetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
||||||
|
void IsSixAxisSensorAtRest(HLERequestContext& ctx);
|
||||||
|
void IsFirmwareUpdateAvailableForSixAxisSensor(HLERequestContext& ctx);
|
||||||
|
void EnableSixAxisSensorUnalteredPassthrough(HLERequestContext& ctx);
|
||||||
|
void IsSixAxisSensorUnalteredPassthroughEnabled(HLERequestContext& ctx);
|
||||||
|
void StoreSixAxisSensorCalibrationParameter(HLERequestContext& ctx);
|
||||||
|
void LoadSixAxisSensorCalibrationParameter(HLERequestContext& ctx);
|
||||||
|
void GetSixAxisSensorIcInformation(HLERequestContext& ctx);
|
||||||
|
void ResetIsSixAxisSensorDeviceNewlyAssigned(HLERequestContext& ctx);
|
||||||
|
void ActivateGesture(HLERequestContext& ctx);
|
||||||
|
void SetSupportedNpadStyleSet(HLERequestContext& ctx);
|
||||||
|
void GetSupportedNpadStyleSet(HLERequestContext& ctx);
|
||||||
|
void SetSupportedNpadIdType(HLERequestContext& ctx);
|
||||||
|
void ActivateNpad(HLERequestContext& ctx);
|
||||||
|
void DeactivateNpad(HLERequestContext& ctx);
|
||||||
|
void AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx);
|
||||||
|
void DisconnectNpad(HLERequestContext& ctx);
|
||||||
|
void GetPlayerLedPattern(HLERequestContext& ctx);
|
||||||
|
void ActivateNpadWithRevision(HLERequestContext& ctx);
|
||||||
|
void SetNpadJoyHoldType(HLERequestContext& ctx);
|
||||||
|
void GetNpadJoyHoldType(HLERequestContext& ctx);
|
||||||
|
void SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx);
|
||||||
|
void SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx);
|
||||||
|
void SetNpadJoyAssignmentModeDual(HLERequestContext& ctx);
|
||||||
|
void MergeSingleJoyAsDualJoy(HLERequestContext& ctx);
|
||||||
|
void StartLrAssignmentMode(HLERequestContext& ctx);
|
||||||
|
void StopLrAssignmentMode(HLERequestContext& ctx);
|
||||||
|
void SetNpadHandheldActivationMode(HLERequestContext& ctx);
|
||||||
|
void GetNpadHandheldActivationMode(HLERequestContext& ctx);
|
||||||
|
void SwapNpadAssignment(HLERequestContext& ctx);
|
||||||
|
void IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& ctx);
|
||||||
|
void EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx);
|
||||||
|
void SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext& ctx);
|
||||||
|
void SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx);
|
||||||
|
void SetNpadCaptureButtonAssignment(HLERequestContext& ctx);
|
||||||
|
void ClearNpadCaptureButtonAssignment(HLERequestContext& ctx);
|
||||||
|
void GetVibrationDeviceInfo(HLERequestContext& ctx);
|
||||||
|
void SendVibrationValue(HLERequestContext& ctx);
|
||||||
|
void GetActualVibrationValue(HLERequestContext& ctx);
|
||||||
|
void CreateActiveVibrationDeviceList(HLERequestContext& ctx);
|
||||||
|
void PermitVibration(HLERequestContext& ctx);
|
||||||
|
void IsVibrationPermitted(HLERequestContext& ctx);
|
||||||
|
void SendVibrationValues(HLERequestContext& ctx);
|
||||||
|
void SendVibrationGcErmCommand(HLERequestContext& ctx);
|
||||||
|
void GetActualVibrationGcErmCommand(HLERequestContext& ctx);
|
||||||
|
void BeginPermitVibrationSession(HLERequestContext& ctx);
|
||||||
|
void EndPermitVibrationSession(HLERequestContext& ctx);
|
||||||
|
void IsVibrationDeviceMounted(HLERequestContext& ctx);
|
||||||
|
void SendVibrationValueInBool(HLERequestContext& ctx);
|
||||||
|
void ActivateConsoleSixAxisSensor(HLERequestContext& ctx);
|
||||||
|
void StartConsoleSixAxisSensor(HLERequestContext& ctx);
|
||||||
|
void StopConsoleSixAxisSensor(HLERequestContext& ctx);
|
||||||
|
void ActivateSevenSixAxisSensor(HLERequestContext& ctx);
|
||||||
|
void StartSevenSixAxisSensor(HLERequestContext& ctx);
|
||||||
|
void StopSevenSixAxisSensor(HLERequestContext& ctx);
|
||||||
|
void InitializeSevenSixAxisSensor(HLERequestContext& ctx);
|
||||||
|
void FinalizeSevenSixAxisSensor(HLERequestContext& ctx);
|
||||||
|
void SetSevenSixAxisSensorFusionStrength(HLERequestContext& ctx);
|
||||||
|
void GetSevenSixAxisSensorFusionStrength(HLERequestContext& ctx);
|
||||||
|
void ResetSevenSixAxisSensorTimestamp(HLERequestContext& ctx);
|
||||||
|
void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx);
|
||||||
|
void EnableUsbFullKeyController(HLERequestContext& ctx);
|
||||||
|
void IsUsbFullKeyControllerConnected(HLERequestContext& ctx);
|
||||||
|
void HasBattery(HLERequestContext& ctx);
|
||||||
|
void HasLeftRightBattery(HLERequestContext& ctx);
|
||||||
|
void GetNpadInterfaceType(HLERequestContext& ctx);
|
||||||
|
void GetNpadLeftRightInterfaceType(HLERequestContext& ctx);
|
||||||
|
void GetNpadOfHighestBatteryLevel(HLERequestContext& ctx);
|
||||||
|
void GetNpadOfHighestBatteryLevelForJoyRight(HLERequestContext& ctx);
|
||||||
|
void GetPalmaConnectionHandle(HLERequestContext& ctx);
|
||||||
|
void InitializePalma(HLERequestContext& ctx);
|
||||||
|
void AcquirePalmaOperationCompleteEvent(HLERequestContext& ctx);
|
||||||
|
void GetPalmaOperationInfo(HLERequestContext& ctx);
|
||||||
|
void PlayPalmaActivity(HLERequestContext& ctx);
|
||||||
|
void SetPalmaFrModeType(HLERequestContext& ctx);
|
||||||
|
void ReadPalmaStep(HLERequestContext& ctx);
|
||||||
|
void EnablePalmaStep(HLERequestContext& ctx);
|
||||||
|
void ResetPalmaStep(HLERequestContext& ctx);
|
||||||
|
void ReadPalmaApplicationSection(HLERequestContext& ctx);
|
||||||
|
void WritePalmaApplicationSection(HLERequestContext& ctx);
|
||||||
|
void ReadPalmaUniqueCode(HLERequestContext& ctx);
|
||||||
|
void SetPalmaUniqueCodeInvalid(HLERequestContext& ctx);
|
||||||
|
void WritePalmaActivityEntry(HLERequestContext& ctx);
|
||||||
|
void WritePalmaRgbLedPatternEntry(HLERequestContext& ctx);
|
||||||
|
void WritePalmaWaveEntry(HLERequestContext& ctx);
|
||||||
|
void SetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
|
||||||
|
void GetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
|
||||||
|
void SuspendPalmaFeature(HLERequestContext& ctx);
|
||||||
|
void GetPalmaOperationResult(HLERequestContext& ctx);
|
||||||
|
void ReadPalmaPlayLog(HLERequestContext& ctx);
|
||||||
|
void ResetPalmaPlayLog(HLERequestContext& ctx);
|
||||||
|
void SetIsPalmaAllConnectable(HLERequestContext& ctx);
|
||||||
|
void SetIsPalmaPairedConnectable(HLERequestContext& ctx);
|
||||||
|
void PairPalma(HLERequestContext& ctx);
|
||||||
|
void SetPalmaBoostMode(HLERequestContext& ctx);
|
||||||
|
void CancelWritePalmaWaveEntry(HLERequestContext& ctx);
|
||||||
|
void EnablePalmaBoostMode(HLERequestContext& ctx);
|
||||||
|
void GetPalmaBluetoothAddress(HLERequestContext& ctx);
|
||||||
|
void SetDisallowedPalmaConnection(HLERequestContext& ctx);
|
||||||
|
void SetNpadCommunicationMode(HLERequestContext& ctx);
|
||||||
|
void GetNpadCommunicationMode(HLERequestContext& ctx);
|
||||||
|
void SetTouchScreenConfiguration(HLERequestContext& ctx);
|
||||||
|
void IsFirmwareUpdateNeededForNotification(HLERequestContext& ctx);
|
||||||
|
void ActivateDigitizer(HLERequestContext& ctx);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Result SendVibrationValueImpl(const u64 aruid, const VibrationDeviceHandle& handle,
|
||||||
|
const VibrationValue& value);
|
||||||
|
|
||||||
|
std::shared_ptr<ResourceManager> GetResourceManager();
|
||||||
|
|
||||||
|
std::shared_ptr<ResourceManager> resource_manager = nullptr;
|
||||||
|
std::shared_ptr<IAppletResource> applet_resource = nullptr;
|
||||||
|
std::shared_ptr<HidFirmwareSettings> firmware_settings = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::HID
|
|
@ -0,0 +1,403 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "core/hle/service/hid//hid_result.h"
|
||||||
|
#include "core/hle/service/hid//hid_types.h"
|
||||||
|
#include "core/hle/service/hid/hid_system_server.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/npad_resource/npad.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/touch_screen.h"
|
||||||
|
#include "core/hle/service/ipc_helpers.h"
|
||||||
|
|
||||||
|
namespace Service::HID {
|
||||||
|
|
||||||
|
IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<ResourceManager> resource)
|
||||||
|
: ServiceFramework{system_, "hid:sys"}, resource_manager{resource} {
|
||||||
|
// clang-format off
|
||||||
|
static const FunctionInfo functions[] = {
|
||||||
|
{31, nullptr, "SendKeyboardLockKeyEvent"},
|
||||||
|
{101, nullptr, "AcquireHomeButtonEventHandle"},
|
||||||
|
{111, nullptr, "ActivateHomeButton"},
|
||||||
|
{121, nullptr, "AcquireSleepButtonEventHandle"},
|
||||||
|
{131, nullptr, "ActivateSleepButton"},
|
||||||
|
{141, nullptr, "AcquireCaptureButtonEventHandle"},
|
||||||
|
{151, nullptr, "ActivateCaptureButton"},
|
||||||
|
{161, nullptr, "GetPlatformConfig"},
|
||||||
|
{210, nullptr, "AcquireNfcDeviceUpdateEventHandle"},
|
||||||
|
{211, nullptr, "GetNpadsWithNfc"},
|
||||||
|
{212, nullptr, "AcquireNfcActivateEventHandle"},
|
||||||
|
{213, nullptr, "ActivateNfc"},
|
||||||
|
{214, nullptr, "GetXcdHandleForNpadWithNfc"},
|
||||||
|
{215, nullptr, "IsNfcActivated"},
|
||||||
|
{230, nullptr, "AcquireIrSensorEventHandle"},
|
||||||
|
{231, nullptr, "ActivateIrSensor"},
|
||||||
|
{232, nullptr, "GetIrSensorState"},
|
||||||
|
{233, nullptr, "GetXcdHandleForNpadWithIrSensor"},
|
||||||
|
{301, nullptr, "ActivateNpadSystem"},
|
||||||
|
{303, &IHidSystemServer::ApplyNpadSystemCommonPolicy, "ApplyNpadSystemCommonPolicy"},
|
||||||
|
{304, &IHidSystemServer::EnableAssigningSingleOnSlSrPress, "EnableAssigningSingleOnSlSrPress"},
|
||||||
|
{305, &IHidSystemServer::DisableAssigningSingleOnSlSrPress, "DisableAssigningSingleOnSlSrPress"},
|
||||||
|
{306, &IHidSystemServer::GetLastActiveNpad, "GetLastActiveNpad"},
|
||||||
|
{307, nullptr, "GetNpadSystemExtStyle"},
|
||||||
|
{308, &IHidSystemServer::ApplyNpadSystemCommonPolicyFull, "ApplyNpadSystemCommonPolicyFull"},
|
||||||
|
{309, nullptr, "GetNpadFullKeyGripColor"},
|
||||||
|
{310, &IHidSystemServer::GetMaskedSupportedNpadStyleSet, "GetMaskedSupportedNpadStyleSet"},
|
||||||
|
{311, nullptr, "SetNpadPlayerLedBlinkingDevice"},
|
||||||
|
{312, &IHidSystemServer::SetSupportedNpadStyleSetAll, "SetSupportedNpadStyleSetAll"},
|
||||||
|
{313, &IHidSystemServer::GetNpadCaptureButtonAssignment, "GetNpadCaptureButtonAssignment"},
|
||||||
|
{314, nullptr, "GetAppletFooterUiType"},
|
||||||
|
{315, nullptr, "GetAppletDetailedUiType"},
|
||||||
|
{316, nullptr, "GetNpadInterfaceType"},
|
||||||
|
{317, nullptr, "GetNpadLeftRightInterfaceType"},
|
||||||
|
{318, nullptr, "HasBattery"},
|
||||||
|
{319, nullptr, "HasLeftRightBattery"},
|
||||||
|
{321, nullptr/*&IHidSystemServer::GetUniquePadsFromNpad*/, "GetUniquePadsFromNpad"},
|
||||||
|
{322, nullptr, "GetIrSensorState"},
|
||||||
|
{323, nullptr, "GetXcdHandleForNpadWithIrSensor"},
|
||||||
|
{324, nullptr, "GetUniquePadButtonSet"},
|
||||||
|
{325, nullptr, "GetUniquePadColor"},
|
||||||
|
{326, nullptr, "GetUniquePadAppletDetailedUiType"},
|
||||||
|
{327, nullptr, "GetAbstractedPadIdDataFromNpad"},
|
||||||
|
{328, nullptr, "AttachAbstractedPadToNpad"},
|
||||||
|
{329, nullptr, "DetachAbstractedPadAll"},
|
||||||
|
{330, nullptr, "CheckAbstractedPadConnection"},
|
||||||
|
{500, nullptr, "SetAppletResourceUserId"},
|
||||||
|
{501, nullptr, "RegisterAppletResourceUserId"},
|
||||||
|
{502, nullptr, "UnregisterAppletResourceUserId"},
|
||||||
|
{503, nullptr, "EnableAppletToGetInput"},
|
||||||
|
{504, nullptr, "SetAruidValidForVibration"},
|
||||||
|
{505, nullptr, "EnableAppletToGetSixAxisSensor"},
|
||||||
|
{506, nullptr, "EnableAppletToGetPadInput"},
|
||||||
|
{507, nullptr, "EnableAppletToGetTouchScreen"},
|
||||||
|
{510, &IHidSystemServer::SetVibrationMasterVolume, "SetVibrationMasterVolume"},
|
||||||
|
{511, &IHidSystemServer::GetVibrationMasterVolume, "GetVibrationMasterVolume"},
|
||||||
|
{512, nullptr, "BeginPermitVibrationSession"},
|
||||||
|
{513, nullptr, "EndPermitVibrationSession"},
|
||||||
|
{514, nullptr, "Unknown514"},
|
||||||
|
{520, nullptr, "EnableHandheldHids"},
|
||||||
|
{521, nullptr, "DisableHandheldHids"},
|
||||||
|
{522, nullptr, "SetJoyConRailEnabled"},
|
||||||
|
{523, nullptr, "IsJoyConRailEnabled"},
|
||||||
|
{524, nullptr, "IsHandheldHidsEnabled"},
|
||||||
|
{525, nullptr, "IsJoyConAttachedOnAllRail"},
|
||||||
|
{540, nullptr, "AcquirePlayReportControllerUsageUpdateEvent"},
|
||||||
|
{541, nullptr, "GetPlayReportControllerUsages"},
|
||||||
|
{542, nullptr, "AcquirePlayReportRegisteredDeviceUpdateEvent"},
|
||||||
|
{543, nullptr, "GetRegisteredDevicesOld"},
|
||||||
|
{544, nullptr, "AcquireConnectionTriggerTimeoutEvent"},
|
||||||
|
{545, nullptr, "SendConnectionTrigger"},
|
||||||
|
{546, nullptr, "AcquireDeviceRegisteredEventForControllerSupport"},
|
||||||
|
{547, nullptr, "GetAllowedBluetoothLinksCount"},
|
||||||
|
{548, nullptr, "GetRegisteredDevices"},
|
||||||
|
{549, nullptr, "GetConnectableRegisteredDevices"},
|
||||||
|
{700, nullptr, "ActivateUniquePad"},
|
||||||
|
{702, nullptr, "AcquireUniquePadConnectionEventHandle"},
|
||||||
|
{703, nullptr, "GetUniquePadIds"},
|
||||||
|
{751, nullptr/*&IHidSystemServer::AcquireJoyDetachOnBluetoothOffEventHandle*/, "AcquireJoyDetachOnBluetoothOffEventHandle"},
|
||||||
|
{800, nullptr, "ListSixAxisSensorHandles"},
|
||||||
|
{801, nullptr, "IsSixAxisSensorUserCalibrationSupported"},
|
||||||
|
{802, nullptr, "ResetSixAxisSensorCalibrationValues"},
|
||||||
|
{803, nullptr, "StartSixAxisSensorUserCalibration"},
|
||||||
|
{804, nullptr, "CancelSixAxisSensorUserCalibration"},
|
||||||
|
{805, nullptr, "GetUniquePadBluetoothAddress"},
|
||||||
|
{806, nullptr, "DisconnectUniquePad"},
|
||||||
|
{807, nullptr, "GetUniquePadType"},
|
||||||
|
{808, nullptr, "GetUniquePadInterface"},
|
||||||
|
{809, nullptr, "GetUniquePadSerialNumber"},
|
||||||
|
{810, nullptr, "GetUniquePadControllerNumber"},
|
||||||
|
{811, nullptr, "GetSixAxisSensorUserCalibrationStage"},
|
||||||
|
{812, nullptr, "GetConsoleUniqueSixAxisSensorHandle"},
|
||||||
|
{821, nullptr, "StartAnalogStickManualCalibration"},
|
||||||
|
{822, nullptr, "RetryCurrentAnalogStickManualCalibrationStage"},
|
||||||
|
{823, nullptr, "CancelAnalogStickManualCalibration"},
|
||||||
|
{824, nullptr, "ResetAnalogStickManualCalibration"},
|
||||||
|
{825, nullptr, "GetAnalogStickState"},
|
||||||
|
{826, nullptr, "GetAnalogStickManualCalibrationStage"},
|
||||||
|
{827, nullptr, "IsAnalogStickButtonPressed"},
|
||||||
|
{828, nullptr, "IsAnalogStickInReleasePosition"},
|
||||||
|
{829, nullptr, "IsAnalogStickInCircumference"},
|
||||||
|
{830, nullptr, "SetNotificationLedPattern"},
|
||||||
|
{831, nullptr, "SetNotificationLedPatternWithTimeout"},
|
||||||
|
{832, nullptr, "PrepareHidsForNotificationWake"},
|
||||||
|
{850, nullptr/*&IHidSystemServer::IsUsbFullKeyControllerEnabled*/, "IsUsbFullKeyControllerEnabled"},
|
||||||
|
{851, nullptr, "EnableUsbFullKeyController"},
|
||||||
|
{852, nullptr, "IsUsbConnected"},
|
||||||
|
{870, nullptr, "IsHandheldButtonPressedOnConsoleMode"},
|
||||||
|
{900, nullptr, "ActivateInputDetector"},
|
||||||
|
{901, nullptr, "NotifyInputDetector"},
|
||||||
|
{1000, nullptr, "InitializeFirmwareUpdate"},
|
||||||
|
{1001, nullptr, "GetFirmwareVersion"},
|
||||||
|
{1002, nullptr, "GetAvailableFirmwareVersion"},
|
||||||
|
{1003, nullptr, "IsFirmwareUpdateAvailable"},
|
||||||
|
{1004, nullptr, "CheckFirmwareUpdateRequired"},
|
||||||
|
{1005, nullptr, "StartFirmwareUpdate"},
|
||||||
|
{1006, nullptr, "AbortFirmwareUpdate"},
|
||||||
|
{1007, nullptr, "GetFirmwareUpdateState"},
|
||||||
|
{1008, nullptr, "ActivateAudioControl"},
|
||||||
|
{1009, nullptr, "AcquireAudioControlEventHandle"},
|
||||||
|
{1010, nullptr, "GetAudioControlStates"},
|
||||||
|
{1011, nullptr, "DeactivateAudioControl"},
|
||||||
|
{1050, nullptr, "IsSixAxisSensorAccurateUserCalibrationSupported"},
|
||||||
|
{1051, nullptr, "StartSixAxisSensorAccurateUserCalibration"},
|
||||||
|
{1052, nullptr, "CancelSixAxisSensorAccurateUserCalibration"},
|
||||||
|
{1053, nullptr, "GetSixAxisSensorAccurateUserCalibrationState"},
|
||||||
|
{1100, nullptr, "GetHidbusSystemServiceObject"},
|
||||||
|
{1120, nullptr, "SetFirmwareHotfixUpdateSkipEnabled"},
|
||||||
|
{1130, nullptr, "InitializeUsbFirmwareUpdate"},
|
||||||
|
{1131, nullptr, "FinalizeUsbFirmwareUpdate"},
|
||||||
|
{1132, nullptr, "CheckUsbFirmwareUpdateRequired"},
|
||||||
|
{1133, nullptr, "StartUsbFirmwareUpdate"},
|
||||||
|
{1134, nullptr, "GetUsbFirmwareUpdateState"},
|
||||||
|
{1150, nullptr, "SetTouchScreenMagnification"},
|
||||||
|
{1151, nullptr, "GetTouchScreenFirmwareVersion"},
|
||||||
|
{1152, &IHidSystemServer::SetTouchScreenDefaultConfiguration, "SetTouchScreenDefaultConfiguration"},
|
||||||
|
{1153, &IHidSystemServer::GetTouchScreenDefaultConfiguration, "GetTouchScreenDefaultConfiguration"},
|
||||||
|
{1154, nullptr, "IsFirmwareAvailableForNotification"},
|
||||||
|
{1155, nullptr, "SetForceHandheldStyleVibration"},
|
||||||
|
{1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"},
|
||||||
|
{1157, nullptr, "CancelConnectionTrigger"},
|
||||||
|
{1200, nullptr, "IsButtonConfigSupported"},
|
||||||
|
{1201, nullptr, "IsButtonConfigEmbeddedSupported"},
|
||||||
|
{1202, nullptr, "DeleteButtonConfig"},
|
||||||
|
{1203, nullptr, "DeleteButtonConfigEmbedded"},
|
||||||
|
{1204, nullptr, "SetButtonConfigEnabled"},
|
||||||
|
{1205, nullptr, "SetButtonConfigEmbeddedEnabled"},
|
||||||
|
{1206, nullptr, "IsButtonConfigEnabled"},
|
||||||
|
{1207, nullptr, "IsButtonConfigEmbeddedEnabled"},
|
||||||
|
{1208, nullptr, "SetButtonConfigEmbedded"},
|
||||||
|
{1209, nullptr, "SetButtonConfigFull"},
|
||||||
|
{1210, nullptr, "SetButtonConfigLeft"},
|
||||||
|
{1211, nullptr, "SetButtonConfigRight"},
|
||||||
|
{1212, nullptr, "GetButtonConfigEmbedded"},
|
||||||
|
{1213, nullptr, "GetButtonConfigFull"},
|
||||||
|
{1214, nullptr, "GetButtonConfigLeft"},
|
||||||
|
{1215, nullptr, "GetButtonConfigRight"},
|
||||||
|
{1250, nullptr, "IsCustomButtonConfigSupported"},
|
||||||
|
{1251, nullptr, "IsDefaultButtonConfigEmbedded"},
|
||||||
|
{1252, nullptr, "IsDefaultButtonConfigFull"},
|
||||||
|
{1253, nullptr, "IsDefaultButtonConfigLeft"},
|
||||||
|
{1254, nullptr, "IsDefaultButtonConfigRight"},
|
||||||
|
{1255, nullptr, "IsButtonConfigStorageEmbeddedEmpty"},
|
||||||
|
{1256, nullptr, "IsButtonConfigStorageFullEmpty"},
|
||||||
|
{1257, nullptr, "IsButtonConfigStorageLeftEmpty"},
|
||||||
|
{1258, nullptr, "IsButtonConfigStorageRightEmpty"},
|
||||||
|
{1259, nullptr, "GetButtonConfigStorageEmbeddedDeprecated"},
|
||||||
|
{1260, nullptr, "GetButtonConfigStorageFullDeprecated"},
|
||||||
|
{1261, nullptr, "GetButtonConfigStorageLeftDeprecated"},
|
||||||
|
{1262, nullptr, "GetButtonConfigStorageRightDeprecated"},
|
||||||
|
{1263, nullptr, "SetButtonConfigStorageEmbeddedDeprecated"},
|
||||||
|
{1264, nullptr, "SetButtonConfigStorageFullDeprecated"},
|
||||||
|
{1265, nullptr, "SetButtonConfigStorageLeftDeprecated"},
|
||||||
|
{1266, nullptr, "SetButtonConfigStorageRightDeprecated"},
|
||||||
|
{1267, nullptr, "DeleteButtonConfigStorageEmbedded"},
|
||||||
|
{1268, nullptr, "DeleteButtonConfigStorageFull"},
|
||||||
|
{1269, nullptr, "DeleteButtonConfigStorageLeft"},
|
||||||
|
{1270, nullptr, "DeleteButtonConfigStorageRight"},
|
||||||
|
{1271, nullptr, "IsUsingCustomButtonConfig"},
|
||||||
|
{1272, nullptr, "IsAnyCustomButtonConfigEnabled"},
|
||||||
|
{1273, nullptr, "SetAllCustomButtonConfigEnabled"},
|
||||||
|
{1274, nullptr, "SetDefaultButtonConfig"},
|
||||||
|
{1275, nullptr, "SetAllDefaultButtonConfig"},
|
||||||
|
{1276, nullptr, "SetHidButtonConfigEmbedded"},
|
||||||
|
{1277, nullptr, "SetHidButtonConfigFull"},
|
||||||
|
{1278, nullptr, "SetHidButtonConfigLeft"},
|
||||||
|
{1279, nullptr, "SetHidButtonConfigRight"},
|
||||||
|
{1280, nullptr, "GetHidButtonConfigEmbedded"},
|
||||||
|
{1281, nullptr, "GetHidButtonConfigFull"},
|
||||||
|
{1282, nullptr, "GetHidButtonConfigLeft"},
|
||||||
|
{1283, nullptr, "GetHidButtonConfigRight"},
|
||||||
|
{1284, nullptr, "GetButtonConfigStorageEmbedded"},
|
||||||
|
{1285, nullptr, "GetButtonConfigStorageFull"},
|
||||||
|
{1286, nullptr, "GetButtonConfigStorageLeft"},
|
||||||
|
{1287, nullptr, "GetButtonConfigStorageRight"},
|
||||||
|
{1288, nullptr, "SetButtonConfigStorageEmbedded"},
|
||||||
|
{1289, nullptr, "SetButtonConfigStorageFull"},
|
||||||
|
{1290, nullptr, "DeleteButtonConfigStorageRight"},
|
||||||
|
{1291, nullptr, "DeleteButtonConfigStorageRight"},
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RegisterHandlers(functions);
|
||||||
|
}
|
||||||
|
|
||||||
|
IHidSystemServer::~IHidSystemServer() = default;
|
||||||
|
|
||||||
|
void IHidSystemServer::ApplyNpadSystemCommonPolicy(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
|
||||||
|
LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
|
||||||
|
|
||||||
|
GetResourceManager()->GetNpad()->ApplyNpadSystemCommonPolicy(applet_resource_user_id);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidSystemServer::EnableAssigningSingleOnSlSrPress(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
|
||||||
|
LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
|
||||||
|
|
||||||
|
GetResourceManager()->GetNpad()->AssigningSingleOnSlSrPress(applet_resource_user_id, true);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidSystemServer::DisableAssigningSingleOnSlSrPress(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
|
||||||
|
LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
|
||||||
|
|
||||||
|
GetResourceManager()->GetNpad()->AssigningSingleOnSlSrPress(applet_resource_user_id, false);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidSystemServer::GetLastActiveNpad(HLERequestContext& ctx) {
|
||||||
|
NpadIdType npad_id{};
|
||||||
|
const Result result = GetResourceManager()->GetNpad()->GetLastActiveNpad(npad_id);
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(result);
|
||||||
|
// rb.PushEnum(ResultSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidSystemServer::ApplyNpadSystemCommonPolicyFull(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
|
||||||
|
LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
|
||||||
|
|
||||||
|
GetResourceManager()->GetNpad()->ApplyNpadSystemCommonPolicyFull(applet_resource_user_id);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidSystemServer::GetMaskedSupportedNpadStyleSet(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
|
||||||
|
LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
|
||||||
|
|
||||||
|
NpadStyleSet supported_styleset{};
|
||||||
|
const auto& npad = GetResourceManager()->GetNpad();
|
||||||
|
const Result result =
|
||||||
|
npad->GetMaskedSupportedNpadStyleSet(applet_resource_user_id, supported_styleset);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(result);
|
||||||
|
rb.PushEnum(supported_styleset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidSystemServer::SetSupportedNpadStyleSetAll(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
|
||||||
|
|
||||||
|
const auto& npad = GetResourceManager()->GetNpad();
|
||||||
|
const auto result = npad->SetSupportedNpadStyleSet(applet_resource_user_id, NpadStyleSet::All);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidSystemServer::GetNpadCaptureButtonAssignment(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
|
||||||
|
|
||||||
|
const auto size = ctx.GetWriteBufferNumElements<NpadButton>();
|
||||||
|
std::vector<NpadButton> button_assignment(size);
|
||||||
|
const auto& npad = GetResourceManager()->GetNpad();
|
||||||
|
const auto reply_size =
|
||||||
|
npad->GetNpadCaptureButtonAssignment(applet_resource_user_id, button_assignment);
|
||||||
|
|
||||||
|
ctx.WriteBuffer(button_assignment);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.Push(reply_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidSystemServer::SetVibrationMasterVolume(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto volume{rp.Pop<float>()};
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_HID, "called, volume={}", volume);
|
||||||
|
|
||||||
|
const Result result = GetResourceManager()->GetNpad()->SetVibrationMasterVolume(volume);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidSystemServer::GetVibrationMasterVolume(HLERequestContext& ctx) {
|
||||||
|
float volume{};
|
||||||
|
const Result result = GetResourceManager()->GetNpad()->GetVibrationMasterVolume(volume);
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_HID, "called, volume={}", volume);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(result);
|
||||||
|
rb.Push(volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidSystemServer::SetTouchScreenDefaultConfiguration(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
auto touch_screen_configuration{rp.PopRaw<TouchScreenConfigurationForNx>()};
|
||||||
|
|
||||||
|
LOG_WARNING(Service_HID, "(STUBBED) called, mode={}", touch_screen_configuration.mode);
|
||||||
|
|
||||||
|
switch (touch_screen_configuration.mode) {
|
||||||
|
case TouchScreenModeForNx::UseSystemSetting:
|
||||||
|
case TouchScreenModeForNx::Finger:
|
||||||
|
case TouchScreenModeForNx::Heat2:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
touch_screen_configuration.mode = TouchScreenModeForNx::UseSystemSetting;
|
||||||
|
} /*
|
||||||
|
|
||||||
|
const Result result = GetResourceManager()->GetTouchScreen()->SetTouchScreenConfiguration(
|
||||||
|
touch_screen_configuration);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHidSystemServer::GetTouchScreenDefaultConfiguration(HLERequestContext& ctx) {
|
||||||
|
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||||
|
|
||||||
|
// TouchScreenConfigurationForNx touch_screen_configuration{};
|
||||||
|
// const Result result = GetResourceManager()->GetTouchScreen()->GetDefaultConfiguration(
|
||||||
|
// touch_screen_configuration.mode);
|
||||||
|
|
||||||
|
// switch (touch_screen_configuration.mode) {
|
||||||
|
// case TouchScreenModeForNx::UseSystemSetting:
|
||||||
|
// case TouchScreenModeForNx::Finger:
|
||||||
|
// case TouchScreenModeForNx::Heat2:
|
||||||
|
// break;
|
||||||
|
// default:
|
||||||
|
// touch_screen_configuration.mode = TouchScreenModeForNx::UseSystemSetting;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// IPC::ResponseBuilder rb{ctx, 6};
|
||||||
|
// rb.Push(ResultSuccess);
|
||||||
|
// rb.PushRaw(touch_screen_configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<ResourceManager> IHidSystemServer::GetResourceManager() {
|
||||||
|
resource_manager->VerifiyInitalization();
|
||||||
|
return resource_manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::HID
|
|
@ -0,0 +1,39 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Service::HID {
|
||||||
|
class ResourceManager;
|
||||||
|
|
||||||
|
class IHidSystemServer final : public ServiceFramework<IHidSystemServer> {
|
||||||
|
public:
|
||||||
|
explicit IHidSystemServer(Core::System& system_, std::shared_ptr<ResourceManager> resource);
|
||||||
|
~IHidSystemServer() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void ApplyNpadSystemCommonPolicy(HLERequestContext& ctx);
|
||||||
|
void EnableAssigningSingleOnSlSrPress(HLERequestContext& ctx);
|
||||||
|
void DisableAssigningSingleOnSlSrPress(HLERequestContext& ctx);
|
||||||
|
void GetLastActiveNpad(HLERequestContext& ctx);
|
||||||
|
void ApplyNpadSystemCommonPolicyFull(HLERequestContext& ctx);
|
||||||
|
void GetMaskedSupportedNpadStyleSet(HLERequestContext& ctx);
|
||||||
|
void SetSupportedNpadStyleSetAll(HLERequestContext& ctx);
|
||||||
|
void GetNpadCaptureButtonAssignment(HLERequestContext& ctx);
|
||||||
|
void SetVibrationMasterVolume(HLERequestContext& ctx);
|
||||||
|
void GetVibrationMasterVolume(HLERequestContext& ctx);
|
||||||
|
void SetTouchScreenDefaultConfiguration(HLERequestContext& ctx);
|
||||||
|
void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx);
|
||||||
|
|
||||||
|
std::shared_ptr<ResourceManager> GetResourceManager();
|
||||||
|
|
||||||
|
std::shared_ptr<ResourceManager> resource_manager = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::HID
|
|
@ -1,21 +1,33 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
#include "common/bit_field.h"
|
#include "common/bit_field.h"
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/point.h"
|
#include "common/point.h"
|
||||||
#include "common/uuid.h"
|
#include "common/uuid.h"
|
||||||
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
namespace Core::HID {
|
namespace Service::HID {
|
||||||
|
|
||||||
enum class DeviceIndex : u8 {
|
enum class DeviceIndex : u8 {
|
||||||
Left = 0,
|
Left = 0,
|
||||||
Right = 1,
|
Right = 1,
|
||||||
None = 2,
|
None = 2,
|
||||||
MaxDeviceIndex = 3,
|
MaxDeviceIndex = 3,
|
||||||
|
MaxDeviceInfo = None,
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is nn::hid::NpadCommunicationMode
|
||||||
|
enum class NpadCommunicationMode : u64 {
|
||||||
|
Mode_5ms = 0,
|
||||||
|
Mode_10ms = 1,
|
||||||
|
Mode_15ms = 2,
|
||||||
|
Default = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
// This is nn::hid::NpadButton
|
// This is nn::hid::NpadButton
|
||||||
|
@ -218,10 +230,18 @@ enum class NpadIdType : u32 {
|
||||||
Invalid = 0xFFFFFFFF,
|
Invalid = 0xFFFFFFFF,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class NpadRevision : u32 {
|
||||||
|
Revision0 = 0,
|
||||||
|
Revision1 = 1,
|
||||||
|
Revision2 = 2,
|
||||||
|
Revision3 = 3,
|
||||||
|
};
|
||||||
|
static_assert(sizeof(NpadRevision) == 4, "NpadRevision is an invalid size");
|
||||||
|
|
||||||
// This is nn::hid::NpadStyleIndex
|
// This is nn::hid::NpadStyleIndex
|
||||||
enum class NpadStyleIndex : u8 {
|
enum class NpadStyleIndex : u8 {
|
||||||
None = 0,
|
None = 0,
|
||||||
ProController = 3,
|
FullKey = 3,
|
||||||
Handheld = 4,
|
Handheld = 4,
|
||||||
HandheldNES = 4,
|
HandheldNES = 4,
|
||||||
JoyconDual = 5,
|
JoyconDual = 5,
|
||||||
|
@ -258,6 +278,7 @@ enum class NpadStyleSet : u32 {
|
||||||
|
|
||||||
All = 0xFFFFFFFFU,
|
All = 0xFFFFFFFFU,
|
||||||
};
|
};
|
||||||
|
DECLARE_ENUM_FLAG_OPERATORS(NpadStyleSet);
|
||||||
static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size");
|
static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size");
|
||||||
|
|
||||||
// This is nn::hid::VibrationDevicePosition
|
// This is nn::hid::VibrationDevicePosition
|
||||||
|
@ -282,6 +303,12 @@ enum class VibrationGcErmCommand : u64 {
|
||||||
StopHard = 2,
|
StopHard = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// This is nn::hid::debug::AccelerometerPlayMode
|
||||||
|
enum class AccelerometerPlayMode : u32 {
|
||||||
|
Loose = 0,
|
||||||
|
Tight = 1,
|
||||||
|
};
|
||||||
|
|
||||||
// This is nn::hid::GyroscopeZeroDriftMode
|
// This is nn::hid::GyroscopeZeroDriftMode
|
||||||
enum class GyroscopeZeroDriftMode : u32 {
|
enum class GyroscopeZeroDriftMode : u32 {
|
||||||
Loose = 0,
|
Loose = 0,
|
||||||
|
@ -289,17 +316,24 @@ enum class GyroscopeZeroDriftMode : u32 {
|
||||||
Tight = 2,
|
Tight = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
// This is nn::settings::system::TouchScreenMode
|
// This is nn::hid::NpadJoyDeviceType
|
||||||
enum class TouchScreenMode : u32 {
|
enum class NpadJoyDeviceType : s64 {
|
||||||
Stylus = 0,
|
Left = 0,
|
||||||
Standard = 1,
|
Right = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
// This is nn::hid::TouchScreenModeForNx
|
// This is nn::hid::NpadJoyAssignmentMode
|
||||||
enum class TouchScreenModeForNx : u8 {
|
enum class NpadJoyAssignmentMode : u32 {
|
||||||
UseSystemSetting,
|
Dual = 0,
|
||||||
Finger,
|
Single = 1,
|
||||||
Heat2,
|
};
|
||||||
|
|
||||||
|
// This is nn::hid::NpadHandheldActivationMode
|
||||||
|
enum class NpadHandheldActivationMode : u64 {
|
||||||
|
Dual = 0,
|
||||||
|
Single = 1,
|
||||||
|
None = 2,
|
||||||
|
MaxActivationMode = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
// This is nn::hid::NpadStyleTag
|
// This is nn::hid::NpadStyleTag
|
||||||
|
@ -322,9 +356,153 @@ struct NpadStyleTag {
|
||||||
BitField<29, 1, u32> system_ext;
|
BitField<29, 1, u32> system_ext;
|
||||||
BitField<30, 1, u32> system;
|
BitField<30, 1, u32> system;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
NpadStyleTag() {
|
||||||
|
raw = NpadStyleSet::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
NpadStyleTag(NpadStyleSet style_set) {
|
||||||
|
raw = style_set;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
static_assert(sizeof(NpadStyleTag) == 4, "NpadStyleTag is an invalid size");
|
static_assert(sizeof(NpadStyleTag) == 4, "NpadStyleTag is an invalid size");
|
||||||
|
|
||||||
|
// This is nn::hid::NpadJoyHoldType
|
||||||
|
enum class NpadJoyHoldType : u64 {
|
||||||
|
Vertical = 0,
|
||||||
|
Horizontal = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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 = 1,
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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::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,
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is nn::hid::DebugPadAttribute
|
||||||
|
enum class DebugPadAttribute : u32 {
|
||||||
|
IsConnected = 1 << 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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::TouchAttribute
|
// This is nn::hid::TouchAttribute
|
||||||
struct TouchAttribute {
|
struct TouchAttribute {
|
||||||
union {
|
union {
|
||||||
|
@ -335,6 +513,20 @@ struct TouchAttribute {
|
||||||
};
|
};
|
||||||
static_assert(sizeof(TouchAttribute) == 0x4, "TouchAttribute is an invalid size");
|
static_assert(sizeof(TouchAttribute) == 0x4, "TouchAttribute 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::TouchState
|
// This is nn::hid::TouchState
|
||||||
struct TouchState {
|
struct TouchState {
|
||||||
u64 delta_time{};
|
u64 delta_time{};
|
||||||
|
@ -347,14 +539,6 @@ struct TouchState {
|
||||||
};
|
};
|
||||||
static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size");
|
static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size");
|
||||||
|
|
||||||
// This is nn::hid::TouchScreenConfigurationForNx
|
|
||||||
struct TouchScreenConfigurationForNx {
|
|
||||||
TouchScreenModeForNx mode{TouchScreenModeForNx::UseSystemSetting};
|
|
||||||
INSERT_PADDING_BYTES(0xF);
|
|
||||||
};
|
|
||||||
static_assert(sizeof(TouchScreenConfigurationForNx) == 0x10,
|
|
||||||
"TouchScreenConfigurationForNx is an invalid size");
|
|
||||||
|
|
||||||
struct NpadColor {
|
struct NpadColor {
|
||||||
u8 r{};
|
u8 r{};
|
||||||
u8 g{};
|
u8 g{};
|
||||||
|
@ -509,6 +693,16 @@ struct DebugPadButton {
|
||||||
};
|
};
|
||||||
static_assert(sizeof(DebugPadButton) == 0x4, "DebugPadButton is an invalid size");
|
static_assert(sizeof(DebugPadButton) == 0x4, "DebugPadButton is an invalid size");
|
||||||
|
|
||||||
|
// This is nn::hid::debug::DebugPadAutoPilotState
|
||||||
|
struct DebugPadAutoPilotState {
|
||||||
|
DebugPadAttribute attribute;
|
||||||
|
DebugPadButton buttons;
|
||||||
|
AnalogStickState stick_l;
|
||||||
|
AnalogStickState stick_r;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(DebugPadAutoPilotState) == 0x18, "DebugPadAutoPilotState is an invalid size");
|
||||||
|
|
||||||
|
|
||||||
// This is nn::hid::ConsoleSixAxisSensorHandle
|
// This is nn::hid::ConsoleSixAxisSensorHandle
|
||||||
struct ConsoleSixAxisSensorHandle {
|
struct ConsoleSixAxisSensorHandle {
|
||||||
u8 unknown_1{};
|
u8 unknown_1{};
|
||||||
|
@ -529,12 +723,36 @@ static_assert(sizeof(SixAxisSensorHandle) == 4, "SixAxisSensorHandle is an inval
|
||||||
|
|
||||||
// These parameters seem related to how much gyro/accelerometer is used
|
// These parameters seem related to how much gyro/accelerometer is used
|
||||||
struct SixAxisSensorFusionParameters {
|
struct SixAxisSensorFusionParameters {
|
||||||
f32 parameter1{0.03f}; // Range 0.0 to 1.0, default 0.03
|
f32 parameter1{};
|
||||||
f32 parameter2{0.4f}; // Default 0.4
|
f32 parameter2{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(SixAxisSensorFusionParameters) == 8,
|
static_assert(sizeof(SixAxisSensorFusionParameters) == 8,
|
||||||
"SixAxisSensorFusionParameters is an invalid size");
|
"SixAxisSensorFusionParameters is an invalid size");
|
||||||
|
|
||||||
|
// These parameters seem related to how much gyro/accelerometer is used
|
||||||
|
struct SixAxisSensorShiftAccelerometerCalibration {
|
||||||
|
f32 calibration1{};
|
||||||
|
f32 calibration2{};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(SixAxisSensorShiftAccelerometerCalibration) == 8,
|
||||||
|
"SixAxisSensorShiftAccelerometerCalibration is an invalid size");
|
||||||
|
|
||||||
|
// These parameters seem related to how much gyro/accelerometer is used
|
||||||
|
struct SixAxisSensorShiftGyroscopeCalibration {
|
||||||
|
f32 calibration1{};
|
||||||
|
f32 calibration2{};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(SixAxisSensorShiftGyroscopeCalibration) == 8,
|
||||||
|
"SixAxisSensorShiftGyroscopeCalibration is an invalid size");
|
||||||
|
|
||||||
|
// These parameters seem related to how much gyro/accelerometer is used
|
||||||
|
struct SixAxisAccelerometerParameters {
|
||||||
|
f32 parameter1{};
|
||||||
|
f32 parameter2{};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(SixAxisAccelerometerParameters) == 8,
|
||||||
|
"SixAxisSensorFusionParameters is an invalid size");
|
||||||
|
|
||||||
// This is nn::hid::server::SixAxisSensorProperties
|
// This is nn::hid::server::SixAxisSensorProperties
|
||||||
struct SixAxisSensorProperties {
|
struct SixAxisSensorProperties {
|
||||||
union {
|
union {
|
||||||
|
@ -580,7 +798,7 @@ static_assert(sizeof(SixAxisSensorIcInformation) == 0xC8,
|
||||||
|
|
||||||
// This is nn::hid::VibrationDeviceHandle
|
// This is nn::hid::VibrationDeviceHandle
|
||||||
struct VibrationDeviceHandle {
|
struct VibrationDeviceHandle {
|
||||||
NpadStyleIndex npad_type{NpadStyleIndex::None};
|
NpadStyleIndex npad_style_index{NpadStyleIndex::None};
|
||||||
u8 npad_id{};
|
u8 npad_id{};
|
||||||
DeviceIndex device_index{DeviceIndex::None};
|
DeviceIndex device_index{DeviceIndex::None};
|
||||||
INSERT_PADDING_BYTES_NOINIT(1);
|
INSERT_PADDING_BYTES_NOINIT(1);
|
||||||
|
@ -645,6 +863,16 @@ struct KeyboardKey {
|
||||||
};
|
};
|
||||||
static_assert(sizeof(KeyboardKey) == 0x20, "KeyboardKey is an invalid size");
|
static_assert(sizeof(KeyboardKey) == 0x20, "KeyboardKey is an invalid size");
|
||||||
|
|
||||||
|
// This is nn::hid::debug::KeyboardAutoPilotState
|
||||||
|
struct KeyboardAutoPilotState {
|
||||||
|
KeyboardModifier modifier{};
|
||||||
|
INSERT_PADDING_BYTES(0x4);
|
||||||
|
KeyboardKey keys{};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(KeyboardAutoPilotState) == 0x28, "KeyboardAutoPilotState is an invalid size");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// This is nn::hid::MouseButton
|
// This is nn::hid::MouseButton
|
||||||
struct MouseButton {
|
struct MouseButton {
|
||||||
union {
|
union {
|
||||||
|
@ -683,65 +911,101 @@ struct MouseState {
|
||||||
};
|
};
|
||||||
static_assert(sizeof(MouseState) == 0x28, "MouseState is an invalid size");
|
static_assert(sizeof(MouseState) == 0x28, "MouseState is an invalid size");
|
||||||
|
|
||||||
struct UniquePadId {
|
// This is nn::hid::debug::MouseAutoPilotState
|
||||||
u64 id;
|
struct MouseAutoPilotState {
|
||||||
|
s32 x{};
|
||||||
|
s32 y{};
|
||||||
|
s32 delta_x{};
|
||||||
|
s32 delta_y{};
|
||||||
|
s32 delta_wheel{};
|
||||||
|
MouseButton button{};
|
||||||
|
MouseAttribute attribute{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(UniquePadId) == 0x8, "UniquePadId is an invalid size");
|
static_assert(sizeof(MouseAutoPilotState) == 0x1c, "MouseAutoPilotState is an invalid size");
|
||||||
|
|
||||||
/// Converts a NpadIdType to an array index.
|
// This is nn::hid::PalmaOperationType
|
||||||
constexpr size_t NpadIdTypeToIndex(NpadIdType npad_id_type) {
|
enum class PalmaOperationType : u32 {
|
||||||
switch (npad_id_type) {
|
PlayActivity,
|
||||||
case NpadIdType::Player1:
|
SetFrModeType,
|
||||||
return 0;
|
ReadStep,
|
||||||
case NpadIdType::Player2:
|
EnableStep,
|
||||||
return 1;
|
ResetStep,
|
||||||
case NpadIdType::Player3:
|
ReadApplicationSection,
|
||||||
return 2;
|
WriteApplicationSection,
|
||||||
case NpadIdType::Player4:
|
ReadUniqueCode,
|
||||||
return 3;
|
SetUniqueCodeInvalid,
|
||||||
case NpadIdType::Player5:
|
WriteActivityEntry,
|
||||||
return 4;
|
WriteRgbLedPatternEntry,
|
||||||
case NpadIdType::Player6:
|
WriteWaveEntry,
|
||||||
return 5;
|
ReadDataBaseIdentificationVersion,
|
||||||
case NpadIdType::Player7:
|
WriteDataBaseIdentificationVersion,
|
||||||
return 6;
|
SuspendFeature,
|
||||||
case NpadIdType::Player8:
|
ReadPlayLog,
|
||||||
return 7;
|
ResetPlayLog,
|
||||||
case NpadIdType::Handheld:
|
};
|
||||||
return 8;
|
|
||||||
case NpadIdType::Other:
|
|
||||||
return 9;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts an array index to a NpadIdType
|
// This is nn::hid::PalmaWaveSet
|
||||||
constexpr NpadIdType IndexToNpadIdType(size_t index) {
|
enum class PalmaWaveSet : u64 {
|
||||||
switch (index) {
|
Small,
|
||||||
case 0:
|
Medium,
|
||||||
return NpadIdType::Player1;
|
Large,
|
||||||
case 1:
|
};
|
||||||
return NpadIdType::Player2;
|
|
||||||
case 2:
|
|
||||||
return NpadIdType::Player3;
|
|
||||||
case 3:
|
|
||||||
return NpadIdType::Player4;
|
|
||||||
case 4:
|
|
||||||
return NpadIdType::Player5;
|
|
||||||
case 5:
|
|
||||||
return NpadIdType::Player6;
|
|
||||||
case 6:
|
|
||||||
return NpadIdType::Player7;
|
|
||||||
case 7:
|
|
||||||
return NpadIdType::Player8;
|
|
||||||
case 8:
|
|
||||||
return NpadIdType::Handheld;
|
|
||||||
case 9:
|
|
||||||
return NpadIdType::Other;
|
|
||||||
default:
|
|
||||||
return NpadIdType::Invalid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Core::HID
|
// 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,
|
||||||
|
};
|
||||||
|
|
||||||
|
using PalmaOperationData = std::array<u8, 0x140>;
|
||||||
|
|
||||||
|
// This is nn::hid::PalmaOperationInfo
|
||||||
|
struct PalmaOperationInfo {
|
||||||
|
PalmaOperationType operation;
|
||||||
|
Result result;
|
||||||
|
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 {
|
||||||
|
NpadIdType npad_id;
|
||||||
|
INSERT_PADDING_BYTES(4);
|
||||||
|
};
|
||||||
|
static_assert(sizeof(PalmaConnectionHandle) == 0x8, "PalmaConnectionHandle has incorrect size.");
|
||||||
|
|
||||||
|
// This is nn::hid::TouchScreenModeForNx
|
||||||
|
enum class TouchScreenModeForNx : u8 {
|
||||||
|
UseSystemSetting,
|
||||||
|
Finger,
|
||||||
|
Heat2,
|
||||||
|
};
|
||||||
|
// This is nn::hid::TouchScreenConfigurationForNx
|
||||||
|
struct TouchScreenConfigurationForNx {
|
||||||
|
TouchScreenModeForNx mode{TouchScreenModeForNx::UseSystemSetting};
|
||||||
|
INSERT_PADDING_BYTES(0xF);
|
||||||
|
};
|
||||||
|
static_assert(sizeof(TouchScreenConfigurationForNx) == 0x10,
|
||||||
|
"TouchScreenConfigurationForNx has incorrect size.");
|
||||||
|
|
||||||
|
} // namespace Service::HID
|
|
@ -0,0 +1,132 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/service/hid/hid_result.h"
|
||||||
|
#include "core/hle/service/hid/hid_types.h"
|
||||||
|
|
||||||
|
namespace Service::HID {
|
||||||
|
|
||||||
|
constexpr bool IsNpadIdValid(const NpadIdType npad_id) {
|
||||||
|
switch (npad_id) {
|
||||||
|
case NpadIdType::Player1:
|
||||||
|
case NpadIdType::Player2:
|
||||||
|
case NpadIdType::Player3:
|
||||||
|
case NpadIdType::Player4:
|
||||||
|
case NpadIdType::Player5:
|
||||||
|
case NpadIdType::Player6:
|
||||||
|
case NpadIdType::Player7:
|
||||||
|
case NpadIdType::Player8:
|
||||||
|
case NpadIdType::Other:
|
||||||
|
case NpadIdType::Handheld:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr Result IsVibrationHandleValid(const VibrationDeviceHandle& handle) {
|
||||||
|
switch (handle.npad_style_index) {
|
||||||
|
case NpadStyleIndex::FullKey:
|
||||||
|
case NpadStyleIndex::Handheld:
|
||||||
|
case NpadStyleIndex::JoyconDual:
|
||||||
|
case NpadStyleIndex::JoyconLeft:
|
||||||
|
case NpadStyleIndex::JoyconRight:
|
||||||
|
case NpadStyleIndex::GameCube:
|
||||||
|
case NpadStyleIndex::N64:
|
||||||
|
case NpadStyleIndex::SystemExt:
|
||||||
|
case NpadStyleIndex::System:
|
||||||
|
// These support vibration
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return ResultVibrationInvalidStyleIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsNpadIdValid(static_cast<NpadIdType>(handle.npad_id))) {
|
||||||
|
return ResultVibrationInvalidNpadId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handle.device_index >= DeviceIndex::MaxDeviceInfo) {
|
||||||
|
return ResultVibrationDeviceIndexOutOfRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts a NpadIdType to an array index.
|
||||||
|
constexpr size_t NpadIdTypeToIndex(NpadIdType npad_id_type) {
|
||||||
|
switch (npad_id_type) {
|
||||||
|
case NpadIdType::Player1:
|
||||||
|
return 0;
|
||||||
|
case NpadIdType::Player2:
|
||||||
|
return 1;
|
||||||
|
case NpadIdType::Player3:
|
||||||
|
return 2;
|
||||||
|
case NpadIdType::Player4:
|
||||||
|
return 3;
|
||||||
|
case NpadIdType::Player5:
|
||||||
|
return 4;
|
||||||
|
case NpadIdType::Player6:
|
||||||
|
return 5;
|
||||||
|
case NpadIdType::Player7:
|
||||||
|
return 6;
|
||||||
|
case NpadIdType::Player8:
|
||||||
|
return 7;
|
||||||
|
case NpadIdType::Handheld:
|
||||||
|
return 8;
|
||||||
|
case NpadIdType::Other:
|
||||||
|
return 9;
|
||||||
|
default:
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts an array index to a NpadIdType
|
||||||
|
constexpr NpadIdType IndexToNpadIdType(size_t index) {
|
||||||
|
switch (index) {
|
||||||
|
case 0:
|
||||||
|
return NpadIdType::Player1;
|
||||||
|
case 1:
|
||||||
|
return NpadIdType::Player2;
|
||||||
|
case 2:
|
||||||
|
return NpadIdType::Player3;
|
||||||
|
case 3:
|
||||||
|
return NpadIdType::Player4;
|
||||||
|
case 4:
|
||||||
|
return NpadIdType::Player5;
|
||||||
|
case 5:
|
||||||
|
return NpadIdType::Player6;
|
||||||
|
case 6:
|
||||||
|
return NpadIdType::Player7;
|
||||||
|
case 7:
|
||||||
|
return NpadIdType::Player8;
|
||||||
|
case 8:
|
||||||
|
return NpadIdType::Handheld;
|
||||||
|
case 9:
|
||||||
|
return NpadIdType::Other;
|
||||||
|
default:
|
||||||
|
return NpadIdType::Invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr NpadStyleSet GetStylesetByIndex(std::size_t index) {
|
||||||
|
switch (index) {
|
||||||
|
case 0:
|
||||||
|
return NpadStyleSet::Fullkey;
|
||||||
|
case 1:
|
||||||
|
return NpadStyleSet::Handheld;
|
||||||
|
case 2:
|
||||||
|
return NpadStyleSet::JoyDual;
|
||||||
|
case 3:
|
||||||
|
return NpadStyleSet::JoyLeft;
|
||||||
|
case 4:
|
||||||
|
return NpadStyleSet::JoyRight;
|
||||||
|
case 5:
|
||||||
|
return NpadStyleSet::Palma;
|
||||||
|
default:
|
||||||
|
return NpadStyleSet::None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::HID
|
|
@ -1,523 +1,35 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include "common/logging/log.h"
|
|
||||||
#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.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/ipc_helpers.h"
|
||||||
#include "core/hle/service/service.h"
|
|
||||||
#include "core/memory.h"
|
|
||||||
|
|
||||||
namespace Service::HID {
|
namespace Service::HID {
|
||||||
// (15ms, 66Hz)
|
|
||||||
constexpr auto hidbus_update_ns = std::chrono::nanoseconds{15 * 1000 * 1000};
|
|
||||||
|
|
||||||
HidBus::HidBus(Core::System& system_)
|
IHidbusServer::IHidbusServer(Core::System& system_) : ServiceFramework{system_, "hidbus"} {
|
||||||
: ServiceFramework{system_, "hidbus"}, service_context{system_, service_name} {
|
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{1, &HidBus::GetBusHandle, "GetBusHandle"},
|
{1, nullptr, "GetBusHandle"},
|
||||||
{2, &HidBus::IsExternalDeviceConnected, "IsExternalDeviceConnected"},
|
{2, nullptr, "IsExternalDeviceConnected"},
|
||||||
{3, &HidBus::Initialize, "Initialize"},
|
{3, nullptr, "Initialize"},
|
||||||
{4, &HidBus::Finalize, "Finalize"},
|
{4, nullptr, "Finalize"},
|
||||||
{5, &HidBus::EnableExternalDevice, "EnableExternalDevice"},
|
{5, nullptr, "EnableExternalDevice"},
|
||||||
{6, &HidBus::GetExternalDeviceId, "GetExternalDeviceId"},
|
{6, nullptr, "GetExternalDeviceId"},
|
||||||
{7, &HidBus::SendCommandAsync, "SendCommandAsync"},
|
{7, nullptr, "SendCommandAsync"},
|
||||||
{8, &HidBus::GetSendCommandAsynceResult, "GetSendCommandAsynceResult"},
|
{8, nullptr, "GetSendCommandAsynceResult"},
|
||||||
{9, &HidBus::SetEventForSendCommandAsycResult, "SetEventForSendCommandAsycResult"},
|
{9, nullptr, "SetEventForSendCommandAsycResult"},
|
||||||
{10, &HidBus::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
|
{10, nullptr, "GetSharedMemoryHandle"},
|
||||||
{11, &HidBus::EnableJoyPollingReceiveMode, "EnableJoyPollingReceiveMode"},
|
{11, nullptr, "EnableJoyPollingReceiveMode"},
|
||||||
{12, &HidBus::DisableJoyPollingReceiveMode, "DisableJoyPollingReceiveMode"},
|
{12, nullptr, "DisableJoyPollingReceiveMode"},
|
||||||
{13, nullptr, "GetPollingData"},
|
{13, nullptr, "GetPollingData"},
|
||||||
{14, &HidBus::SetStatusManagerType, "SetStatusManagerType"},
|
{14, nullptr, "SetStatusManagerType"},
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
|
|
||||||
// Register update callbacks
|
|
||||||
hidbus_update_event = Core::Timing::CreateEvent(
|
|
||||||
"Hidbus::UpdateCallback",
|
|
||||||
[this](std::uintptr_t user_data, s64 time,
|
|
||||||
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
|
||||||
const auto guard = LockService();
|
|
||||||
UpdateHidbus(user_data, ns_late);
|
|
||||||
return std::nullopt;
|
|
||||||
});
|
|
||||||
|
|
||||||
system_.CoreTiming().ScheduleLoopingEvent(hidbus_update_ns, hidbus_update_ns,
|
|
||||||
hidbus_update_event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HidBus::~HidBus() {
|
IHidbusServer::~IHidbusServer() = default;
|
||||||
system.CoreTiming().UnscheduleEvent(hidbus_update_event, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HidBus::UpdateHidbus(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
|
} // namespace Service::HID
|
||||||
if (is_hidbus_enabled) {
|
|
||||||
for (std::size_t i = 0; i < devices.size(); ++i) {
|
|
||||||
if (!devices[i].is_device_initializated) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto& device = devices[i].device;
|
|
||||||
device->OnUpdate();
|
|
||||||
auto& cur_entry = hidbus_status.entries[devices[i].handle.internal_index];
|
|
||||||
cur_entry.is_polling_mode = device->IsPollingMode();
|
|
||||||
cur_entry.polling_mode = device->GetPollingMode();
|
|
||||||
cur_entry.is_enabled = device->IsEnabled();
|
|
||||||
|
|
||||||
u8* shared_memory = system.Kernel().GetHidBusSharedMem().GetPointer();
|
|
||||||
std::memcpy(shared_memory + (i * sizeof(HidbusStatusManagerEntry)), &hidbus_status,
|
|
||||||
sizeof(HidbusStatusManagerEntry));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<std::size_t> HidBus::GetDeviceIndexFromHandle(BusHandle handle) const {
|
|
||||||
for (std::size_t i = 0; i < devices.size(); ++i) {
|
|
||||||
const auto& device_handle = devices[i].handle;
|
|
||||||
if (handle.abstracted_pad_id == device_handle.abstracted_pad_id &&
|
|
||||||
handle.internal_index == device_handle.internal_index &&
|
|
||||||
handle.player_number == device_handle.player_number &&
|
|
||||||
handle.bus_type_id == device_handle.bus_type_id &&
|
|
||||||
handle.is_valid == device_handle.is_valid) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HidBus::GetBusHandle(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
struct Parameters {
|
|
||||||
Core::HID::NpadIdType npad_id;
|
|
||||||
INSERT_PADDING_WORDS_NOINIT(1);
|
|
||||||
BusType bus_type;
|
|
||||||
u64 applet_resource_user_id;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
|
|
||||||
|
|
||||||
const auto parameters{rp.PopRaw<Parameters>()};
|
|
||||||
|
|
||||||
LOG_INFO(Service_HID, "called, npad_id={}, bus_type={}, applet_resource_user_id={}",
|
|
||||||
parameters.npad_id, parameters.bus_type, parameters.applet_resource_user_id);
|
|
||||||
|
|
||||||
bool is_handle_found = 0;
|
|
||||||
std::size_t handle_index = 0;
|
|
||||||
|
|
||||||
for (std::size_t i = 0; i < devices.size(); i++) {
|
|
||||||
const auto& handle = devices[i].handle;
|
|
||||||
if (!handle.is_valid) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (static_cast<Core::HID::NpadIdType>(handle.player_number) == parameters.npad_id &&
|
|
||||||
handle.bus_type_id == static_cast<u8>(parameters.bus_type)) {
|
|
||||||
is_handle_found = true;
|
|
||||||
handle_index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle not found. Create a new one
|
|
||||||
if (!is_handle_found) {
|
|
||||||
for (std::size_t i = 0; i < devices.size(); i++) {
|
|
||||||
if (devices[i].handle.is_valid) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
devices[i].handle = {
|
|
||||||
.abstracted_pad_id = static_cast<u8>(i),
|
|
||||||
.internal_index = static_cast<u8>(i),
|
|
||||||
.player_number = static_cast<u8>(parameters.npad_id),
|
|
||||||
.bus_type_id = static_cast<u8>(parameters.bus_type),
|
|
||||||
.is_valid = true,
|
|
||||||
};
|
|
||||||
handle_index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct OutData {
|
|
||||||
bool is_valid;
|
|
||||||
INSERT_PADDING_BYTES(7);
|
|
||||||
BusHandle handle;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(OutData) == 0x10, "OutData has incorrect size.");
|
|
||||||
|
|
||||||
const OutData out_data{
|
|
||||||
.is_valid = true,
|
|
||||||
.handle = devices[handle_index].handle,
|
|
||||||
};
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 6};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.PushRaw(out_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HidBus::IsExternalDeviceConnected(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto bus_handle_{rp.PopRaw<BusHandle>()};
|
|
||||||
|
|
||||||
LOG_INFO(Service_HID,
|
|
||||||
"Called, abstracted_pad_id={}, bus_type={}, internal_index={}, "
|
|
||||||
"player_number={}, is_valid={}",
|
|
||||||
bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index,
|
|
||||||
bus_handle_.player_number, bus_handle_.is_valid);
|
|
||||||
|
|
||||||
const auto device_index = GetDeviceIndexFromHandle(bus_handle_);
|
|
||||||
|
|
||||||
if (device_index) {
|
|
||||||
const auto& device = devices[device_index.value()].device;
|
|
||||||
const bool is_attached = device->IsDeviceActivated();
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.Push(is_attached);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_ERROR(Service_HID, "Invalid handle");
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultUnknown);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HidBus::Initialize(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto bus_handle_{rp.PopRaw<BusHandle>()};
|
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
|
||||||
|
|
||||||
LOG_INFO(Service_HID,
|
|
||||||
"called, abstracted_pad_id={} bus_type={} internal_index={} "
|
|
||||||
"player_number={} is_valid={}, applet_resource_user_id={}",
|
|
||||||
bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index,
|
|
||||||
bus_handle_.player_number, bus_handle_.is_valid, applet_resource_user_id);
|
|
||||||
|
|
||||||
is_hidbus_enabled = true;
|
|
||||||
|
|
||||||
const auto device_index = GetDeviceIndexFromHandle(bus_handle_);
|
|
||||||
|
|
||||||
if (device_index) {
|
|
||||||
const auto entry_index = devices[device_index.value()].handle.internal_index;
|
|
||||||
auto& cur_entry = hidbus_status.entries[entry_index];
|
|
||||||
|
|
||||||
if (bus_handle_.internal_index == 0 && Settings::values.enable_ring_controller) {
|
|
||||||
MakeDevice<RingController>(bus_handle_);
|
|
||||||
devices[device_index.value()].is_device_initializated = true;
|
|
||||||
devices[device_index.value()].device->ActivateDevice();
|
|
||||||
cur_entry.is_in_focus = true;
|
|
||||||
cur_entry.is_connected = true;
|
|
||||||
cur_entry.is_connected_result = ResultSuccess;
|
|
||||||
cur_entry.is_enabled = false;
|
|
||||||
cur_entry.is_polling_mode = false;
|
|
||||||
} else {
|
|
||||||
MakeDevice<HidbusStubbed>(bus_handle_);
|
|
||||||
devices[device_index.value()].is_device_initializated = true;
|
|
||||||
cur_entry.is_in_focus = true;
|
|
||||||
cur_entry.is_connected = false;
|
|
||||||
cur_entry.is_connected_result = ResultSuccess;
|
|
||||||
cur_entry.is_enabled = false;
|
|
||||||
cur_entry.is_polling_mode = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::memcpy(system.Kernel().GetHidBusSharedMem().GetPointer(), &hidbus_status,
|
|
||||||
sizeof(hidbus_status));
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_ERROR(Service_HID, "Invalid handle");
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultUnknown);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HidBus::Finalize(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto bus_handle_{rp.PopRaw<BusHandle>()};
|
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
|
||||||
|
|
||||||
LOG_INFO(Service_HID,
|
|
||||||
"called, abstracted_pad_id={}, bus_type={}, internal_index={}, "
|
|
||||||
"player_number={}, is_valid={}, applet_resource_user_id={}",
|
|
||||||
bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index,
|
|
||||||
bus_handle_.player_number, bus_handle_.is_valid, applet_resource_user_id);
|
|
||||||
|
|
||||||
const auto device_index = GetDeviceIndexFromHandle(bus_handle_);
|
|
||||||
|
|
||||||
if (device_index) {
|
|
||||||
const auto entry_index = devices[device_index.value()].handle.internal_index;
|
|
||||||
auto& cur_entry = hidbus_status.entries[entry_index];
|
|
||||||
auto& device = devices[device_index.value()].device;
|
|
||||||
devices[device_index.value()].is_device_initializated = false;
|
|
||||||
device->DeactivateDevice();
|
|
||||||
|
|
||||||
cur_entry.is_in_focus = true;
|
|
||||||
cur_entry.is_connected = false;
|
|
||||||
cur_entry.is_connected_result = ResultSuccess;
|
|
||||||
cur_entry.is_enabled = false;
|
|
||||||
cur_entry.is_polling_mode = false;
|
|
||||||
std::memcpy(system.Kernel().GetHidBusSharedMem().GetPointer(), &hidbus_status,
|
|
||||||
sizeof(hidbus_status));
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_ERROR(Service_HID, "Invalid handle");
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultUnknown);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HidBus::EnableExternalDevice(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
struct Parameters {
|
|
||||||
bool enable;
|
|
||||||
INSERT_PADDING_BYTES_NOINIT(7);
|
|
||||||
BusHandle bus_handle;
|
|
||||||
u64 inval;
|
|
||||||
u64 applet_resource_user_id;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(Parameters) == 0x20, "Parameters has incorrect size.");
|
|
||||||
|
|
||||||
const auto parameters{rp.PopRaw<Parameters>()};
|
|
||||||
|
|
||||||
LOG_DEBUG(Service_HID,
|
|
||||||
"called, enable={}, abstracted_pad_id={}, bus_type={}, internal_index={}, "
|
|
||||||
"player_number={}, is_valid={}, inval={}, applet_resource_user_id{}",
|
|
||||||
parameters.enable, parameters.bus_handle.abstracted_pad_id,
|
|
||||||
parameters.bus_handle.bus_type_id, parameters.bus_handle.internal_index,
|
|
||||||
parameters.bus_handle.player_number, parameters.bus_handle.is_valid, parameters.inval,
|
|
||||||
parameters.applet_resource_user_id);
|
|
||||||
|
|
||||||
const auto device_index = GetDeviceIndexFromHandle(parameters.bus_handle);
|
|
||||||
|
|
||||||
if (device_index) {
|
|
||||||
auto& device = devices[device_index.value()].device;
|
|
||||||
device->Enable(parameters.enable);
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_ERROR(Service_HID, "Invalid handle");
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultUnknown);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HidBus::GetExternalDeviceId(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto bus_handle_{rp.PopRaw<BusHandle>()};
|
|
||||||
|
|
||||||
LOG_DEBUG(Service_HID,
|
|
||||||
"called, abstracted_pad_id={}, bus_type={}, internal_index={}, player_number={}, "
|
|
||||||
"is_valid={}",
|
|
||||||
bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index,
|
|
||||||
bus_handle_.player_number, bus_handle_.is_valid);
|
|
||||||
|
|
||||||
const auto device_index = GetDeviceIndexFromHandle(bus_handle_);
|
|
||||||
|
|
||||||
if (device_index) {
|
|
||||||
const auto& device = devices[device_index.value()].device;
|
|
||||||
u32 device_id = device->GetDeviceId();
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.Push<u32>(device_id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_ERROR(Service_HID, "Invalid handle");
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultUnknown);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HidBus::SendCommandAsync(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto data = ctx.ReadBuffer();
|
|
||||||
const auto bus_handle_{rp.PopRaw<BusHandle>()};
|
|
||||||
|
|
||||||
LOG_DEBUG(Service_HID,
|
|
||||||
"called, data_size={}, abstracted_pad_id={}, bus_type={}, internal_index={}, "
|
|
||||||
"player_number={}, is_valid={}",
|
|
||||||
data.size(), bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id,
|
|
||||||
bus_handle_.internal_index, bus_handle_.player_number, bus_handle_.is_valid);
|
|
||||||
|
|
||||||
const auto device_index = GetDeviceIndexFromHandle(bus_handle_);
|
|
||||||
|
|
||||||
if (device_index) {
|
|
||||||
auto& device = devices[device_index.value()].device;
|
|
||||||
device->SetCommand(data);
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_ERROR(Service_HID, "Invalid handle");
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultUnknown);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
void HidBus::GetSendCommandAsynceResult(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto bus_handle_{rp.PopRaw<BusHandle>()};
|
|
||||||
|
|
||||||
LOG_DEBUG(Service_HID,
|
|
||||||
"called, abstracted_pad_id={}, bus_type={}, internal_index={}, player_number={}, "
|
|
||||||
"is_valid={}",
|
|
||||||
bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index,
|
|
||||||
bus_handle_.player_number, bus_handle_.is_valid);
|
|
||||||
|
|
||||||
const auto device_index = GetDeviceIndexFromHandle(bus_handle_);
|
|
||||||
|
|
||||||
if (device_index) {
|
|
||||||
const auto& device = devices[device_index.value()].device;
|
|
||||||
const std::vector<u8> data = device->GetReply();
|
|
||||||
const u64 data_size = ctx.WriteBuffer(data);
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.Push<u64>(data_size);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_ERROR(Service_HID, "Invalid handle");
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultUnknown);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
void HidBus::SetEventForSendCommandAsycResult(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto bus_handle_{rp.PopRaw<BusHandle>()};
|
|
||||||
|
|
||||||
LOG_INFO(Service_HID,
|
|
||||||
"called, abstracted_pad_id={}, bus_type={}, internal_index={}, player_number={}, "
|
|
||||||
"is_valid={}",
|
|
||||||
bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index,
|
|
||||||
bus_handle_.player_number, bus_handle_.is_valid);
|
|
||||||
|
|
||||||
const auto device_index = GetDeviceIndexFromHandle(bus_handle_);
|
|
||||||
|
|
||||||
if (device_index) {
|
|
||||||
const auto& device = devices[device_index.value()].device;
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.PushCopyObjects(device->GetSendCommandAsycEvent());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_ERROR(Service_HID, "Invalid handle");
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultUnknown);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
void HidBus::GetSharedMemoryHandle(HLERequestContext& ctx) {
|
|
||||||
LOG_DEBUG(Service_HID, "called");
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.PushCopyObjects(&system.Kernel().GetHidBusSharedMem());
|
|
||||||
}
|
|
||||||
|
|
||||||
void HidBus::EnableJoyPollingReceiveMode(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto t_mem_size{rp.Pop<u32>()};
|
|
||||||
const auto t_mem_handle{ctx.GetCopyHandle(0)};
|
|
||||||
const auto polling_mode_{rp.PopEnum<JoyPollingMode>()};
|
|
||||||
const auto bus_handle_{rp.PopRaw<BusHandle>()};
|
|
||||||
|
|
||||||
ASSERT_MSG(t_mem_size == 0x1000, "t_mem_size is not 0x1000 bytes");
|
|
||||||
|
|
||||||
auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
|
||||||
t_mem_handle);
|
|
||||||
|
|
||||||
if (t_mem.IsNull()) {
|
|
||||||
LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultUnknown);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT_MSG(t_mem->GetSize() == 0x1000, "t_mem has incorrect size");
|
|
||||||
|
|
||||||
LOG_INFO(Service_HID,
|
|
||||||
"called, t_mem_handle=0x{:08X}, polling_mode={}, abstracted_pad_id={}, bus_type={}, "
|
|
||||||
"internal_index={}, player_number={}, is_valid={}",
|
|
||||||
t_mem_handle, polling_mode_, bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id,
|
|
||||||
bus_handle_.internal_index, bus_handle_.player_number, bus_handle_.is_valid);
|
|
||||||
|
|
||||||
const auto device_index = GetDeviceIndexFromHandle(bus_handle_);
|
|
||||||
|
|
||||||
if (device_index) {
|
|
||||||
auto& device = devices[device_index.value()].device;
|
|
||||||
device->SetPollingMode(polling_mode_);
|
|
||||||
device->SetTransferMemoryAddress(t_mem->GetSourceAddress());
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_ERROR(Service_HID, "Invalid handle");
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultUnknown);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HidBus::DisableJoyPollingReceiveMode(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto bus_handle_{rp.PopRaw<BusHandle>()};
|
|
||||||
|
|
||||||
LOG_INFO(Service_HID,
|
|
||||||
"called, abstracted_pad_id={}, bus_type={}, internal_index={}, player_number={}, "
|
|
||||||
"is_valid={}",
|
|
||||||
bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index,
|
|
||||||
bus_handle_.player_number, bus_handle_.is_valid);
|
|
||||||
|
|
||||||
const auto device_index = GetDeviceIndexFromHandle(bus_handle_);
|
|
||||||
|
|
||||||
if (device_index) {
|
|
||||||
auto& device = devices[device_index.value()].device;
|
|
||||||
device->DisablePollingMode();
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_ERROR(Service_HID, "Invalid handle");
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultUnknown);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HidBus::SetStatusManagerType(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto manager_type{rp.PopEnum<StatusManagerType>()};
|
|
||||||
|
|
||||||
LOG_WARNING(Service_HID, "(STUBBED) called, manager_type={}", manager_type);
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
};
|
|
||||||
} // namespace Service::HID
|
|
|
@ -3,127 +3,18 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#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 "core/hle/service/service.h"
|
||||||
|
|
||||||
namespace Core::Timing {
|
|
||||||
struct EventType;
|
|
||||||
} // namespace Core::Timing
|
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
class System;
|
class System;
|
||||||
} // namespace Core
|
}
|
||||||
|
|
||||||
namespace Service::HID {
|
namespace Service::HID {
|
||||||
|
|
||||||
class HidBus final : public ServiceFramework<HidBus> {
|
class IHidbusServer final : public ServiceFramework<IHidbusServer> {
|
||||||
public:
|
public:
|
||||||
explicit HidBus(Core::System& system_);
|
explicit IHidbusServer(Core::System& system_);
|
||||||
~HidBus() override;
|
~IHidbusServer() override;
|
||||||
|
|
||||||
private:
|
|
||||||
static const std::size_t max_number_of_handles = 0x13;
|
|
||||||
|
|
||||||
enum class HidBusDeviceId : std::size_t {
|
|
||||||
RingController = 0x20,
|
|
||||||
FamicomRight = 0x21,
|
|
||||||
Starlink = 0x28,
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is nn::hidbus::detail::StatusManagerType
|
|
||||||
enum class StatusManagerType : u32 {
|
|
||||||
None,
|
|
||||||
Type16,
|
|
||||||
Type32,
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is nn::hidbus::BusType
|
|
||||||
enum class BusType : u32 {
|
|
||||||
LeftJoyRail,
|
|
||||||
RightJoyRail,
|
|
||||||
InternalBus, // Lark microphone
|
|
||||||
|
|
||||||
MaxBusType,
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is nn::hidbus::BusHandle
|
|
||||||
struct BusHandle {
|
|
||||||
u32 abstracted_pad_id;
|
|
||||||
u8 internal_index;
|
|
||||||
u8 player_number;
|
|
||||||
u8 bus_type_id;
|
|
||||||
bool is_valid;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(BusHandle) == 0x8, "BusHandle is an invalid size");
|
|
||||||
|
|
||||||
// This is nn::hidbus::JoyPollingReceivedData
|
|
||||||
struct JoyPollingReceivedData {
|
|
||||||
std::array<u8, 0x30> data;
|
|
||||||
u64 out_size;
|
|
||||||
u64 sampling_number;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(JoyPollingReceivedData) == 0x40,
|
|
||||||
"JoyPollingReceivedData is an invalid size");
|
|
||||||
|
|
||||||
struct HidbusStatusManagerEntry {
|
|
||||||
u8 is_connected{};
|
|
||||||
INSERT_PADDING_BYTES(0x3);
|
|
||||||
Result is_connected_result{0};
|
|
||||||
u8 is_enabled{};
|
|
||||||
u8 is_in_focus{};
|
|
||||||
u8 is_polling_mode{};
|
|
||||||
u8 reserved{};
|
|
||||||
JoyPollingMode polling_mode{};
|
|
||||||
INSERT_PADDING_BYTES(0x70); // Unknown
|
|
||||||
};
|
|
||||||
static_assert(sizeof(HidbusStatusManagerEntry) == 0x80,
|
|
||||||
"HidbusStatusManagerEntry is an invalid size");
|
|
||||||
|
|
||||||
struct HidbusStatusManager {
|
|
||||||
std::array<HidbusStatusManagerEntry, max_number_of_handles> entries{};
|
|
||||||
INSERT_PADDING_BYTES(0x680); // Unused
|
|
||||||
};
|
|
||||||
static_assert(sizeof(HidbusStatusManager) <= 0x1000, "HidbusStatusManager is an invalid size");
|
|
||||||
|
|
||||||
struct HidbusDevice {
|
|
||||||
bool is_device_initializated{};
|
|
||||||
BusHandle handle{};
|
|
||||||
std::unique_ptr<HidbusBase> device{nullptr};
|
|
||||||
};
|
|
||||||
|
|
||||||
void GetBusHandle(HLERequestContext& ctx);
|
|
||||||
void IsExternalDeviceConnected(HLERequestContext& ctx);
|
|
||||||
void Initialize(HLERequestContext& ctx);
|
|
||||||
void Finalize(HLERequestContext& ctx);
|
|
||||||
void EnableExternalDevice(HLERequestContext& ctx);
|
|
||||||
void GetExternalDeviceId(HLERequestContext& ctx);
|
|
||||||
void SendCommandAsync(HLERequestContext& ctx);
|
|
||||||
void GetSendCommandAsynceResult(HLERequestContext& ctx);
|
|
||||||
void SetEventForSendCommandAsycResult(HLERequestContext& ctx);
|
|
||||||
void GetSharedMemoryHandle(HLERequestContext& ctx);
|
|
||||||
void EnableJoyPollingReceiveMode(HLERequestContext& ctx);
|
|
||||||
void DisableJoyPollingReceiveMode(HLERequestContext& ctx);
|
|
||||||
void SetStatusManagerType(HLERequestContext& ctx);
|
|
||||||
|
|
||||||
void UpdateHidbus(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
|
||||||
std::optional<std::size_t> GetDeviceIndexFromHandle(BusHandle handle) const;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void MakeDevice(BusHandle handle) {
|
|
||||||
const auto device_index = GetDeviceIndexFromHandle(handle);
|
|
||||||
if (device_index) {
|
|
||||||
devices[device_index.value()].device = std::make_unique<T>(system, service_context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_hidbus_enabled{false};
|
|
||||||
HidbusStatusManager hidbus_status{};
|
|
||||||
std::array<HidbusDevice, max_number_of_handles> devices{};
|
|
||||||
std::shared_ptr<Core::Timing::EventType> hidbus_update_event;
|
|
||||||
KernelHelpers::ServiceContext service_context;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Service::HID
|
} // namespace Service::HID
|
|
@ -1,70 +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() = default;
|
|
||||||
|
|
||||||
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
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
|
namespace Service::HIDBUS {
|
||||||
|
|
||||||
|
constexpr Result ResultNotEnabled{ErrorModule::HIDBUS, 1};
|
||||||
|
constexpr Result ResultControllerUpdateFailed{ErrorModule::HIDBUS, 3};
|
||||||
|
constexpr Result ResultInvalidBusHandle{ErrorModule::HIDBUS, 4};
|
||||||
|
constexpr Result ResultNoDeviceConnected{ErrorModule::HIDBUS, 5};
|
||||||
|
constexpr Result ResultUknown6{ErrorModule::HIDBUS, 6};
|
||||||
|
constexpr Result ResultPollingRecieveDataNotAvailable{ErrorModule::HIDBUS, 7};
|
||||||
|
constexpr Result ResultDeviceEnabledNotSet{ErrorModule::HIDBUS, 8};
|
||||||
|
constexpr Result ResultBusHandleAlreadyInitialized{ErrorModule::HIDBUS, 10};
|
||||||
|
constexpr Result ResultInvalidBusType{ErrorModule::HIDBUS, 11};
|
||||||
|
|
||||||
|
} // namespace Service::HIDBUS
|
|
@ -0,0 +1,11 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include "common/common_funcs.h"
|
||||||
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
namespace Service::HIDBUS {} // namespace Service::HIDBUS
|
|
@ -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
|
|
|
@ -1,567 +1,41 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <random>
|
|
||||||
|
|
||||||
#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/irs.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/hle/service/ipc_helpers.h"
|
||||||
#include "core/memory.h"
|
|
||||||
|
|
||||||
namespace Service::IRS {
|
namespace Service::IRS {
|
||||||
|
|
||||||
IRS::IRS(Core::System& system_) : ServiceFramework{system_, "irs"} {
|
IIrSensorServer::IIrSensorServer(Core::System& system_) : ServiceFramework{system_, "irs"} {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{302, &IRS::ActivateIrsensor, "ActivateIrsensor"},
|
{302, nullptr, "ActivateIrsensor"},
|
||||||
{303, &IRS::DeactivateIrsensor, "DeactivateIrsensor"},
|
{303, nullptr, "DeactivateIrsensor"},
|
||||||
{304, &IRS::GetIrsensorSharedMemoryHandle, "GetIrsensorSharedMemoryHandle"},
|
{304, nullptr, "GetIrsensorSharedMemoryHandle"},
|
||||||
{305, &IRS::StopImageProcessor, "StopImageProcessor"},
|
{305, nullptr, "StopImageProcessor"},
|
||||||
{306, &IRS::RunMomentProcessor, "RunMomentProcessor"},
|
{306, nullptr, "RunMomentProcessor"},
|
||||||
{307, &IRS::RunClusteringProcessor, "RunClusteringProcessor"},
|
{307, nullptr, "RunClusteringProcessor"},
|
||||||
{308, &IRS::RunImageTransferProcessor, "RunImageTransferProcessor"},
|
{308, nullptr, "RunImageTransferProcessor"},
|
||||||
{309, &IRS::GetImageTransferProcessorState, "GetImageTransferProcessorState"},
|
{309, nullptr, "GetImageTransferProcessorState"},
|
||||||
{310, &IRS::RunTeraPluginProcessor, "RunTeraPluginProcessor"},
|
{310, nullptr, "RunTeraPluginProcessor"},
|
||||||
{311, &IRS::GetNpadIrCameraHandle, "GetNpadIrCameraHandle"},
|
{311, nullptr, "GetNpadIrCameraHandle"},
|
||||||
{312, &IRS::RunPointingProcessor, "RunPointingProcessor"},
|
{312, nullptr, "RunPointingProcessor"},
|
||||||
{313, &IRS::SuspendImageProcessor, "SuspendImageProcessor"},
|
{313, nullptr, "SuspendImageProcessor"},
|
||||||
{314, &IRS::CheckFirmwareVersion, "CheckFirmwareVersion"},
|
{314, nullptr, "CheckFirmwareVersion"},
|
||||||
{315, &IRS::SetFunctionLevel, "SetFunctionLevel"},
|
{315, nullptr, "SetFunctionLevel"},
|
||||||
{316, &IRS::RunImageTransferExProcessor, "RunImageTransferExProcessor"},
|
{316, nullptr, "RunImageTransferExProcessor"},
|
||||||
{317, &IRS::RunIrLedProcessor, "RunIrLedProcessor"},
|
{317, nullptr, "RunIrLedProcessor"},
|
||||||
{318, &IRS::StopImageProcessorAsync, "StopImageProcessorAsync"},
|
{318, nullptr, "StopImageProcessorAsync"},
|
||||||
{319, &IRS::ActivateIrsensorWithFunctionLevel, "ActivateIrsensorWithFunctionLevel"},
|
{319, nullptr, "ActivateIrsensorWithFunctionLevel"},
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
u8* raw_shared_memory = system.Kernel().GetIrsSharedMem().GetPointer();
|
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
shared_memory = std::construct_at(reinterpret_cast<StatusManager*>(raw_shared_memory));
|
|
||||||
|
|
||||||
npad_device = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
|
|
||||||
}
|
}
|
||||||
IRS::~IRS() = default;
|
IIrSensorServer::~IIrSensorServer() = default;
|
||||||
|
|
||||||
void IRS::ActivateIrsensor(HLERequestContext& ctx) {
|
IIrSensorSystemServer::IIrSensorSystemServer(Core::System& system_)
|
||||||
IPC::RequestParser rp{ctx};
|
: ServiceFramework{system_, "irs:sys"} {
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
|
||||||
|
|
||||||
LOG_WARNING(Service_IRS, "(STUBBED) called, applet_resource_user_id={}",
|
|
||||||
applet_resource_user_id);
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRS::DeactivateIrsensor(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
|
||||||
|
|
||||||
LOG_WARNING(Service_IRS, "(STUBBED) called, applet_resource_user_id={}",
|
|
||||||
applet_resource_user_id);
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRS::GetIrsensorSharedMemoryHandle(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
|
||||||
|
|
||||||
LOG_DEBUG(Service_IRS, "called, applet_resource_user_id={}", applet_resource_user_id);
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.PushCopyObjects(&system.Kernel().GetIrsSharedMem());
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRS::StopImageProcessor(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
struct Parameters {
|
|
||||||
Core::IrSensor::IrCameraHandle camera_handle;
|
|
||||||
INSERT_PADDING_WORDS_NOINIT(1);
|
|
||||||
u64 applet_resource_user_id;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
|
|
||||||
|
|
||||||
const auto parameters{rp.PopRaw<Parameters>()};
|
|
||||||
|
|
||||||
LOG_WARNING(Service_IRS,
|
|
||||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
|
||||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
|
||||||
parameters.applet_resource_user_id);
|
|
||||||
|
|
||||||
auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
|
||||||
if (result.IsSuccess()) {
|
|
||||||
// TODO: Stop Image processor
|
|
||||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
|
||||||
Common::Input::PollingMode::Active);
|
|
||||||
result = ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRS::RunMomentProcessor(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
struct Parameters {
|
|
||||||
Core::IrSensor::IrCameraHandle camera_handle;
|
|
||||||
INSERT_PADDING_WORDS_NOINIT(1);
|
|
||||||
u64 applet_resource_user_id;
|
|
||||||
Core::IrSensor::PackedMomentProcessorConfig processor_config;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(Parameters) == 0x30, "Parameters has incorrect size.");
|
|
||||||
|
|
||||||
const auto parameters{rp.PopRaw<Parameters>()};
|
|
||||||
|
|
||||||
LOG_WARNING(Service_IRS,
|
|
||||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
|
||||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
|
||||||
parameters.applet_resource_user_id);
|
|
||||||
|
|
||||||
const auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
|
||||||
|
|
||||||
if (result.IsSuccess()) {
|
|
||||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
|
|
||||||
MakeProcessor<MomentProcessor>(parameters.camera_handle, device);
|
|
||||||
auto& image_transfer_processor = GetProcessor<MomentProcessor>(parameters.camera_handle);
|
|
||||||
image_transfer_processor.SetConfig(parameters.processor_config);
|
|
||||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
|
||||||
Common::Input::PollingMode::IR);
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRS::RunClusteringProcessor(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
struct Parameters {
|
|
||||||
Core::IrSensor::IrCameraHandle camera_handle;
|
|
||||||
INSERT_PADDING_WORDS_NOINIT(1);
|
|
||||||
u64 applet_resource_user_id;
|
|
||||||
Core::IrSensor::PackedClusteringProcessorConfig processor_config;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(Parameters) == 0x38, "Parameters has incorrect size.");
|
|
||||||
|
|
||||||
const auto parameters{rp.PopRaw<Parameters>()};
|
|
||||||
|
|
||||||
LOG_WARNING(Service_IRS,
|
|
||||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
|
||||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
|
||||||
parameters.applet_resource_user_id);
|
|
||||||
|
|
||||||
auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
|
||||||
|
|
||||||
if (result.IsSuccess()) {
|
|
||||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
|
|
||||||
MakeProcessorWithCoreContext<ClusteringProcessor>(parameters.camera_handle, device);
|
|
||||||
auto& image_transfer_processor =
|
|
||||||
GetProcessor<ClusteringProcessor>(parameters.camera_handle);
|
|
||||||
image_transfer_processor.SetConfig(parameters.processor_config);
|
|
||||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
|
||||||
Common::Input::PollingMode::IR);
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRS::RunImageTransferProcessor(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
struct Parameters {
|
|
||||||
Core::IrSensor::IrCameraHandle camera_handle;
|
|
||||||
INSERT_PADDING_WORDS_NOINIT(1);
|
|
||||||
u64 applet_resource_user_id;
|
|
||||||
Core::IrSensor::PackedImageTransferProcessorConfig processor_config;
|
|
||||||
u32 transfer_memory_size;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(Parameters) == 0x30, "Parameters has incorrect size.");
|
|
||||||
|
|
||||||
const auto parameters{rp.PopRaw<Parameters>()};
|
|
||||||
const auto t_mem_handle{ctx.GetCopyHandle(0)};
|
|
||||||
|
|
||||||
auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
|
||||||
t_mem_handle);
|
|
||||||
|
|
||||||
if (t_mem.IsNull()) {
|
|
||||||
LOG_ERROR(Service_IRS, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultUnknown);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT_MSG(t_mem->GetSize() == parameters.transfer_memory_size, "t_mem has incorrect size");
|
|
||||||
|
|
||||||
LOG_INFO(Service_IRS,
|
|
||||||
"called, npad_type={}, npad_id={}, transfer_memory_size={}, transfer_memory_size={}, "
|
|
||||||
"applet_resource_user_id={}",
|
|
||||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
|
||||||
parameters.transfer_memory_size, t_mem->GetSize(), parameters.applet_resource_user_id);
|
|
||||||
|
|
||||||
const auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
|
||||||
|
|
||||||
if (result.IsSuccess()) {
|
|
||||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
|
|
||||||
MakeProcessorWithCoreContext<ImageTransferProcessor>(parameters.camera_handle, device);
|
|
||||||
auto& image_transfer_processor =
|
|
||||||
GetProcessor<ImageTransferProcessor>(parameters.camera_handle);
|
|
||||||
image_transfer_processor.SetConfig(parameters.processor_config);
|
|
||||||
image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress());
|
|
||||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
|
||||||
Common::Input::PollingMode::IR);
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRS::GetImageTransferProcessorState(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
struct Parameters {
|
|
||||||
Core::IrSensor::IrCameraHandle camera_handle;
|
|
||||||
INSERT_PADDING_WORDS_NOINIT(1);
|
|
||||||
u64 applet_resource_user_id;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
|
|
||||||
|
|
||||||
const auto parameters{rp.PopRaw<Parameters>()};
|
|
||||||
|
|
||||||
LOG_DEBUG(Service_IRS, "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
|
||||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
|
||||||
parameters.applet_resource_user_id);
|
|
||||||
|
|
||||||
const auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
|
||||||
if (result.IsError()) {
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(result);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
|
|
||||||
|
|
||||||
if (device.mode != Core::IrSensor::IrSensorMode::ImageTransferProcessor) {
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(InvalidProcessorState);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<u8> data{};
|
|
||||||
const auto& image_transfer_processor =
|
|
||||||
GetProcessor<ImageTransferProcessor>(parameters.camera_handle);
|
|
||||||
const auto& state = image_transfer_processor.GetState(data);
|
|
||||||
|
|
||||||
ctx.WriteBuffer(data);
|
|
||||||
IPC::ResponseBuilder rb{ctx, 6};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.PushRaw(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRS::RunTeraPluginProcessor(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
struct Parameters {
|
|
||||||
Core::IrSensor::IrCameraHandle camera_handle;
|
|
||||||
Core::IrSensor::PackedTeraPluginProcessorConfig processor_config;
|
|
||||||
INSERT_PADDING_WORDS_NOINIT(1);
|
|
||||||
u64 applet_resource_user_id;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
|
|
||||||
|
|
||||||
const auto parameters{rp.PopRaw<Parameters>()};
|
|
||||||
|
|
||||||
LOG_WARNING(
|
|
||||||
Service_IRS,
|
|
||||||
"(STUBBED) called, npad_type={}, npad_id={}, mode={}, mcu_version={}.{}, "
|
|
||||||
"applet_resource_user_id={}",
|
|
||||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
|
||||||
parameters.processor_config.mode, parameters.processor_config.required_mcu_version.major,
|
|
||||||
parameters.processor_config.required_mcu_version.minor, parameters.applet_resource_user_id);
|
|
||||||
|
|
||||||
const auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
|
||||||
|
|
||||||
if (result.IsSuccess()) {
|
|
||||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
|
|
||||||
MakeProcessor<TeraPluginProcessor>(parameters.camera_handle, device);
|
|
||||||
auto& image_transfer_processor =
|
|
||||||
GetProcessor<TeraPluginProcessor>(parameters.camera_handle);
|
|
||||||
image_transfer_processor.SetConfig(parameters.processor_config);
|
|
||||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
|
||||||
Common::Input::PollingMode::IR);
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRS::GetNpadIrCameraHandle(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()};
|
|
||||||
|
|
||||||
if (npad_id > Core::HID::NpadIdType::Player8 && npad_id != Core::HID::NpadIdType::Invalid &&
|
|
||||||
npad_id != Core::HID::NpadIdType::Handheld) {
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(Service::HID::InvalidNpadId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Core::IrSensor::IrCameraHandle camera_handle{
|
|
||||||
.npad_id = static_cast<u8>(NpadIdTypeToIndex(npad_id)),
|
|
||||||
.npad_type = Core::HID::NpadStyleIndex::None,
|
|
||||||
};
|
|
||||||
|
|
||||||
LOG_INFO(Service_IRS, "called, npad_id={}, camera_npad_id={}, camera_npad_type={}", npad_id,
|
|
||||||
camera_handle.npad_id, camera_handle.npad_type);
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.PushRaw(camera_handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRS::RunPointingProcessor(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()};
|
|
||||||
const auto processor_config{rp.PopRaw<Core::IrSensor::PackedPointingProcessorConfig>()};
|
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
|
||||||
|
|
||||||
LOG_WARNING(
|
|
||||||
Service_IRS,
|
|
||||||
"(STUBBED) called, npad_type={}, npad_id={}, mcu_version={}.{}, applet_resource_user_id={}",
|
|
||||||
camera_handle.npad_type, camera_handle.npad_id, processor_config.required_mcu_version.major,
|
|
||||||
processor_config.required_mcu_version.minor, applet_resource_user_id);
|
|
||||||
|
|
||||||
auto result = IsIrCameraHandleValid(camera_handle);
|
|
||||||
|
|
||||||
if (result.IsSuccess()) {
|
|
||||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
|
|
||||||
MakeProcessor<PointingProcessor>(camera_handle, device);
|
|
||||||
auto& image_transfer_processor = GetProcessor<PointingProcessor>(camera_handle);
|
|
||||||
image_transfer_processor.SetConfig(processor_config);
|
|
||||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
|
||||||
Common::Input::PollingMode::IR);
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRS::SuspendImageProcessor(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
struct Parameters {
|
|
||||||
Core::IrSensor::IrCameraHandle camera_handle;
|
|
||||||
INSERT_PADDING_WORDS_NOINIT(1);
|
|
||||||
u64 applet_resource_user_id;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
|
|
||||||
|
|
||||||
const auto parameters{rp.PopRaw<Parameters>()};
|
|
||||||
|
|
||||||
LOG_WARNING(Service_IRS,
|
|
||||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
|
||||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
|
||||||
parameters.applet_resource_user_id);
|
|
||||||
|
|
||||||
auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
|
||||||
if (result.IsSuccess()) {
|
|
||||||
// TODO: Suspend image processor
|
|
||||||
result = ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRS::CheckFirmwareVersion(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()};
|
|
||||||
const auto mcu_version{rp.PopRaw<Core::IrSensor::PackedMcuVersion>()};
|
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
|
||||||
|
|
||||||
LOG_WARNING(
|
|
||||||
Service_IRS,
|
|
||||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}, mcu_version={}.{}",
|
|
||||||
camera_handle.npad_type, camera_handle.npad_id, applet_resource_user_id, mcu_version.major,
|
|
||||||
mcu_version.minor);
|
|
||||||
|
|
||||||
auto result = IsIrCameraHandleValid(camera_handle);
|
|
||||||
if (result.IsSuccess()) {
|
|
||||||
// TODO: Check firmware version
|
|
||||||
result = ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRS::SetFunctionLevel(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()};
|
|
||||||
const auto function_level{rp.PopRaw<Core::IrSensor::PackedFunctionLevel>()};
|
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
|
||||||
|
|
||||||
LOG_WARNING(
|
|
||||||
Service_IRS,
|
|
||||||
"(STUBBED) called, npad_type={}, npad_id={}, function_level={}, applet_resource_user_id={}",
|
|
||||||
camera_handle.npad_type, camera_handle.npad_id, function_level.function_level,
|
|
||||||
applet_resource_user_id);
|
|
||||||
|
|
||||||
auto result = IsIrCameraHandleValid(camera_handle);
|
|
||||||
if (result.IsSuccess()) {
|
|
||||||
// TODO: Set Function level
|
|
||||||
result = ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRS::RunImageTransferExProcessor(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
struct Parameters {
|
|
||||||
Core::IrSensor::IrCameraHandle camera_handle;
|
|
||||||
INSERT_PADDING_WORDS_NOINIT(1);
|
|
||||||
u64 applet_resource_user_id;
|
|
||||||
Core::IrSensor::PackedImageTransferProcessorExConfig processor_config;
|
|
||||||
u64 transfer_memory_size;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(Parameters) == 0x38, "Parameters has incorrect size.");
|
|
||||||
|
|
||||||
const auto parameters{rp.PopRaw<Parameters>()};
|
|
||||||
const auto t_mem_handle{ctx.GetCopyHandle(0)};
|
|
||||||
|
|
||||||
auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
|
||||||
t_mem_handle);
|
|
||||||
|
|
||||||
LOG_INFO(Service_IRS,
|
|
||||||
"called, npad_type={}, npad_id={}, transfer_memory_size={}, "
|
|
||||||
"applet_resource_user_id={}",
|
|
||||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
|
||||||
parameters.transfer_memory_size, parameters.applet_resource_user_id);
|
|
||||||
|
|
||||||
auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
|
||||||
|
|
||||||
if (result.IsSuccess()) {
|
|
||||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
|
|
||||||
MakeProcessorWithCoreContext<ImageTransferProcessor>(parameters.camera_handle, device);
|
|
||||||
auto& image_transfer_processor =
|
|
||||||
GetProcessor<ImageTransferProcessor>(parameters.camera_handle);
|
|
||||||
image_transfer_processor.SetConfig(parameters.processor_config);
|
|
||||||
image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress());
|
|
||||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
|
||||||
Common::Input::PollingMode::IR);
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRS::RunIrLedProcessor(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()};
|
|
||||||
const auto processor_config{rp.PopRaw<Core::IrSensor::PackedIrLedProcessorConfig>()};
|
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
|
||||||
|
|
||||||
LOG_WARNING(Service_IRS,
|
|
||||||
"(STUBBED) called, npad_type={}, npad_id={}, light_target={}, mcu_version={}.{} "
|
|
||||||
"applet_resource_user_id={}",
|
|
||||||
camera_handle.npad_type, camera_handle.npad_id, processor_config.light_target,
|
|
||||||
processor_config.required_mcu_version.major,
|
|
||||||
processor_config.required_mcu_version.minor, applet_resource_user_id);
|
|
||||||
|
|
||||||
auto result = IsIrCameraHandleValid(camera_handle);
|
|
||||||
|
|
||||||
if (result.IsSuccess()) {
|
|
||||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
|
|
||||||
MakeProcessor<IrLedProcessor>(camera_handle, device);
|
|
||||||
auto& image_transfer_processor = GetProcessor<IrLedProcessor>(camera_handle);
|
|
||||||
image_transfer_processor.SetConfig(processor_config);
|
|
||||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
|
||||||
Common::Input::PollingMode::IR);
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRS::StopImageProcessorAsync(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
struct Parameters {
|
|
||||||
Core::IrSensor::IrCameraHandle camera_handle;
|
|
||||||
INSERT_PADDING_WORDS_NOINIT(1);
|
|
||||||
u64 applet_resource_user_id;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
|
|
||||||
|
|
||||||
const auto parameters{rp.PopRaw<Parameters>()};
|
|
||||||
|
|
||||||
LOG_WARNING(Service_IRS,
|
|
||||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
|
||||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
|
||||||
parameters.applet_resource_user_id);
|
|
||||||
|
|
||||||
auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
|
||||||
if (result.IsSuccess()) {
|
|
||||||
// TODO: Stop image processor async
|
|
||||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
|
||||||
Common::Input::PollingMode::Active);
|
|
||||||
result = ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRS::ActivateIrsensorWithFunctionLevel(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
struct Parameters {
|
|
||||||
Core::IrSensor::PackedFunctionLevel function_level;
|
|
||||||
INSERT_PADDING_WORDS_NOINIT(1);
|
|
||||||
u64 applet_resource_user_id;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
|
|
||||||
|
|
||||||
const auto parameters{rp.PopRaw<Parameters>()};
|
|
||||||
|
|
||||||
LOG_WARNING(Service_IRS, "(STUBBED) called, function_level={}, applet_resource_user_id={}",
|
|
||||||
parameters.function_level.function_level, parameters.applet_resource_user_id);
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IRS::IsIrCameraHandleValid(const Core::IrSensor::IrCameraHandle& camera_handle) const {
|
|
||||||
if (camera_handle.npad_id >
|
|
||||||
static_cast<u8>(NpadIdTypeToIndex(Core::HID::NpadIdType::Handheld))) {
|
|
||||||
return InvalidIrCameraHandle;
|
|
||||||
}
|
|
||||||
if (camera_handle.npad_type != Core::HID::NpadStyleIndex::None) {
|
|
||||||
return InvalidIrCameraHandle;
|
|
||||||
}
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
Core::IrSensor::DeviceFormat& IRS::GetIrCameraSharedMemoryDeviceEntry(
|
|
||||||
const Core::IrSensor::IrCameraHandle& camera_handle) {
|
|
||||||
const auto npad_id_max_index = static_cast<u8>(sizeof(StatusManager::device));
|
|
||||||
ASSERT_MSG(camera_handle.npad_id < npad_id_max_index, "invalid npad_id");
|
|
||||||
return shared_memory->device[camera_handle.npad_id];
|
|
||||||
}
|
|
||||||
|
|
||||||
IRS_SYS::IRS_SYS(Core::System& system_) : ServiceFramework{system_, "irs:sys"} {
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{500, nullptr, "SetAppletResourceUserId"},
|
{500, nullptr, "SetAppletResourceUserId"},
|
||||||
|
@ -574,6 +48,6 @@ IRS_SYS::IRS_SYS(Core::System& system_) : ServiceFramework{system_, "irs:sys"} {
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
}
|
}
|
||||||
|
|
||||||
IRS_SYS::~IRS_SYS() = default;
|
IIrSensorSystemServer::~IIrSensorSystemServer() = default;
|
||||||
|
|
||||||
} // namespace Service::IRS
|
} // namespace Service::IRS
|
|
@ -3,121 +3,24 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#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 "core/hle/service/service.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
class System;
|
class System;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Core::HID {
|
|
||||||
class EmulatedController;
|
|
||||||
} // namespace Core::HID
|
|
||||||
|
|
||||||
namespace Service::IRS {
|
namespace Service::IRS {
|
||||||
|
|
||||||
class IRS final : public ServiceFramework<IRS> {
|
class IIrSensorServer final : public ServiceFramework<IIrSensorServer> {
|
||||||
public:
|
public:
|
||||||
explicit IRS(Core::System& system_);
|
explicit IIrSensorServer(Core::System& system_);
|
||||||
~IRS() override;
|
~IIrSensorServer() override;
|
||||||
|
|
||||||
private:
|
|
||||||
// This is nn::irsensor::detail::AruidFormat
|
|
||||||
struct AruidFormat {
|
|
||||||
u64 sensor_aruid;
|
|
||||||
u64 sensor_aruid_status;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(AruidFormat) == 0x10, "AruidFormat is an invalid size");
|
|
||||||
|
|
||||||
// This is nn::irsensor::detail::StatusManager
|
|
||||||
struct StatusManager {
|
|
||||||
std::array<Core::IrSensor::DeviceFormat, 9> device;
|
|
||||||
std::array<AruidFormat, 5> aruid;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(StatusManager) == 0x8000, "StatusManager is an invalid size");
|
|
||||||
|
|
||||||
void ActivateIrsensor(HLERequestContext& ctx);
|
|
||||||
void DeactivateIrsensor(HLERequestContext& ctx);
|
|
||||||
void GetIrsensorSharedMemoryHandle(HLERequestContext& ctx);
|
|
||||||
void StopImageProcessor(HLERequestContext& ctx);
|
|
||||||
void RunMomentProcessor(HLERequestContext& ctx);
|
|
||||||
void RunClusteringProcessor(HLERequestContext& ctx);
|
|
||||||
void RunImageTransferProcessor(HLERequestContext& ctx);
|
|
||||||
void GetImageTransferProcessorState(HLERequestContext& ctx);
|
|
||||||
void RunTeraPluginProcessor(HLERequestContext& ctx);
|
|
||||||
void GetNpadIrCameraHandle(HLERequestContext& ctx);
|
|
||||||
void RunPointingProcessor(HLERequestContext& ctx);
|
|
||||||
void SuspendImageProcessor(HLERequestContext& ctx);
|
|
||||||
void CheckFirmwareVersion(HLERequestContext& ctx);
|
|
||||||
void SetFunctionLevel(HLERequestContext& ctx);
|
|
||||||
void RunImageTransferExProcessor(HLERequestContext& ctx);
|
|
||||||
void RunIrLedProcessor(HLERequestContext& ctx);
|
|
||||||
void StopImageProcessorAsync(HLERequestContext& ctx);
|
|
||||||
void ActivateIrsensorWithFunctionLevel(HLERequestContext& ctx);
|
|
||||||
|
|
||||||
Result IsIrCameraHandleValid(const Core::IrSensor::IrCameraHandle& camera_handle) const;
|
|
||||||
Core::IrSensor::DeviceFormat& GetIrCameraSharedMemoryDeviceEntry(
|
|
||||||
const Core::IrSensor::IrCameraHandle& camera_handle);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void MakeProcessor(const Core::IrSensor::IrCameraHandle& handle,
|
|
||||||
Core::IrSensor::DeviceFormat& device_state) {
|
|
||||||
const auto index = static_cast<std::size_t>(handle.npad_id);
|
|
||||||
if (index > sizeof(processors)) {
|
|
||||||
LOG_CRITICAL(Service_IRS, "Invalid index {}", index);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
processors[index] = std::make_unique<T>(device_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void MakeProcessorWithCoreContext(const Core::IrSensor::IrCameraHandle& handle,
|
|
||||||
Core::IrSensor::DeviceFormat& device_state) {
|
|
||||||
const auto index = static_cast<std::size_t>(handle.npad_id);
|
|
||||||
if (index > sizeof(processors)) {
|
|
||||||
LOG_CRITICAL(Service_IRS, "Invalid index {}", index);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if constexpr (std::is_constructible_v<T, Core::System&, Core::IrSensor::DeviceFormat&,
|
|
||||||
std::size_t>) {
|
|
||||||
processors[index] = std::make_unique<T>(system, device_state, index);
|
|
||||||
} else {
|
|
||||||
processors[index] = std::make_unique<T>(system.HIDCore(), device_state, index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T& GetProcessor(const Core::IrSensor::IrCameraHandle& handle) {
|
|
||||||
const auto index = static_cast<std::size_t>(handle.npad_id);
|
|
||||||
if (index > sizeof(processors)) {
|
|
||||||
LOG_CRITICAL(Service_IRS, "Invalid index {}", index);
|
|
||||||
return static_cast<T&>(*processors[0]);
|
|
||||||
}
|
|
||||||
return static_cast<T&>(*processors[index]);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
const T& GetProcessor(const Core::IrSensor::IrCameraHandle& handle) const {
|
|
||||||
const auto index = static_cast<std::size_t>(handle.npad_id);
|
|
||||||
if (index > sizeof(processors)) {
|
|
||||||
LOG_CRITICAL(Service_IRS, "Invalid index {}", index);
|
|
||||||
return static_cast<T&>(*processors[0]);
|
|
||||||
}
|
|
||||||
return static_cast<T&>(*processors[index]);
|
|
||||||
}
|
|
||||||
|
|
||||||
Core::HID::EmulatedController* npad_device = nullptr;
|
|
||||||
StatusManager* shared_memory = nullptr;
|
|
||||||
std::array<std::unique_ptr<ProcessorBase>, 9> processors{};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class IRS_SYS final : public ServiceFramework<IRS_SYS> {
|
class IIrSensorSystemServer final : public ServiceFramework<IIrSensorSystemServer> {
|
||||||
public:
|
public:
|
||||||
explicit IRS_SYS(Core::System& system);
|
explicit IIrSensorSystemServer(Core::System& system);
|
||||||
~IRS_SYS() override;
|
~IIrSensorSystemServer() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Service::IRS
|
} // namespace Service::IRS
|
|
@ -0,0 +1,13 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
|
namespace Service::IRS {
|
||||||
|
|
||||||
|
constexpr Result InvalidProcessorState{ErrorModule::Irsensor, 78};
|
||||||
|
constexpr Result InvalidIrCameraHandle{ErrorModule::Irsensor, 204};
|
||||||
|
|
||||||
|
} // namespace Service::IRS
|
|
@ -5,9 +5,9 @@
|
||||||
|
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/hid/hid_types.h"
|
#include "core/hle/service/hid/hid_server/hid_types.h"
|
||||||
|
|
||||||
namespace Core::IrSensor {
|
namespace Service::IRS {
|
||||||
|
|
||||||
// This is nn::irsensor::CameraAmbientNoiseLevel
|
// This is nn::irsensor::CameraAmbientNoiseLevel
|
||||||
enum class CameraAmbientNoiseLevel : u32 {
|
enum class CameraAmbientNoiseLevel : u32 {
|
||||||
|
@ -170,7 +170,7 @@ static_assert(sizeof(PackedCameraConfig) == 0x10, "PackedCameraConfig is an inva
|
||||||
// This is nn::irsensor::IrCameraHandle
|
// This is nn::irsensor::IrCameraHandle
|
||||||
struct IrCameraHandle {
|
struct IrCameraHandle {
|
||||||
u8 npad_id{};
|
u8 npad_id{};
|
||||||
Core::HID::NpadStyleIndex npad_type{Core::HID::NpadStyleIndex::None};
|
Service::HID::NpadStyleIndex npad_type{Service::HID::NpadStyleIndex::None};
|
||||||
INSERT_PADDING_BYTES(2);
|
INSERT_PADDING_BYTES(2);
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IrCameraHandle) == 4, "IrCameraHandle is an invalid size");
|
static_assert(sizeof(IrCameraHandle) == 4, "IrCameraHandle is an invalid size");
|
||||||
|
@ -281,10 +281,9 @@ static_assert(sizeof(ProcessorState) == 0xE20, "ProcessorState is an invalid siz
|
||||||
|
|
||||||
// This is nn::irsensor::detail::DeviceFormat
|
// This is nn::irsensor::detail::DeviceFormat
|
||||||
struct DeviceFormat {
|
struct DeviceFormat {
|
||||||
Core::IrSensor::IrCameraStatus camera_status{Core::IrSensor::IrCameraStatus::Unconnected};
|
IrCameraStatus camera_status{IrCameraStatus::Unconnected};
|
||||||
Core::IrSensor::IrCameraInternalStatus camera_internal_status{
|
IrCameraInternalStatus camera_internal_status{IrCameraInternalStatus::Ready};
|
||||||
Core::IrSensor::IrCameraInternalStatus::Ready};
|
IrSensorMode mode{IrSensorMode::None};
|
||||||
Core::IrSensor::IrSensorMode mode{Core::IrSensor::IrSensorMode::None};
|
|
||||||
ProcessorState state{};
|
ProcessorState state{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(DeviceFormat) == 0xE30, "DeviceFormat is an invalid size");
|
static_assert(sizeof(DeviceFormat) == 0xE30, "DeviceFormat is an invalid size");
|
||||||
|
@ -292,10 +291,10 @@ static_assert(sizeof(DeviceFormat) == 0xE30, "DeviceFormat is an invalid size");
|
||||||
// This is nn::irsensor::ImageTransferProcessorState
|
// This is nn::irsensor::ImageTransferProcessorState
|
||||||
struct ImageTransferProcessorState {
|
struct ImageTransferProcessorState {
|
||||||
u64 sampling_number;
|
u64 sampling_number;
|
||||||
Core::IrSensor::CameraAmbientNoiseLevel ambient_noise_level;
|
CameraAmbientNoiseLevel ambient_noise_level;
|
||||||
INSERT_PADDING_BYTES(4);
|
INSERT_PADDING_BYTES(4);
|
||||||
};
|
};
|
||||||
static_assert(sizeof(ImageTransferProcessorState) == 0x10,
|
static_assert(sizeof(ImageTransferProcessorState) == 0x10,
|
||||||
"ImageTransferProcessorState is an invalid size");
|
"ImageTransferProcessorState is an invalid size");
|
||||||
|
|
||||||
} // namespace Core::IrSensor
|
} // 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 <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,265 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <queue>
|
|
||||||
|
|
||||||
#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::HID::HIDCore& hid_core_,
|
|
||||||
Core::IrSensor::DeviceFormat& device_format,
|
|
||||||
std::size_t npad_index)
|
|
||||||
: device{device_format} {
|
|
||||||
npad_device = hid_core_.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 = next_state.timestamp + 131;
|
|
||||||
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,110 +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::HID {
|
|
||||||
class EmulatedController;
|
|
||||||
} // namespace Core::HID
|
|
||||||
|
|
||||||
namespace Service::IRS {
|
|
||||||
class ClusteringProcessor final : public ProcessorBase {
|
|
||||||
public:
|
|
||||||
explicit ClusteringProcessor(Core::HID::HIDCore& hid_core_,
|
|
||||||
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{};
|
|
||||||
};
|
|
||||||
} // 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,34 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include "core/hle/service/hid/irsensor/moment_processor.h"
|
|
||||||
|
|
||||||
namespace Service::IRS {
|
|
||||||
MomentProcessor::MomentProcessor(Core::IrSensor::DeviceFormat& device_format)
|
|
||||||
: device(device_format) {
|
|
||||||
device.mode = Core::IrSensor::IrSensorMode::MomentProcessor;
|
|
||||||
device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected;
|
|
||||||
device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped;
|
|
||||||
}
|
|
||||||
|
|
||||||
MomentProcessor::~MomentProcessor() = default;
|
|
||||||
|
|
||||||
void MomentProcessor::StartProcessor() {}
|
|
||||||
|
|
||||||
void MomentProcessor::SuspendProcessor() {}
|
|
||||||
|
|
||||||
void MomentProcessor::StopProcessor() {}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // 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/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 MomentProcessor final : public ProcessorBase {
|
|
||||||
public:
|
|
||||||
explicit MomentProcessor(Core::IrSensor::DeviceFormat& device_format);
|
|
||||||
~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:
|
|
||||||
// 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, 0x30> stadistic;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(MomentProcessorState) == 0x258, "MomentProcessorState is an invalid size");
|
|
||||||
|
|
||||||
MomentProcessorConfig current_config{};
|
|
||||||
Core::IrSensor::DeviceFormat& device;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // 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
|
|
|
@ -0,0 +1,267 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "core/hle/service/hid/hid_result.h"
|
||||||
|
#include "core/hle/service/hid/hid_types.h"
|
||||||
|
#include "core/hle/service/hid/hid_util.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/debug_pad.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/gesture.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/keyboard.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/mouse.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/npad_resource/npad.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/palma.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/sixaxis.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/touch_screen.h"
|
||||||
|
|
||||||
|
namespace Service::HID {
|
||||||
|
|
||||||
|
/* std::shared_ptr<NpadSharedMemory> SharedMemory::GetNpadSharedMemory(
|
||||||
|
SixAxisSensorHandle handle) const {
|
||||||
|
// TODO: THIS REE IS BROKEN
|
||||||
|
|
||||||
|
const auto npad_id = static_cast<NpadIdType>(handle.npad_id);
|
||||||
|
|
||||||
|
// This should crash console
|
||||||
|
ASSERT_MSG(IsNpadIdValid(npad_id), "ResultInvalidNpadId {}", npad_id);
|
||||||
|
|
||||||
|
const auto& player_memory = npad_shared_memory[NpadIdTypeToIndex(npad_id)];
|
||||||
|
DeviceIndex device_index = handle.device_index;
|
||||||
|
NpadStyleIndex style_index = handle.npad_type;
|
||||||
|
|
||||||
|
if (style_index == NpadStyleIndex::Handheld) {
|
||||||
|
u8 unknown_value_1 = 0;
|
||||||
|
u8 unknown_value_2 = 0;
|
||||||
|
u8 shared_mem_value = 0;
|
||||||
|
|
||||||
|
u8 unknown_data = 0;
|
||||||
|
if (unknown_value_1 == 2 && shared_mem_value == 2 || (unknown_value_2 >> 3 & 1) != 0) {
|
||||||
|
switch (npad_id) {
|
||||||
|
case NpadIdType::Player1:
|
||||||
|
case NpadIdType::Player2:
|
||||||
|
case NpadIdType::Player3:
|
||||||
|
case NpadIdType::Player4:
|
||||||
|
case NpadIdType::Player5:
|
||||||
|
case NpadIdType::Player6:
|
||||||
|
case NpadIdType::Player7:
|
||||||
|
unknown_data = 0;
|
||||||
|
break;
|
||||||
|
case NpadIdType::Other:
|
||||||
|
unknown_data = 0;
|
||||||
|
break;
|
||||||
|
case NpadIdType::Handheld:
|
||||||
|
unknown_data = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// This should crash console
|
||||||
|
ASSERT_MSG("Invalid npad id");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unknown_data != 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (style_index == NpadStyleIndex::FullKey) {
|
||||||
|
device_index = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return player_memory;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
ResourceManager::ResourceManager(Core::System& system_) : service_context{system_, "hid"} {}
|
||||||
|
|
||||||
|
ResourceManager::~ResourceManager() = default;
|
||||||
|
|
||||||
|
void ResourceManager::Initialize() {
|
||||||
|
debug_pad = std::make_shared<DebugPad>();
|
||||||
|
gesture = std::make_shared<Gesture>();
|
||||||
|
keyboard = std::make_shared<Keyboard>();
|
||||||
|
mouse = std::make_shared<Mouse>();
|
||||||
|
npad = std::make_shared<Npad>(service_context, this);
|
||||||
|
palma = std::make_shared<Palma>();
|
||||||
|
sixaxis = std::make_shared<SixAxis>();
|
||||||
|
touch_screen = std::make_shared<TouchScreen>();
|
||||||
|
|
||||||
|
is_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceManager::VerifiyInitalization() {
|
||||||
|
if (!is_initialized) {
|
||||||
|
Initialize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ResourceManager::GetVibrationDeviceInfo(VibrationDeviceInfo& out_device_info,
|
||||||
|
const VibrationDeviceHandle& handle) const {
|
||||||
|
out_device_info.type = VibrationDeviceType::Unknown;
|
||||||
|
out_device_info.position = VibrationDevicePosition::None;
|
||||||
|
|
||||||
|
switch (handle.npad_style_index) {
|
||||||
|
case NpadStyleIndex::FullKey:
|
||||||
|
case NpadStyleIndex::Handheld:
|
||||||
|
case NpadStyleIndex::JoyconDual:
|
||||||
|
case NpadStyleIndex::JoyconLeft:
|
||||||
|
case NpadStyleIndex::JoyconRight:
|
||||||
|
case NpadStyleIndex::GameCube:
|
||||||
|
case NpadStyleIndex::N64:
|
||||||
|
case NpadStyleIndex::SystemExt:
|
||||||
|
case NpadStyleIndex::System:
|
||||||
|
// These support vibration
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return ResultVibrationInvalidStyleIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsNpadIdValid(static_cast<NpadIdType>(handle.npad_id))) {
|
||||||
|
return ResultVibrationInvalidNpadId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handle.device_index >= DeviceIndex::MaxDeviceInfo) {
|
||||||
|
return ResultVibrationDeviceIndexOutOfRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool check_device_index = false;
|
||||||
|
switch (handle.npad_style_index) {
|
||||||
|
case NpadStyleIndex::FullKey:
|
||||||
|
case NpadStyleIndex::Handheld:
|
||||||
|
case NpadStyleIndex::JoyconDual:
|
||||||
|
case NpadStyleIndex::JoyconLeft:
|
||||||
|
case NpadStyleIndex::JoyconRight:
|
||||||
|
out_device_info.type = VibrationDeviceType::LinearResonantActuator;
|
||||||
|
check_device_index = true;
|
||||||
|
break;
|
||||||
|
case NpadStyleIndex::GameCube:
|
||||||
|
out_device_info.type = VibrationDeviceType::GcErm;
|
||||||
|
break;
|
||||||
|
case NpadStyleIndex::N64:
|
||||||
|
out_device_info.type = VibrationDeviceType::N64;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
out_device_info.type = VibrationDeviceType::Unknown;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check_device_index) {
|
||||||
|
switch (handle.device_index) {
|
||||||
|
case DeviceIndex::Left:
|
||||||
|
out_device_info.position = VibrationDevicePosition::Left;
|
||||||
|
break;
|
||||||
|
case DeviceIndex::Right:
|
||||||
|
out_device_info.position = VibrationDevicePosition::Right;
|
||||||
|
break;
|
||||||
|
case DeviceIndex::None:
|
||||||
|
default:
|
||||||
|
ASSERT_MSG("DeviceIndex should never be None!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ResourceManager::CheckVibrationAvailability(const u64 aruid, bool& out_is_enabled) const {
|
||||||
|
// TODO: Replace this with actual active aruid
|
||||||
|
u64 active_aruid = aruid;
|
||||||
|
|
||||||
|
if (aruid != 0 && active_aruid != aruid) {
|
||||||
|
out_is_enabled = false;
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_is_enabled = true;
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<DebugPad> ResourceManager::GetDebugPad() {
|
||||||
|
return debug_pad;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Gesture> ResourceManager::GetGesture() {
|
||||||
|
return gesture;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Keyboard> ResourceManager::GetKeyboard() {
|
||||||
|
return keyboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Mouse> ResourceManager::GetMouse() {
|
||||||
|
return mouse;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Mouse> ResourceManager::GetDebugMouse() {
|
||||||
|
return debug_mouse;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Npad> ResourceManager::GetNpad() {
|
||||||
|
return npad;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Palma> ResourceManager::GetPalma() {
|
||||||
|
return palma;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SixAxis> ResourceManager::GetSixAxis() {
|
||||||
|
return sixaxis;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SixAxis> ResourceManager::GetConsoleSixAxis() {
|
||||||
|
return sixaxis;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SixAxis> ResourceManager::GetSevenSixAxis() {
|
||||||
|
return sixaxis;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<TouchScreen> ResourceManager::GetTouchScreen() {
|
||||||
|
return touch_screen;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Vibration> ResourceManager::GetVibration(const VibrationDeviceHandle& handle) {
|
||||||
|
if (IsVibrationHandleValid(handle).IsError()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
switch (handle.npad_style_index) {
|
||||||
|
case NpadStyleIndex::FullKey:
|
||||||
|
case NpadStyleIndex::Handheld:
|
||||||
|
case NpadStyleIndex::JoyconDual:
|
||||||
|
case NpadStyleIndex::JoyconLeft:
|
||||||
|
case NpadStyleIndex::JoyconRight:
|
||||||
|
case NpadStyleIndex::SystemExt:
|
||||||
|
case NpadStyleIndex::System:
|
||||||
|
// These support vibration
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
/*return GetNpad()
|
||||||
|
->GetAbstractNpad(static_cast<NpadIdType>(handle.npad_id))
|
||||||
|
->GetVibration(handle.device_index);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Vibration> ResourceManager::GetGCVibration(const VibrationDeviceHandle& handle) {
|
||||||
|
if (IsVibrationHandleValid(handle).IsError()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (handle.npad_style_index != NpadStyleIndex::GameCube) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
// return GetNpad()->GetAbstractNpad(static_cast<NpadIdType>(handle.npad_id))->GetGcVibration();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Vibration> ResourceManager::GetN64Vibration(const VibrationDeviceHandle& handle) {
|
||||||
|
if (IsVibrationHandleValid(handle).IsError()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (handle.npad_style_index != NpadStyleIndex::N64) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
// return
|
||||||
|
// GetNpad()->GetAbstractNpad(static_cast<NpadIdType>(handle.npad_id))->GetN64Vibration();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::HID
|
|
@ -0,0 +1,73 @@
|
||||||
|
// 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 Service::HID {
|
||||||
|
struct VibrationDeviceInfo;
|
||||||
|
struct VibrationDeviceHandle;
|
||||||
|
|
||||||
|
class DebugPad;
|
||||||
|
class Gesture;
|
||||||
|
class Keyboard;
|
||||||
|
class Mouse;
|
||||||
|
class Npad;
|
||||||
|
class Palma;
|
||||||
|
class SixAxis;
|
||||||
|
class TouchScreen;
|
||||||
|
} // namespace Service::HID
|
||||||
|
|
||||||
|
namespace Service::HID {
|
||||||
|
class Vibration {};
|
||||||
|
|
||||||
|
class ResourceManager {
|
||||||
|
public:
|
||||||
|
explicit ResourceManager(Core::System& system_);
|
||||||
|
~ResourceManager();
|
||||||
|
|
||||||
|
void Initialize();
|
||||||
|
void VerifiyInitalization();
|
||||||
|
|
||||||
|
Result GetVibrationDeviceInfo(VibrationDeviceInfo& out_device_info,
|
||||||
|
const VibrationDeviceHandle& handle) const;
|
||||||
|
Result CheckVibrationAvailability(const u64 aruid, bool& out_is_enabled) const;
|
||||||
|
|
||||||
|
std::shared_ptr<DebugPad> GetDebugPad();
|
||||||
|
std::shared_ptr<Gesture> GetGesture();
|
||||||
|
std::shared_ptr<Keyboard> GetKeyboard();
|
||||||
|
std::shared_ptr<Mouse> GetMouse();
|
||||||
|
std::shared_ptr<Mouse> GetDebugMouse();
|
||||||
|
std::shared_ptr<Npad> GetNpad();
|
||||||
|
std::shared_ptr<Palma> GetPalma();
|
||||||
|
std::shared_ptr<SixAxis> GetSixAxis();
|
||||||
|
std::shared_ptr<SixAxis> GetConsoleSixAxis();
|
||||||
|
std::shared_ptr<SixAxis> GetSevenSixAxis();
|
||||||
|
std::shared_ptr<TouchScreen> GetTouchScreen();
|
||||||
|
std::shared_ptr<Vibration> GetVibration(const VibrationDeviceHandle& handle);
|
||||||
|
std::shared_ptr<Vibration> GetGCVibration(const VibrationDeviceHandle& handle);
|
||||||
|
std::shared_ptr<Vibration> GetN64Vibration(const VibrationDeviceHandle& handle);
|
||||||
|
|
||||||
|
bool is_initialized;
|
||||||
|
|
||||||
|
std::shared_ptr<DebugPad> debug_pad = nullptr;
|
||||||
|
std::shared_ptr<Gesture> gesture = nullptr;
|
||||||
|
std::shared_ptr<Keyboard> keyboard = nullptr;
|
||||||
|
std::shared_ptr<Mouse> mouse = nullptr;
|
||||||
|
std::shared_ptr<Mouse> debug_mouse = nullptr;
|
||||||
|
std::shared_ptr<Npad> npad = nullptr;
|
||||||
|
std::shared_ptr<Palma> palma = nullptr;
|
||||||
|
std::shared_ptr<SixAxis> sixaxis = nullptr;
|
||||||
|
std::shared_ptr<TouchScreen> touch_screen = nullptr;
|
||||||
|
std::shared_ptr<Vibration> vibration = nullptr;
|
||||||
|
|
||||||
|
KernelHelpers::ServiceContext service_context;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::HID
|
|
@ -0,0 +1,36 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "core/hle/service/hid/resource_manager/base_resource.h"
|
||||||
|
|
||||||
|
namespace Service::HID {
|
||||||
|
|
||||||
|
// TODO: Get the actual aruid to index table
|
||||||
|
static constexpr std::array<std::pair<u64, std::size_t>, ARUID_MAX> aruid_list{
|
||||||
|
std::pair<u64, std::size_t>{0, 0}, // Default
|
||||||
|
{135, 1}, // HID
|
||||||
|
};
|
||||||
|
|
||||||
|
BaseResource::BaseResource() {}
|
||||||
|
|
||||||
|
BaseResource::~BaseResource() = default;
|
||||||
|
|
||||||
|
std::size_t BaseResource::GetIndexFromAruid(const u64 aruid) const {
|
||||||
|
for (const auto& [applet_id, index] : aruid_list) {
|
||||||
|
if (applet_id == aruid) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ARUID_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseResource::GetAruidList(std::span<u64> list) const {
|
||||||
|
const std::size_t list_size = std::min(aruid_list.size(), ARUID_MAX);
|
||||||
|
|
||||||
|
for (std::size_t index = 0; index < list_size; ++index) {
|
||||||
|
list[index] = aruid_list[index].first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::HID
|
|
@ -0,0 +1,21 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Service::HID {
|
||||||
|
constexpr std::size_t ARUID_MAX = 0x2; // Console real limit is 0x20
|
||||||
|
constexpr std::size_t PLAYERS_MAX = 10;
|
||||||
|
constexpr std::size_t SUPPORTED_NPAD_TYPES_MAX = 11;
|
||||||
|
constexpr std::size_t HID_ENTRY_COUNT = 17;
|
||||||
|
|
||||||
|
class BaseResource {
|
||||||
|
public:
|
||||||
|
explicit BaseResource();
|
||||||
|
~BaseResource();
|
||||||
|
|
||||||
|
std::size_t GetIndexFromAruid(const u64 aruid) const;
|
||||||
|
void GetAruidList(std::span<u64> list) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::HID
|
|
@ -0,0 +1,24 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "core/hle/service/hid/hid_types.h"
|
||||||
|
#include "core/hle/service/hid/hid_util.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/debug_pad.h"
|
||||||
|
|
||||||
|
namespace Service::HID {
|
||||||
|
|
||||||
|
DebugPad::DebugPad() {}
|
||||||
|
|
||||||
|
DebugPad::~DebugPad() = default;
|
||||||
|
|
||||||
|
Result DebugPad::Activate(const u64 aruid) {
|
||||||
|
is_activated = true;
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result DebugPad::Activate() {
|
||||||
|
is_activated = true;
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::HID
|
|
@ -0,0 +1,34 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include "core/hle/service/hid/resource_manager/base_resource.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Service::HID {} // namespace Service::HID
|
||||||
|
|
||||||
|
namespace Service::HID {
|
||||||
|
|
||||||
|
class DebugPad final : public BaseResource {
|
||||||
|
public:
|
||||||
|
explicit DebugPad();
|
||||||
|
~DebugPad();
|
||||||
|
|
||||||
|
Result Activate(const u64 aruid);
|
||||||
|
Result Activate();
|
||||||
|
Result Deactivate();
|
||||||
|
|
||||||
|
Result SetAutoPilotState(const DebugPadAutoPilotState& auto_pilot_state);
|
||||||
|
Result UnsetAutoPilotState();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool is_activated;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::HID
|
|
@ -0,0 +1,24 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "core/hle/service/hid/hid_types.h"
|
||||||
|
#include "core/hle/service/hid/hid_util.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/gesture.h"
|
||||||
|
|
||||||
|
namespace Service::HID {
|
||||||
|
|
||||||
|
Gesture::Gesture() {}
|
||||||
|
|
||||||
|
Gesture::~Gesture() = default;
|
||||||
|
|
||||||
|
Result Gesture::Activate(const u64 aruid, const u32 basic_gesture_id) {
|
||||||
|
is_activated = true;
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Gesture::Activate() {
|
||||||
|
is_activated = true;
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::HID
|
|
@ -0,0 +1,30 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include "core/hle/service/hid/resource_manager/base_resource.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Service::HID {} // namespace Service::HID
|
||||||
|
|
||||||
|
namespace Service::HID {
|
||||||
|
|
||||||
|
class Gesture final : public BaseResource {
|
||||||
|
public:
|
||||||
|
explicit Gesture();
|
||||||
|
~Gesture();
|
||||||
|
|
||||||
|
Result Activate(const u64 aruid, const u32 basic_gesture_id);
|
||||||
|
Result Activate();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool is_activated;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::HID
|
|
@ -0,0 +1,29 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "core/hle/service/hid/hid_types.h"
|
||||||
|
#include "core/hle/service/hid/hid_util.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/keyboard.h"
|
||||||
|
|
||||||
|
namespace Service::HID {
|
||||||
|
|
||||||
|
Keyboard::Keyboard() {}
|
||||||
|
|
||||||
|
Keyboard::~Keyboard() = default;
|
||||||
|
|
||||||
|
Result Keyboard::Activate(const u64 aruid) {
|
||||||
|
is_activated = true;
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Keyboard::Activate() {
|
||||||
|
is_activated = true;
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Keyboard::Deactivate() {
|
||||||
|
is_activated = false;
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::HID
|
|
@ -0,0 +1,38 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include "core/hle/service/hid/resource_manager/base_resource.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Service::HID {
|
||||||
|
struct KeyboardAutoPilotState;
|
||||||
|
} // namespace Service::HID
|
||||||
|
|
||||||
|
namespace Service::HID {
|
||||||
|
|
||||||
|
class Keyboard final : public BaseResource {
|
||||||
|
public:
|
||||||
|
explicit Keyboard();
|
||||||
|
~Keyboard();
|
||||||
|
|
||||||
|
Result Activate(const u64 aruid);
|
||||||
|
Result Activate();
|
||||||
|
Result Deactivate();
|
||||||
|
|
||||||
|
Result SetAutoPilotState(const KeyboardAutoPilotState& auto_pilot_state);
|
||||||
|
Result UnsetAutoPilotState();
|
||||||
|
|
||||||
|
Result SendLockKeyEvent(const u32 keyboard_lock_key_event);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool is_activated;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::HID
|
|
@ -0,0 +1,23 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "core/hle/service/hid/hid_types.h"
|
||||||
|
#include "core/hle/service/hid/hid_util.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/mouse.h"
|
||||||
|
|
||||||
|
namespace Service::HID {
|
||||||
|
|
||||||
|
Mouse::Mouse() {}
|
||||||
|
|
||||||
|
Mouse::~Mouse() = default;
|
||||||
|
|
||||||
|
Result Mouse::Activate(const u64 aruid) {
|
||||||
|
is_activated = true;
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Mouse::Activate() {
|
||||||
|
is_activated = true;
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
} // namespace Service::HID
|
|
@ -0,0 +1,36 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include "core/hle/service/hid/resource_manager/base_resource.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Service::HID {
|
||||||
|
struct MouseAutoPilotState;
|
||||||
|
} // namespace Service::HID
|
||||||
|
|
||||||
|
namespace Service::HID {
|
||||||
|
|
||||||
|
class Mouse final : public BaseResource {
|
||||||
|
public:
|
||||||
|
explicit Mouse();
|
||||||
|
~Mouse();
|
||||||
|
|
||||||
|
Result Activate(const u64 aruid);
|
||||||
|
Result Activate();
|
||||||
|
Result Deactivate();
|
||||||
|
|
||||||
|
Result SetAutoPilotState(const MouseAutoPilotState& auto_pilot_state);
|
||||||
|
Result UnsetAutoPilotState();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool is_activated;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::HID
|
|
@ -0,0 +1,960 @@
|
||||||
|
// 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/service/hid/hid_result.h"
|
||||||
|
#include "core/hle/service/hid/hid_types.h"
|
||||||
|
#include "core/hle/service/hid/hid_util.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/npad_resource/npad.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/npad_resource/npad_controller_state.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/npad_resource/npad_shared_types.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/npad_resource/npad_state.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/palma.h"
|
||||||
|
|
||||||
|
namespace Service::HID {
|
||||||
|
|
||||||
|
AbstractNpadState::AbstractNpadState() {}
|
||||||
|
AbstractNpadState::~AbstractNpadState() = default;
|
||||||
|
|
||||||
|
Result AbstractNpadState::ActivateNpad(const u64 aruid) {
|
||||||
|
Result result = ActivateUnknown();
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
result = UpdateNpadLifo(aruid);
|
||||||
|
if (result.IsError()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result = UpdateSixaxisLifo(aruid);
|
||||||
|
if (result.IsError()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result = UpdateBatteryLifo(aruid);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result AbstractNpadState::ActivateUnknown() {
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result AbstractNpadState::UpdateNpadLifo(const u64 aruid) {
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
Result AbstractNpadState::UpdateSixaxisLifo(const u64 aruid) {
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
Result AbstractNpadState::UpdateBatteryLifo(const u64 aruid) {
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractNpadState::UpdateNpadLifoImpl(const BatteryState& battery_state,
|
||||||
|
NpadInternalState& internal_state) {}
|
||||||
|
void AbstractNpadState::UpdateSixaxisLifoImpl(const BatteryState& battery_state,
|
||||||
|
NpadInternalState& internal_state) {}
|
||||||
|
|
||||||
|
void AbstractNpadState::UpdateBatteryLifoImpl(const BatteryState& battery_state,
|
||||||
|
NpadInternalState& internal_state) {
|
||||||
|
NPadSystemProperties properties{};
|
||||||
|
|
||||||
|
if (battery_state.is_powered_joy_dual) {
|
||||||
|
properties.is_powered_joy_dual.Assign(1);
|
||||||
|
}
|
||||||
|
if (battery_state.is_powered_joy_left) {
|
||||||
|
properties.is_powered_joy_left.Assign(1);
|
||||||
|
}
|
||||||
|
if (battery_state.is_powered_joy_right) {
|
||||||
|
properties.is_powered_joy_right.Assign(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (battery_state.is_charging_joy_dual) {
|
||||||
|
properties.is_charging_joy_dual.Assign(1);
|
||||||
|
}
|
||||||
|
if (battery_state.is_charging_joy_left) {
|
||||||
|
properties.is_charging_joy_left.Assign(1);
|
||||||
|
}
|
||||||
|
if (battery_state.is_charging_joy_right) {
|
||||||
|
properties.is_charging_joy_right.Assign(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal_state.system_properties = properties;
|
||||||
|
internal_state.battery_level_dual = battery_state.battery_level_dual;
|
||||||
|
internal_state.battery_level_left = battery_state.battery_level_left;
|
||||||
|
internal_state.battery_level_right = battery_state.battery_level_right;
|
||||||
|
}
|
||||||
|
|
||||||
|
Npad::Npad(KernelHelpers::ServiceContext& context, ResourceManager* resource)
|
||||||
|
: service_context{context}, resource_manager{resource} {
|
||||||
|
for (auto& npad : npad_state) {
|
||||||
|
npad = std::make_shared<NpadState>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<u64, 1> aruid_list{};
|
||||||
|
GetAruidList(aruid_list);
|
||||||
|
|
||||||
|
active_aruid = aruid_list[0];
|
||||||
|
active_npad_state = npad_state[active_aruid];
|
||||||
|
}
|
||||||
|
|
||||||
|
Npad::~Npad() = default;
|
||||||
|
|
||||||
|
Result Npad::Activate(const u64 aruid) {
|
||||||
|
// No mistake was made here. It uses two different locks
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
std::scoped_lock recursive_lock{recursive_mutex};
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < PLAYERS_MAX; ++i) {
|
||||||
|
const Result result = abstract_npad_state[i]->ActivateNpad(aruid);
|
||||||
|
if (result.IsError()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Npad::ActivateWithRevision(const u64 aruid, const NpadRevision revision) {
|
||||||
|
const auto index = GetIndexFromAruid(aruid);
|
||||||
|
|
||||||
|
if (index >= ARUID_MAX) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
npad_state[index]->SetNpadRevision(revision);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Npad::DisconnectNpad(const u64 aruid, const NpadIdType npad_id) {
|
||||||
|
if (aruid != GetNpadActiveAruid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& state = active_npad_state->GetControllerState(npad_id);
|
||||||
|
DisconnectAbstractPad(state.GetNpadId());
|
||||||
|
state.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Npad::ForceDisconnectNpad(const NpadIdType npad_id) {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
DisconnectNpad(GetNpadActiveAruid(), npad_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Npad::DisconnectAbstractPad(const NpadIdType npad_id) {}
|
||||||
|
|
||||||
|
Result Npad::SetNpadJoyHoldType(const u64 aruid, const NpadJoyHoldType hold_type) {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
const auto index = GetIndexFromAruid(aruid);
|
||||||
|
|
||||||
|
if (index >= ARUID_MAX) {
|
||||||
|
return ResultNpadNotConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
npad_state[index]->SetNpadJoyHoldType(hold_type);
|
||||||
|
if (active_aruid == aruid) {
|
||||||
|
active_npad_state->SetNpadJoyHoldType(hold_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::GetNpadJoyHoldType(const u64 aruid, NpadJoyHoldType& out_hold_type) const {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
const auto index = GetIndexFromAruid(aruid);
|
||||||
|
|
||||||
|
if (index >= ARUID_MAX) {
|
||||||
|
return ResultNpadNotConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& state = npad_state[index];
|
||||||
|
out_hold_type = state->GetNpadJoyHoldType();
|
||||||
|
if (state->GetStatus().is_policy || state->GetStatus().is_full_policy) {
|
||||||
|
out_hold_type = active_npad_state->GetNpadJoyHoldType();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::SetSupportedNpadIdType(const u64 aruid, std::span<const NpadIdType> list) {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
if (list.size() >= SUPPORTED_NPAD_TYPES_MAX) {
|
||||||
|
return ResultInvalidArraySize;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result result = SetSupportedNpadIdTypeImpl(aruid, list);
|
||||||
|
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
UpdateSupportedNpadIdType();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::SetSupportedNpadIdTypeImpl(const u64 aruid, std::span<const NpadIdType> list) {
|
||||||
|
if (list.size() > SUPPORTED_NPAD_TYPES_MAX) {
|
||||||
|
return ResultInvalidArraySize;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto index = GetIndexFromAruid(aruid);
|
||||||
|
|
||||||
|
if (index >= ARUID_MAX) {
|
||||||
|
return ResultNpadNotConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result result = npad_state[index]->SetSupportedNpadIdType(list);
|
||||||
|
|
||||||
|
if (active_aruid == aruid && result.IsSuccess()) {
|
||||||
|
result = active_npad_state->SetSupportedNpadIdType(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::SetSupportedNpadStyleSet(const u64 aruid, const NpadStyleSet supported_style_set) {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
const Result result = SetSupportedNpadStyleSetImpl(aruid, supported_style_set);
|
||||||
|
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
UpdateSupportedStyleSet();
|
||||||
|
resource_manager->GetPalma()->SetIsPalmaPairedConnectable(aruid, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::SetSupportedNpadStyleSetImpl(const u64 aruid, const NpadStyleSet supported_style_set) {
|
||||||
|
const auto index = GetIndexFromAruid(aruid);
|
||||||
|
|
||||||
|
if (index >= ARUID_MAX) {
|
||||||
|
return ResultNpadNotConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& state = npad_state[index];
|
||||||
|
state->SetSupportedNpadStyleSet(supported_style_set);
|
||||||
|
|
||||||
|
if (active_aruid == aruid) {
|
||||||
|
active_npad_state->SetSupportedNpadStyleSet(supported_style_set);
|
||||||
|
active_npad_state->SetNpadJoyHoldType(state->GetNpadJoyHoldType());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::GetSupportedNpadStyleSet(const u64 aruid,
|
||||||
|
NpadStyleSet& out_supported_style_set) const {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
const Result result = GetSupportedNpadStyleSetImpl(aruid, out_supported_style_set);
|
||||||
|
|
||||||
|
if (result == ResultNpadNotConnected) {
|
||||||
|
out_supported_style_set = NpadStyleSet::None;
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::GetSupportedNpadStyleSetImpl(const u64 aruid,
|
||||||
|
NpadStyleSet& out_supported_style_set) const {
|
||||||
|
const auto index = GetIndexFromAruid(aruid);
|
||||||
|
|
||||||
|
if (index >= ARUID_MAX) {
|
||||||
|
return ResultNpadNotConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (npad_state[index]->GetStatus().is_supported_styleset_set == 0) {
|
||||||
|
return ResultUndefinedStyleSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_supported_style_set = npad_state[index]->GetSupportedNpadStyleSet();
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Npad::IsFirmwareUpdateAvailableForSixAxisSensor(const SixAxisSensorHandle& handle) const {
|
||||||
|
// Not implemented
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::ResetIsSixAxisSensorDeviceNewlyAssigned(const u64 aruid,
|
||||||
|
const SixAxisSensorHandle& handle) {
|
||||||
|
// auto npad_index = NpadIdTypeToIndex(static_cast<NpadIdType>(handle.device_index));
|
||||||
|
|
||||||
|
// TODO: Implement this part
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
SixAxisSensorSharedState Npad::GetSixAxisSensorState(const SixAxisSensorHandle& handle) {
|
||||||
|
auto npad_index = NpadIdTypeToIndex(static_cast<NpadIdType>(handle.device_index));
|
||||||
|
if (!IsNpadIdValid(static_cast<NpadIdType>(handle.npad_id))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& abtract = abstract_npad_state[npad_index];
|
||||||
|
|
||||||
|
if (handle.npad_type == NpadStyleIndex::FullKey) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Implement this part
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SixAxisSensorSharedConfig> Npad::GetSixAxisSensorConfig(const SixAxisSensorHandle& handle) {
|
||||||
|
auto npad_index = NpadIdTypeToIndex(static_cast<NpadIdType>(handle.device_index));
|
||||||
|
if (!IsNpadIdValid(static_cast<NpadIdType>(handle.npad_id))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& abtract = abstract_npad_state[npad_index];
|
||||||
|
|
||||||
|
if (handle.npad_type == NpadStyleIndex::FullKey) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
void Npad::SetNpadJoyAssignmentModeSingleByDefault(const u64 aruid, const NpadIdType npad_id) {
|
||||||
|
if (aruid != GetNpadActiveAruid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetNpadJoyAssignmentMode(nullptr, aruid, npad_id, NpadJoyDeviceType::Left);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Npad::SetNpadJoyAssignmentModeSingle(const u64 aruid, const NpadIdType npad_id,
|
||||||
|
const NpadJoyDeviceType npad_joy_device_type) {
|
||||||
|
if (aruid != GetNpadActiveAruid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetNpadJoyAssignmentMode(nullptr, aruid, npad_id, npad_joy_device_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Npad::SetNpadJoyAssignmentModeSingleWithDestination(
|
||||||
|
NpadIdType& out_npad_id, const u64 aruid, const NpadIdType npad_id,
|
||||||
|
const NpadJoyDeviceType npad_joy_device_type) {
|
||||||
|
return SetNpadJoyAssignmentMode(&out_npad_id, aruid, npad_id, npad_joy_device_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Npad::SetNpadJoyAssignmentMode(NpadIdType* out_npad_id, const u64 aruid,
|
||||||
|
const NpadIdType npad_id,
|
||||||
|
const NpadJoyDeviceType npad_joy_device_type) {
|
||||||
|
if (!IsNpadIdValid(npad_id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (aruid != GetNpadActiveAruid()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// TODO: Implement this
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Npad::SetNpadJoyAssignmentModeDual(const u64 aruid, const NpadIdType npad_id) {
|
||||||
|
if (!IsNpadIdValid(npad_id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (aruid != GetNpadActiveAruid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Implement this
|
||||||
|
|
||||||
|
auto& state = active_npad_state->GetControllerState(npad_id);
|
||||||
|
state.SetNpadAssignmentMode(NpadJoyAssignmentMode::Dual);
|
||||||
|
state.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::MergeSingleJoyAsDualJoy(const u64 aruid, const NpadIdType npad_id_1,
|
||||||
|
const NpadIdType npad_id_2) {
|
||||||
|
if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) {
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
if (aruid != GetNpadActiveAruid()) {
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& state_1 = active_npad_state->GetControllerState(npad_id_1);
|
||||||
|
auto& state_2 = active_npad_state->GetControllerState(npad_id_2);
|
||||||
|
|
||||||
|
if (state_1.IsUpdatePending() != 0) {
|
||||||
|
state_1.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state_2.IsUpdatePending() != 0) {
|
||||||
|
state_2.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto style_index_1 = state_1.GetConnectedControllerIndex();
|
||||||
|
const auto style_index_2 = state_2.GetConnectedControllerIndex();
|
||||||
|
|
||||||
|
if (style_index_1 == 2 && style_index_2 == 2) {
|
||||||
|
return ResultNpadIsSameType;
|
||||||
|
}
|
||||||
|
if (style_index_1 == 4 && style_index_2 == 4) {
|
||||||
|
return ResultNpadIsSameType;
|
||||||
|
}
|
||||||
|
if (style_index_1 == 4 && style_index_2 != 2) {
|
||||||
|
return ResultNpadIsDualJoycon;
|
||||||
|
}
|
||||||
|
if (style_index_1 == 2 && style_index_2 != 4) {
|
||||||
|
return ResultNpadIsDualJoycon;
|
||||||
|
}
|
||||||
|
if (style_index_1 != 4 && style_index_1 != 2) {
|
||||||
|
return ResultNpadIsDualJoycon;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (style_index_1 == 4) {
|
||||||
|
// Save some global value
|
||||||
|
} else {
|
||||||
|
// Some global value
|
||||||
|
}
|
||||||
|
|
||||||
|
// something = state_2->SomeFunction(someglobal);
|
||||||
|
|
||||||
|
state_1.SetNpadAssignmentMode(NpadJoyAssignmentMode::Dual);
|
||||||
|
state_2.SetNpadAssignmentMode(NpadJoyAssignmentMode::Dual);
|
||||||
|
|
||||||
|
// if (something != 0) {
|
||||||
|
// fun(npad_id_1, something, 0);
|
||||||
|
// }
|
||||||
|
|
||||||
|
state_1.Update();
|
||||||
|
state_2.Update();
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::SwapNpadAssignment(const u64 aruid, const NpadIdType npad_id_1,
|
||||||
|
const NpadIdType npad_id_2) {
|
||||||
|
if (aruid != GetNpadActiveAruid()) {
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) {
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::StartLrAssignmentMode(const u64 aruid) {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
bool is_enabled{};
|
||||||
|
Result result = GetLrAssignmentMode(is_enabled, aruid);
|
||||||
|
|
||||||
|
if (result.IsSuccess() && !is_enabled) {
|
||||||
|
result = SetLrAssignmentMode(aruid, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::StopLrAssignmentMode(const u64 aruid) {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
bool is_enabled{};
|
||||||
|
Result result = GetLrAssignmentMode(is_enabled, aruid);
|
||||||
|
|
||||||
|
if (result.IsSuccess() && is_enabled) {
|
||||||
|
result = SetLrAssignmentMode(aruid, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::SetLrAssignmentMode(const u64 aruid, const bool is_enabled) {
|
||||||
|
const auto index = GetIndexFromAruid(aruid);
|
||||||
|
|
||||||
|
if (index >= ARUID_MAX) {
|
||||||
|
return ResultNpadNotConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
npad_state[index]->SetLrAssignmentMode(is_enabled);
|
||||||
|
if (active_aruid == aruid) {
|
||||||
|
active_npad_state->SetLrAssignmentMode(is_enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::GetLrAssignmentMode(bool& out_is_enabled, const u64 aruid) const {
|
||||||
|
const auto index = GetIndexFromAruid(aruid);
|
||||||
|
|
||||||
|
if (index >= ARUID_MAX) {
|
||||||
|
return ResultNpadNotConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_is_enabled = npad_state[index]->GetLrAssignmentMode();
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::SetNpadHandheldActivationMode(const u64 aruid, const NpadHandheldActivationMode mode) {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
const Result result = SetNpadHandheldActivationModeImpl(aruid, mode);
|
||||||
|
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
// TODO: recheck this part
|
||||||
|
active_npad_state->GetControllerState(NpadIdType::Handheld).Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::SetNpadHandheldActivationModeImpl(const u64 aruid,
|
||||||
|
const NpadHandheldActivationMode mode) {
|
||||||
|
const auto index = GetIndexFromAruid(aruid);
|
||||||
|
|
||||||
|
if (index >= ARUID_MAX) {
|
||||||
|
return ResultNpadNotConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
npad_state[index]->SetNpadHandheldActivationMode(mode);
|
||||||
|
if (active_aruid == aruid) {
|
||||||
|
active_npad_state->SetNpadHandheldActivationMode(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::GetNpadHandheldActivationMode(const u64 aruid,
|
||||||
|
NpadHandheldActivationMode& out_mode) const {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
return GetNpadHandheldActivationModeImpl(aruid, out_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::GetNpadHandheldActivationModeImpl(const u64 aruid,
|
||||||
|
NpadHandheldActivationMode& out_mode) const {
|
||||||
|
const auto index = GetIndexFromAruid(aruid);
|
||||||
|
|
||||||
|
if (index >= ARUID_MAX) {
|
||||||
|
return ResultNpadNotConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_mode = npad_state[index]->GetNpadHandheldActivationMode();
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::IsUnintendedHomeButtonInputProtectionEnabled(bool& out_is_enabled, const u64 aruid,
|
||||||
|
const NpadIdType npad_id) const {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
return IsUnintendedHomeButtonInputProtectionEnabledImpl(out_is_enabled, aruid, npad_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::IsUnintendedHomeButtonInputProtectionEnabledImpl(bool& out_is_enabled, const u64 aruid,
|
||||||
|
const NpadIdType npad_id) const {
|
||||||
|
const auto index = GetIndexFromAruid(aruid);
|
||||||
|
|
||||||
|
if (index >= ARUID_MAX) {
|
||||||
|
return ResultNpadNotConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_is_enabled = npad_state[index]->IsUnintendedHomeButtonInputProtectionEnabled(npad_id);
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::EnableUnintendedHomeButtonInputProtection(const u64 aruid, const NpadIdType npad_id,
|
||||||
|
const bool is_enabled) {
|
||||||
|
// tooo complicated
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Npad::SetNpadAnalogStickUseCenterClamp(const u64 aruid, const bool use_center_clamp) {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
SetNpadAnalogStickUseCenterClampImpl(aruid, use_center_clamp);
|
||||||
|
// update abstract handles
|
||||||
|
// UpdateAbstractCenterClamp(GetAbstractHandle(param_1->abstract_active_player));
|
||||||
|
// UpdateAbstractCenterClamp(GetAbstractHandle(param_1->abstract_active_player+1));
|
||||||
|
// UpdateAbstractCenterClamp(GetAbstractHandle(param_1->abstract_active_player+2));
|
||||||
|
// UpdateAbstractCenterClamp(GetAbstractHandle(param_1->abstract_active_player+3));
|
||||||
|
// UpdateAbstractCenterClamp(GetAbstractHandle(param_1->abstract_active_player+4));
|
||||||
|
// UpdateAbstractCenterClamp(GetAbstractHandle(param_1->abstract_active_player+5));
|
||||||
|
// UpdateAbstractCenterClamp(GetAbstractHandle(param_1->abstract_active_player+6));
|
||||||
|
// UpdateAbstractCenterClamp(GetAbstractHandle(param_1->abstract_active_player+7));
|
||||||
|
// UpdateAbstractCenterClamp(GetAbstractHandle(param_1->abstract_active_player+8));
|
||||||
|
// UpdateAbstractCenterClamp(GetAbstractHandle(param_1->abstract_active_player+9));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::SetNpadAnalogStickUseCenterClampImpl(const u64 aruid, const bool use_center_clamp) {
|
||||||
|
const auto index = GetIndexFromAruid(aruid);
|
||||||
|
|
||||||
|
if (index >= ARUID_MAX) {
|
||||||
|
return ResultNpadNotConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
npad_state[index]->SetNpadAnalogStickUseCenterClampImpl(use_center_clamp);
|
||||||
|
if (active_aruid == aruid) {
|
||||||
|
active_npad_state->SetNpadAnalogStickUseCenterClampImpl(use_center_clamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::SetNpadCaptureButtonAssignment(const u64 aruid, const NpadStyleSet npad_styleset,
|
||||||
|
const NpadButton npad_button_set) {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
const auto index = GetIndexFromAruid(aruid);
|
||||||
|
|
||||||
|
if (index >= ARUID_MAX) {
|
||||||
|
return ResultNpadNotConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must be a power of two
|
||||||
|
const auto raw_styleset = static_cast<u32>(npad_styleset);
|
||||||
|
if (raw_styleset == 0 && (raw_styleset & (raw_styleset - 1)) != 0) {
|
||||||
|
return ResultInvalidStyleSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
int style_index{};
|
||||||
|
NpadStyleSet style_selected{};
|
||||||
|
for (style_index = 0; style_index < 7; ++style_index) {
|
||||||
|
style_selected = GetStylesetByIndex(style_index);
|
||||||
|
if (npad_styleset == style_selected) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (style_selected == NpadStyleSet::None) {
|
||||||
|
return ResultInvalidStyleSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
npad_state[index]->SetCaptureButtonAssignment(style_index, npad_button_set);
|
||||||
|
if (active_aruid == aruid) {
|
||||||
|
active_npad_state->SetCaptureButtonAssignment(style_index, npad_button_set);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::ClearNpadCaptureButtonAssignment(const u64 aruid) {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
const auto index = GetIndexFromAruid(aruid);
|
||||||
|
|
||||||
|
if (index >= ARUID_MAX) {
|
||||||
|
return ResultNpadNotConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::size_t style_index = 0; style_index < 7; ++style_index) {
|
||||||
|
npad_state[index]->SetCaptureButtonAssignment(style_index, NpadButton::None);
|
||||||
|
if (active_aruid == aruid) {
|
||||||
|
active_npad_state->SetCaptureButtonAssignment(style_index, NpadButton::None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t Npad::GetNpadCaptureButtonAssignment(
|
||||||
|
const u64 aruid, std::span<NpadButton> out_button_assignment) const {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
const auto index = GetIndexFromAruid(aruid);
|
||||||
|
|
||||||
|
if (index >= ARUID_MAX) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return npad_state[index]->GetCaptureButtonAssignment(out_button_assignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::AcquireNpadStyleSetUpdateEventHandle(const u64 aruid,
|
||||||
|
Kernel::KReadableEvent** out_event,
|
||||||
|
const NpadIdType npad_id) {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
const auto index = GetIndexFromAruid(aruid);
|
||||||
|
|
||||||
|
if (index >= ARUID_MAX) {
|
||||||
|
return ResultNpadNotConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& state = npad_state[index]->GetControllerState(npad_id);
|
||||||
|
if (!state.IsStyleSetUpdateEventInitialized()) {
|
||||||
|
state.SetStyleSetUpdateEventInitialized(false);
|
||||||
|
|
||||||
|
// Auto clear = true
|
||||||
|
Kernel::KEvent* styleset_update_event =
|
||||||
|
service_context.CreateEvent("ResourceManager:Npad:StylesetUpdateEvent");
|
||||||
|
state.SetNpadStyleSetUpdateEvent(std::move(styleset_update_event));
|
||||||
|
|
||||||
|
// Assume creating the event succeeds otherwise crash the system here
|
||||||
|
state.SetStyleSetUpdateEventInitialized(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_event = &state.GetNpadStyleSetUpdateEvent();
|
||||||
|
|
||||||
|
if (state.IsStyleSetUpdateEventInitialized()) {
|
||||||
|
state.SignalStyleSetUpdateEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::ClearNpadSystemCommonPolicy(const u64 aruid) {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
const Result result = ClearNpadSystemCommonPolicyImpl(aruid);
|
||||||
|
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
// UpdateSystemCommonPolicy();
|
||||||
|
// SetIsPalmaPairedConnectable();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::ClearNpadSystemCommonPolicyImpl(const u64 aruid) {
|
||||||
|
const auto index = GetIndexFromAruid(aruid);
|
||||||
|
|
||||||
|
if (index >= ARUID_MAX) {
|
||||||
|
return ResultNpadNotConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
npad_state[index]->ClearNpadSystemCommonPolicy();
|
||||||
|
if (active_aruid == aruid) {
|
||||||
|
active_npad_state->ClearNpadSystemCommonPolicy();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::ApplyNpadSystemCommonPolicy(const u64 aruid) {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
const Result result = ApplyNpadSystemCommonPolicyImpl(aruid, false);
|
||||||
|
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
// UpdateSystemCommonPolicy();
|
||||||
|
const bool is_connectable = true; //(*param_1 + 4) >> 6 & 1
|
||||||
|
resource_manager->GetPalma()->SetIsPalmaPairedConnectable(aruid, is_connectable);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::ApplyNpadSystemCommonPolicyFull(const u64 aruid) {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
const Result result = ApplyNpadSystemCommonPolicyImpl(aruid, true);
|
||||||
|
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
// UpdateSystemCommonPolicy();
|
||||||
|
const bool is_connectable = true; //(*param_1 + 4) >> 6 & 1
|
||||||
|
resource_manager->GetPalma()->SetIsPalmaPairedConnectable(aruid, is_connectable);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::ApplyNpadSystemCommonPolicyImpl(const u64 aruid, const bool is_full_policy) {
|
||||||
|
const auto index = GetIndexFromAruid(aruid);
|
||||||
|
|
||||||
|
if (index >= ARUID_MAX) {
|
||||||
|
return ResultNpadNotConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
npad_state[index]->ApplyNpadSystemCommonPolicy(is_full_policy);
|
||||||
|
npad_state[index]->SetNpadJoyHoldType(default_joy_hold_type);
|
||||||
|
if (active_aruid == aruid) {
|
||||||
|
active_npad_state->ApplyNpadSystemCommonPolicy(is_full_policy);
|
||||||
|
npad_state[index]->SetNpadJoyHoldType(default_joy_hold_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::AssigningSingleOnSlSrPress(const u64 aruid, const bool is_enabled) {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
bool is_currently_enabled{};
|
||||||
|
Result result = GetAssigningSingleOnSlSrPress(aruid, is_currently_enabled);
|
||||||
|
|
||||||
|
if (result.IsSuccess() && is_currently_enabled != is_enabled) {
|
||||||
|
result = SetAssigningSingleOnSlSrPress(aruid, is_enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::GetAssigningSingleOnSlSrPress(const u64 aruid, bool out_is_enabled) const {
|
||||||
|
const auto index = GetIndexFromAruid(aruid);
|
||||||
|
|
||||||
|
if (index >= ARUID_MAX) {
|
||||||
|
return ResultNpadNotConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_is_enabled = npad_state[index]->GetAssigningSingleOnSlSrPress();
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::SetAssigningSingleOnSlSrPress(const u64 aruid, const bool is_enabled) {
|
||||||
|
const auto index = GetIndexFromAruid(aruid);
|
||||||
|
|
||||||
|
if (index >= ARUID_MAX) {
|
||||||
|
return ResultNpadNotConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
npad_state[index]->SetAssigningSingleOnSlSrPress(is_enabled);
|
||||||
|
if (active_aruid == aruid) {
|
||||||
|
active_npad_state->SetAssigningSingleOnSlSrPress(is_enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::GetMaskedSupportedNpadStyleSet(const u64 aruid,
|
||||||
|
NpadStyleSet& out_npad_styleset) const {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
|
||||||
|
Result result = GetMaskedSupportedNpadStyleSetImpl(aruid, out_npad_styleset);
|
||||||
|
|
||||||
|
if (result == ResultUndefinedStyleSet) {
|
||||||
|
out_npad_styleset = NpadStyleSet::None;
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::GetMaskedSupportedNpadStyleSetImpl(const u64 aruid,
|
||||||
|
NpadStyleSet& out_npad_styleset) const {
|
||||||
|
if (aruid == 0) {
|
||||||
|
out_npad_styleset = NpadStyleSet::Fullkey | NpadStyleSet::Handheld | NpadStyleSet::JoyDual |
|
||||||
|
NpadStyleSet::JoyLeft | NpadStyleSet::JoyRight | NpadStyleSet::Palma |
|
||||||
|
NpadStyleSet::SystemExt | NpadStyleSet::System;
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto index = GetIndexFromAruid(aruid);
|
||||||
|
|
||||||
|
if (index >= ARUID_MAX) {
|
||||||
|
return ResultNpadNotConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (npad_state[index]->GetStatus().is_supported_styleset_set == 0) {
|
||||||
|
return ResultUndefinedStyleSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
NpadStyleTag mask = NpadStyleSet::Fullkey | NpadStyleSet::Handheld | NpadStyleSet::JoyDual |
|
||||||
|
NpadStyleSet::JoyLeft | NpadStyleSet::JoyRight | NpadStyleSet::SystemExt |
|
||||||
|
NpadStyleSet::System;
|
||||||
|
out_npad_styleset = npad_state[index]->GetSupportedNpadStyleSet();
|
||||||
|
|
||||||
|
if (index < ARUID_MAX) {
|
||||||
|
switch (npad_state[index]->GetNpadRevision()) {
|
||||||
|
case NpadRevision::Revision1:
|
||||||
|
mask = NpadStyleSet::Fullkey | NpadStyleSet::Handheld | NpadStyleSet::JoyDual |
|
||||||
|
NpadStyleSet::JoyLeft | NpadStyleSet::JoyRight | NpadStyleSet::Gc |
|
||||||
|
NpadStyleSet::SystemExt | NpadStyleSet::System;
|
||||||
|
break;
|
||||||
|
case NpadRevision::Revision2:
|
||||||
|
mask = NpadStyleSet::Fullkey | NpadStyleSet::Handheld | NpadStyleSet::JoyDual |
|
||||||
|
NpadStyleSet::JoyLeft | NpadStyleSet::JoyRight | NpadStyleSet::Gc |
|
||||||
|
NpadStyleSet::Palma | NpadStyleSet::Lark | NpadStyleSet::SystemExt |
|
||||||
|
NpadStyleSet::System;
|
||||||
|
break;
|
||||||
|
case NpadRevision::Revision3:
|
||||||
|
mask = NpadStyleSet::Fullkey | NpadStyleSet::Handheld | NpadStyleSet::JoyDual |
|
||||||
|
NpadStyleSet::JoyLeft | NpadStyleSet::JoyRight | NpadStyleSet::Gc |
|
||||||
|
NpadStyleSet::Palma | NpadStyleSet::Lark | NpadStyleSet::HandheldLark |
|
||||||
|
NpadStyleSet::Lucia | NpadStyleSet::Lagoon | NpadStyleSet::Lager |
|
||||||
|
NpadStyleSet::SystemExt | NpadStyleSet::System;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
out_npad_styleset = out_npad_styleset & mask.raw;
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
mask.palma.Assign(1);
|
||||||
|
}
|
||||||
|
out_npad_styleset = out_npad_styleset & mask.raw;
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::SetVibrationMasterVolume(const float volume) {
|
||||||
|
// std::scoped_lock lock{external_mutex};
|
||||||
|
|
||||||
|
if (volume < 0.0f || volume > 1.0f) {
|
||||||
|
return ResultVibrationVolumeOutOfRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
vibration_master_volume = volume;
|
||||||
|
// nn::settings::detail::SetVibrationMasterVolume()
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::GetVibrationMasterVolume(float& out_volume) const {
|
||||||
|
// std::scoped_lock lock{external_mutex};
|
||||||
|
// nn::settings::detail::GetVibrationMasterVolume()
|
||||||
|
float current_volume{vibration_master_volume};
|
||||||
|
|
||||||
|
if (current_volume < 0.0f || current_volume > 1.0f) {
|
||||||
|
return ResultVibrationVolumeOutOfRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_volume = current_volume;
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Npad::IsFirmwareUpdateNeededForNotification(const u64 aruid, const s32 unknown) const {
|
||||||
|
// Not Implemented
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Npad::GetLastActiveNpad(NpadIdType& out_npad_id) const {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
|
||||||
|
out_npad_id = NpadIdType::Handheld;
|
||||||
|
const Result result = ResultSuccess; // last_active_npad->GetNpadIdType(out_npad_id);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
NpadRevision Npad::GetNpadRevision(const u64 aruid) const {
|
||||||
|
const auto index = GetIndexFromAruid(aruid);
|
||||||
|
|
||||||
|
if (index >= ARUID_MAX) {
|
||||||
|
return NpadRevision::Revision0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return npad_state[index]->GetNpadRevision();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<AbstractNpadState> Npad::GetAbstractNpad(const NpadIdType npad_id) {
|
||||||
|
return abstract_npad_state[NpadIdTypeToIndex(npad_id)];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Npad::UpdateSupportedNpadIdType() {
|
||||||
|
// Set some u64
|
||||||
|
// Call DisconnectAbstracPads(u64)
|
||||||
|
// Call ConnectAbstractPads(u64)
|
||||||
|
|
||||||
|
auto& state = active_npad_state; // Verify this
|
||||||
|
state->GetControllerState(NpadIdType::Player1).Update();
|
||||||
|
state->GetControllerState(NpadIdType::Player2).Update();
|
||||||
|
state->GetControllerState(NpadIdType::Player3).Update();
|
||||||
|
state->GetControllerState(NpadIdType::Player4).Update();
|
||||||
|
state->GetControllerState(NpadIdType::Player5).Update();
|
||||||
|
state->GetControllerState(NpadIdType::Player6).Update();
|
||||||
|
state->GetControllerState(NpadIdType::Player7).Update();
|
||||||
|
state->GetControllerState(NpadIdType::Player8).Update();
|
||||||
|
state->GetControllerState(NpadIdType::Other).Update();
|
||||||
|
state->GetControllerState(NpadIdType::Handheld).Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Npad::UpdateSupportedStyleSet() {
|
||||||
|
// Set some u64
|
||||||
|
// Call FUN_7100063e68(u64)
|
||||||
|
// Call FUN_7100063fc0(u64)
|
||||||
|
// Call ConnectAbstractPads(u64)
|
||||||
|
|
||||||
|
auto& state = active_npad_state; // Verify this
|
||||||
|
state->GetControllerState(NpadIdType::Player1).Update();
|
||||||
|
state->GetControllerState(NpadIdType::Player2).Update();
|
||||||
|
state->GetControllerState(NpadIdType::Player3).Update();
|
||||||
|
state->GetControllerState(NpadIdType::Player4).Update();
|
||||||
|
state->GetControllerState(NpadIdType::Player5).Update();
|
||||||
|
state->GetControllerState(NpadIdType::Player6).Update();
|
||||||
|
state->GetControllerState(NpadIdType::Player7).Update();
|
||||||
|
state->GetControllerState(NpadIdType::Player8).Update();
|
||||||
|
state->GetControllerState(NpadIdType::Other).Update();
|
||||||
|
state->GetControllerState(NpadIdType::Handheld).Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 Npad::GetNpadActiveAruid() {
|
||||||
|
return active_aruid;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::HID
|
||||||
|
#pragma optimize("", on)
|
|
@ -0,0 +1,217 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "core/hle/result.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/base_resource.h"
|
||||||
|
#include "core/hle/service/kernel_helpers.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
class KReadableEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Service::HID {
|
||||||
|
enum class NpadIdType : u32;
|
||||||
|
enum class NpadJoyAssignmentMode : u32;
|
||||||
|
enum class NpadHandheldActivationMode : u64;
|
||||||
|
enum class NpadJoyDeviceType : s64;
|
||||||
|
enum class NpadStyleSet : u32;
|
||||||
|
enum class NpadJoyHoldType : u64;
|
||||||
|
enum class NpadButton : u64;
|
||||||
|
enum class NpadRevision : u32;
|
||||||
|
using NpadBatteryLevel = u32;
|
||||||
|
|
||||||
|
struct SixAxisSensorHandle;
|
||||||
|
struct NpadInternalState;
|
||||||
|
|
||||||
|
class NpadState;
|
||||||
|
} // namespace Service::HID
|
||||||
|
|
||||||
|
namespace Service::HID {
|
||||||
|
|
||||||
|
class SixAxisSensorSharedState {
|
||||||
|
public:
|
||||||
|
bool IsAtRest() const;
|
||||||
|
};
|
||||||
|
class SixAxisSensorSharedConfig {};
|
||||||
|
|
||||||
|
class AbstractNpadState {
|
||||||
|
public:
|
||||||
|
explicit AbstractNpadState();
|
||||||
|
~AbstractNpadState();
|
||||||
|
|
||||||
|
Result ActivateNpad(const u64 aruid);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct BatteryState {
|
||||||
|
INSERT_PADDING_BYTES(0x1c);
|
||||||
|
bool is_powered_joy_dual;
|
||||||
|
bool is_charging_joy_dual;
|
||||||
|
INSERT_PADDING_BYTES(0x6);
|
||||||
|
NpadBatteryLevel battery_level_dual;
|
||||||
|
bool is_powered_joy_left;
|
||||||
|
bool is_charging_joy_left;
|
||||||
|
INSERT_PADDING_BYTES(0x6);
|
||||||
|
NpadBatteryLevel battery_level_left;
|
||||||
|
bool is_powered_joy_right;
|
||||||
|
bool is_charging_joy_right;
|
||||||
|
INSERT_PADDING_BYTES(0x6);
|
||||||
|
NpadBatteryLevel battery_level_right;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(BatteryState) == 0x40, "BatteryState is an invalid size");
|
||||||
|
|
||||||
|
struct Unknown0x88 {};
|
||||||
|
|
||||||
|
struct AbstractState {
|
||||||
|
INSERT_PADDING_BYTES(0x88);
|
||||||
|
Unknown0x88 unknown_0x88{};
|
||||||
|
};
|
||||||
|
|
||||||
|
Result ActivateUnknown();
|
||||||
|
|
||||||
|
Result UpdateNpadLifo(const u64 aruid);
|
||||||
|
Result UpdateSixaxisLifo(const u64 aruid);
|
||||||
|
Result UpdateBatteryLifo(const u64 aruid);
|
||||||
|
void UpdateNpadLifoImpl(const BatteryState& battery_state, NpadInternalState& internal_state);
|
||||||
|
void UpdateSixaxisLifoImpl(const BatteryState& battery_state,
|
||||||
|
NpadInternalState& internal_state);
|
||||||
|
void UpdateBatteryLifoImpl(const BatteryState& battery_state,
|
||||||
|
NpadInternalState& internal_state);
|
||||||
|
|
||||||
|
AbstractState state{};
|
||||||
|
};
|
||||||
|
|
||||||
|
class Npad final : public BaseResource {
|
||||||
|
public:
|
||||||
|
explicit Npad(KernelHelpers::ServiceContext& context, ResourceManager* resource);
|
||||||
|
~Npad();
|
||||||
|
|
||||||
|
Result Activate(const u64 aruid);
|
||||||
|
void ActivateWithRevision(const u64 aruid, const NpadRevision revision);
|
||||||
|
void DisconnectNpad(const u64 aruid, const NpadIdType npad_id);
|
||||||
|
void ForceDisconnectNpad(const NpadIdType npad_id);
|
||||||
|
void DisconnectAbstractPad(const NpadIdType npad_id);
|
||||||
|
|
||||||
|
// Config
|
||||||
|
Result SetNpadJoyHoldType(const u64 aruid, const NpadJoyHoldType hold_type);
|
||||||
|
Result GetNpadJoyHoldType(const u64 aruid, NpadJoyHoldType& out_hold_type) const;
|
||||||
|
Result SetSupportedNpadIdType(const u64 aruid, std::span<const NpadIdType> list);
|
||||||
|
Result SetSupportedNpadStyleSet(const u64 aruid, const NpadStyleSet supported_style_set);
|
||||||
|
Result GetSupportedNpadStyleSet(const u64 aruid, NpadStyleSet& out_supported_style_set) const;
|
||||||
|
|
||||||
|
// Sixaxis
|
||||||
|
bool IsFirmwareUpdateAvailableForSixAxisSensor(const SixAxisSensorHandle& handle) const;
|
||||||
|
Result ResetIsSixAxisSensorDeviceNewlyAssigned(const u64 aruid,
|
||||||
|
const SixAxisSensorHandle& handle);
|
||||||
|
SixAxisSensorSharedState GetSixAxisSensorState(const SixAxisSensorHandle& handle);
|
||||||
|
std::shared_ptr <
|
||||||
|
SixAxisSensorSharedConfig> GetSixAxisSensorConfig(const SixAxisSensorHandle& handle);
|
||||||
|
|
||||||
|
// Assignment, merge, swap or split npad
|
||||||
|
void SetNpadJoyAssignmentModeSingleByDefault(const u64 aruid, const NpadIdType npad_id);
|
||||||
|
void SetNpadJoyAssignmentModeSingle(const u64 aruid, const NpadIdType npad_id,
|
||||||
|
const NpadJoyDeviceType npad_joy_device_type);
|
||||||
|
bool SetNpadJoyAssignmentModeSingleWithDestination(
|
||||||
|
NpadIdType& out_npad_id, const u64 aruid, const NpadIdType npad_id,
|
||||||
|
const NpadJoyDeviceType npad_joy_device_type);
|
||||||
|
void SetNpadJoyAssignmentModeDual(const u64 aruid, const NpadIdType npad_id);
|
||||||
|
Result MergeSingleJoyAsDualJoy(const u64 aruid, const NpadIdType npad_id_1,
|
||||||
|
const NpadIdType npad_id_2);
|
||||||
|
Result SwapNpadAssignment(const u64 aruid, const NpadIdType npad_id_1,
|
||||||
|
const NpadIdType npad_id_2);
|
||||||
|
Result StartLrAssignmentMode(const u64 aruid);
|
||||||
|
Result StopLrAssignmentMode(const u64 aruid);
|
||||||
|
Result SetNpadHandheldActivationMode(const u64 aruid, const NpadHandheldActivationMode mode);
|
||||||
|
Result GetNpadHandheldActivationMode(const u64 aruid,
|
||||||
|
NpadHandheldActivationMode& out_mode) const;
|
||||||
|
|
||||||
|
// Sticks and Button
|
||||||
|
Result IsUnintendedHomeButtonInputProtectionEnabled(bool& out_is_enabled, const u64 aruid,
|
||||||
|
const NpadIdType npad_id) const;
|
||||||
|
Result EnableUnintendedHomeButtonInputProtection(const u64 aruid, const NpadIdType npad_id,
|
||||||
|
const bool is_enabled);
|
||||||
|
void SetNpadAnalogStickUseCenterClamp(const u64 aruid, const bool use_center_clamp);
|
||||||
|
Result SetNpadCaptureButtonAssignment(const u64 aruid, const NpadStyleSet npad_styleset,
|
||||||
|
const NpadButton npad_button_set);
|
||||||
|
Result ClearNpadCaptureButtonAssignment(const u64 aruid);
|
||||||
|
std::size_t GetNpadCaptureButtonAssignment(const u64 aruid,
|
||||||
|
std::span<NpadButton> out_button_assignment) const;
|
||||||
|
|
||||||
|
// Events
|
||||||
|
Result AcquireNpadStyleSetUpdateEventHandle(const u64 aruid, Kernel::KReadableEvent** out_event,
|
||||||
|
const NpadIdType npad_id);
|
||||||
|
|
||||||
|
Result ClearNpadSystemCommonPolicy(const u64 aruid);
|
||||||
|
Result ApplyNpadSystemCommonPolicy(const u64 aruid);
|
||||||
|
Result ApplyNpadSystemCommonPolicyFull(const u64 aruid);
|
||||||
|
|
||||||
|
Result AssigningSingleOnSlSrPress(const u64 aruid, const bool is_enabled);
|
||||||
|
|
||||||
|
Result GetMaskedSupportedNpadStyleSet(const u64 aruid, NpadStyleSet& out_npad_styleset) const;
|
||||||
|
|
||||||
|
Result SetVibrationMasterVolume(const float volume);
|
||||||
|
Result GetVibrationMasterVolume(float& out_volume) const;
|
||||||
|
bool IsFirmwareUpdateNeededForNotification(const u64 aruid, const s32 unknown) const;
|
||||||
|
Result GetLastActiveNpad(NpadIdType& out_npad_id) const;
|
||||||
|
|
||||||
|
NpadRevision GetNpadRevision(const u64 aruid) const;
|
||||||
|
|
||||||
|
std::shared_ptr<AbstractNpadState> GetAbstractNpad(const NpadIdType npad_id);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Interface implementations
|
||||||
|
Result SetSupportedNpadIdTypeImpl(const u64 aruid, std::span<const NpadIdType> list);
|
||||||
|
Result SetSupportedNpadStyleSetImpl(const u64 aruid, const NpadStyleSet supported_style_set);
|
||||||
|
Result GetSupportedNpadStyleSetImpl(const u64 aruid,
|
||||||
|
NpadStyleSet& out_supported_style_set) const;
|
||||||
|
bool SetNpadJoyAssignmentMode(NpadIdType* out_npad_id, const u64 aruid,
|
||||||
|
const NpadIdType npad_id,
|
||||||
|
const NpadJoyDeviceType npad_joy_device_type);
|
||||||
|
Result SetLrAssignmentMode(const u64 aruid, const bool is_enabled);
|
||||||
|
Result GetLrAssignmentMode(bool& out_is_enabled, const u64 aruid) const;
|
||||||
|
Result SetNpadHandheldActivationModeImpl(const u64 aruid,
|
||||||
|
const NpadHandheldActivationMode mode);
|
||||||
|
Result GetNpadHandheldActivationModeImpl(const u64 aruid,
|
||||||
|
NpadHandheldActivationMode& out_mode) const;
|
||||||
|
Result IsUnintendedHomeButtonInputProtectionEnabledImpl(bool& out_is_enabled, const u64 aruid,
|
||||||
|
const NpadIdType npad_id) const;
|
||||||
|
|
||||||
|
Result SetNpadAnalogStickUseCenterClampImpl(const u64 aruid, const bool use_center_clamp);
|
||||||
|
Result ClearNpadSystemCommonPolicyImpl(const u64 aruid);
|
||||||
|
Result ApplyNpadSystemCommonPolicyImpl(const u64 aruid, const bool is_full_policy);
|
||||||
|
|
||||||
|
Result GetAssigningSingleOnSlSrPress(const u64 aruid, bool out_is_enabled) const;
|
||||||
|
Result SetAssigningSingleOnSlSrPress(const u64 aruid, const bool is_enabled);
|
||||||
|
|
||||||
|
Result GetMaskedSupportedNpadStyleSetImpl(const u64 aruid,
|
||||||
|
NpadStyleSet& out_npad_styleset) const;
|
||||||
|
// Update state
|
||||||
|
void UpdateSupportedNpadIdType();
|
||||||
|
void UpdateSupportedStyleSet();
|
||||||
|
u64 GetNpadActiveAruid();
|
||||||
|
|
||||||
|
mutable std::mutex mutex;
|
||||||
|
mutable std::recursive_mutex recursive_mutex;
|
||||||
|
u64 active_aruid{};
|
||||||
|
std::shared_ptr<NpadState> active_npad_state = nullptr;
|
||||||
|
NpadJoyHoldType default_joy_hold_type{};
|
||||||
|
std::array<std::shared_ptr<NpadState>, ARUID_MAX> npad_state{};
|
||||||
|
std::array<std::shared_ptr<AbstractNpadState>, PLAYERS_MAX> abstract_npad_state{};
|
||||||
|
float vibration_master_volume{};
|
||||||
|
|
||||||
|
KernelHelpers::ServiceContext& service_context;
|
||||||
|
ResourceManager* resource_manager;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::HID
|
|
@ -0,0 +1,65 @@
|
||||||
|
// 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/service/hid/hid_types.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/npad_resource/npad_controller_state.h"
|
||||||
|
|
||||||
|
namespace Service::HID {
|
||||||
|
|
||||||
|
NpadIdType NpadControllerState::GetNpadId() const {
|
||||||
|
return {}; // npad_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 NpadControllerState::IsUpdatePending() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NpadControllerState::Update() {}
|
||||||
|
|
||||||
|
void NpadControllerState::SetNpadAssignmentMode(const NpadJoyAssignmentMode mode) {
|
||||||
|
// assignament_mode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NpadControllerState::IsStyleSetUpdateEventInitialized() const {
|
||||||
|
return state.is_styleset_update_event_initialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NpadControllerState::SetStyleSetUpdateEventInitialized(const bool is_initialized) {
|
||||||
|
state.is_styleset_update_event_initialized = is_initialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NpadControllerState::SetNpadStyleSetUpdateEvent(Kernel::KEvent* event) {
|
||||||
|
state.style_set_update_event = event;
|
||||||
|
}
|
||||||
|
|
||||||
|
Kernel::KReadableEvent& NpadControllerState::GetNpadStyleSetUpdateEvent() {
|
||||||
|
return state.style_set_update_event->GetReadableEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NpadControllerState::SignalStyleSetUpdateEvent() {
|
||||||
|
state.style_set_update_event->Signal();
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 NpadControllerState::GetConnectedControllerIndex() {
|
||||||
|
u32 connected_controllers = 0;
|
||||||
|
u32 connected_index = 0;
|
||||||
|
|
||||||
|
// u32 index = 0;
|
||||||
|
|
||||||
|
if (connected_controllers == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connected_controllers != 1) {
|
||||||
|
// Something Fun happens here
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((connected_controllers & 1) != 0) {
|
||||||
|
// connected_index |= somearray[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
return connected_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::HID
|
|
@ -0,0 +1,48 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
class KReadableEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Service::HID {
|
||||||
|
enum class NpadIdType : u32;
|
||||||
|
enum class NpadJoyAssignmentMode : u32;
|
||||||
|
} // namespace Service::HID
|
||||||
|
|
||||||
|
namespace Service::HID {
|
||||||
|
|
||||||
|
class NpadControllerState {
|
||||||
|
public:
|
||||||
|
NpadIdType GetNpadId() const;
|
||||||
|
u64 IsUpdatePending();
|
||||||
|
void Update();
|
||||||
|
|
||||||
|
void SetNpadAssignmentMode(const NpadJoyAssignmentMode mode);
|
||||||
|
|
||||||
|
bool IsStyleSetUpdateEventInitialized() const;
|
||||||
|
void SetStyleSetUpdateEventInitialized(const bool is_initialized);
|
||||||
|
void SetNpadStyleSetUpdateEvent(Kernel::KEvent* event);
|
||||||
|
Kernel::KReadableEvent& GetNpadStyleSetUpdateEvent();
|
||||||
|
void SignalStyleSetUpdateEvent();
|
||||||
|
|
||||||
|
u32 GetConnectedControllerIndex();
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct StateStructure {
|
||||||
|
bool is_styleset_update_event_initialized{};
|
||||||
|
INSERT_PADDING_BYTES(0x7);
|
||||||
|
Kernel::KEvent* style_set_update_event = nullptr;
|
||||||
|
INSERT_PADDING_BYTES(0x27);
|
||||||
|
};
|
||||||
|
static_assert(sizeof(StateStructure) == 0x38, "StateStructure is an invalid size");
|
||||||
|
|
||||||
|
StateStructure state{};
|
||||||
|
|
||||||
|
// NpadIdType npad_id{};
|
||||||
|
// NpadJoyAssignmentMode assignament_mode{};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::HID
|
|
@ -0,0 +1,143 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "common/vector_math.h"
|
||||||
|
#include "core/hle/service/hid/hid_types.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/base_resource.h"
|
||||||
|
#include "core/hle/service/hid/resource_manager/ring_lifo.h"
|
||||||
|
|
||||||
|
namespace Service::HID {
|
||||||
|
|
||||||
|
// This is nn::hid::detail::NpadFullKeyColorState
|
||||||
|
struct NpadFullKeyColorState {
|
||||||
|
ColorAttribute attribute{ColorAttribute::NoController};
|
||||||
|
NpadControllerColor fullkey{};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(NpadFullKeyColorState) == 0xC, "NpadFullKeyColorState is an invalid size");
|
||||||
|
|
||||||
|
// This is nn::hid::detail::NpadJoyColorState
|
||||||
|
struct NpadJoyColorState {
|
||||||
|
ColorAttribute attribute{ColorAttribute::NoController};
|
||||||
|
NpadControllerColor left{};
|
||||||
|
NpadControllerColor right{};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(NpadJoyColorState) == 0x14, "NpadJoyColorState 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{};
|
||||||
|
NpadButtonState npad_buttons{};
|
||||||
|
AnalogStickState l_stick{};
|
||||||
|
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::SixAxisSensorAttribute
|
||||||
|
struct SixAxisSensorAttribute {
|
||||||
|
union {
|
||||||
|
u32 raw{};
|
||||||
|
BitField<0, 1, u32> is_connected;
|
||||||
|
BitField<1, 1, u32> is_interpolated;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(SixAxisSensorAttribute) == 4, "SixAxisSensorAttribute is an invalid size");
|
||||||
|
|
||||||
|
// This is nn::hid::SixAxisSensorState
|
||||||
|
struct SixAxisSensorState {
|
||||||
|
s64 delta_time{};
|
||||||
|
s64 sampling_number{};
|
||||||
|
Common::Vec3f accel{};
|
||||||
|
Common::Vec3f gyro{};
|
||||||
|
Common::Vec3f rotation{};
|
||||||
|
std::array<Common::Vec3f, 3> orientation{};
|
||||||
|
SixAxisSensorAttribute attribute{};
|
||||||
|
INSERT_PADDING_BYTES(4); // Reserved
|
||||||
|
};
|
||||||
|
static_assert(sizeof(SixAxisSensorState) == 0x60, "SixAxisSensorState is an invalid size");
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
|
||||||
|
struct AppletFooterUi {
|
||||||
|
AppletFooterUiAttributes attributes{};
|
||||||
|
AppletFooterUiType type{AppletFooterUiType::None};
|
||||||
|
INSERT_PADDING_BYTES(0x5B); // Reserved
|
||||||
|
};
|
||||||
|
static_assert(sizeof(AppletFooterUi) == 0x60, "AppletFooterUi is an invalid size");
|
||||||
|
|
||||||
|
struct AppletNfcXcd {
|
||||||
|
union {
|
||||||
|
AppletFooterUi applet_footer{};
|
||||||
|
Lifo<NfcXcdDeviceHandleStateImpl, 0x2> nfc_xcd_device_lifo;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is nn::hid::detail::NpadInternalState
|
||||||
|
struct NpadInternalState {
|
||||||
|
NpadStyleTag style_tag{NpadStyleSet::None};
|
||||||
|
NpadJoyAssignmentMode assignment_mode{NpadJoyAssignmentMode::Dual};
|
||||||
|
NpadFullKeyColorState fullkey_color{};
|
||||||
|
NpadJoyColorState joycon_color{};
|
||||||
|
Lifo<NPadGenericState, HID_ENTRY_COUNT> fullkey_lifo{};
|
||||||
|
Lifo<NPadGenericState, HID_ENTRY_COUNT> handheld_lifo{};
|
||||||
|
Lifo<NPadGenericState, HID_ENTRY_COUNT> joy_dual_lifo{};
|
||||||
|
Lifo<NPadGenericState, HID_ENTRY_COUNT> joy_left_lifo{};
|
||||||
|
Lifo<NPadGenericState, HID_ENTRY_COUNT> joy_right_lifo{};
|
||||||
|
Lifo<NPadGenericState, HID_ENTRY_COUNT> palma_lifo{};
|
||||||
|
Lifo<NPadGenericState, HID_ENTRY_COUNT> system_ext_lifo{};
|
||||||
|
Lifo<SixAxisSensorState, HID_ENTRY_COUNT> sixaxis_fullkey_lifo{};
|
||||||
|
Lifo<SixAxisSensorState, HID_ENTRY_COUNT> sixaxis_handheld_lifo{};
|
||||||
|
Lifo<SixAxisSensorState, HID_ENTRY_COUNT> sixaxis_dual_left_lifo{};
|
||||||
|
Lifo<SixAxisSensorState, HID_ENTRY_COUNT> sixaxis_dual_right_lifo{};
|
||||||
|
Lifo<SixAxisSensorState, HID_ENTRY_COUNT> sixaxis_left_lifo{};
|
||||||
|
Lifo<SixAxisSensorState, HID_ENTRY_COUNT> sixaxis_right_lifo{};
|
||||||
|
DeviceType device_type{};
|
||||||
|
INSERT_PADDING_BYTES(0x4); // Reserved
|
||||||
|
NPadSystemProperties system_properties{};
|
||||||
|
NpadSystemButtonProperties button_properties{};
|
||||||
|
NpadBatteryLevel battery_level_dual{};
|
||||||
|
NpadBatteryLevel battery_level_left{};
|
||||||
|
NpadBatteryLevel battery_level_right{};
|
||||||
|
AppletNfcXcd applet_nfc_xcd{};
|
||||||
|
INSERT_PADDING_BYTES(0x20); // Unknown
|
||||||
|
Lifo<NpadGcTriggerState, HID_ENTRY_COUNT> gc_trigger_lifo{};
|
||||||
|
NpadLarkType lark_type_l_and_main{};
|
||||||
|
NpadLarkType lark_type_r{};
|
||||||
|
NpadLuciaType lucia_type{};
|
||||||
|
NpadLagonType lagon_type{};
|
||||||
|
NpadLagerType lager_type{};
|
||||||
|
SixAxisSensorProperties sixaxis_fullkey_properties;
|
||||||
|
SixAxisSensorProperties sixaxis_handheld_properties;
|
||||||
|
SixAxisSensorProperties sixaxis_dual_left_properties;
|
||||||
|
SixAxisSensorProperties sixaxis_dual_right_properties;
|
||||||
|
SixAxisSensorProperties sixaxis_left_properties;
|
||||||
|
SixAxisSensorProperties sixaxis_right_properties;
|
||||||
|
INSERT_PADDING_BYTES(0xc06); // Unknown
|
||||||
|
};
|
||||||
|
static_assert(sizeof(NpadInternalState) == 0x5000, "NpadInternalState is an invalid size");
|
||||||
|
|
||||||
|
} // namespace Service::HID
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue