mirror of
https://git.suyu.dev/suyu/suyu
synced 2024-12-27 03:42:51 -06:00
core: hid: Add nfc support to emulated controller
This commit is contained in:
parent
f6d57d7dd9
commit
8a3d22c4bd
4 changed files with 123 additions and 3 deletions
|
@ -131,13 +131,16 @@ void EmulatedController::LoadDevices() {
|
||||||
battery_params[RightIndex].Set("battery", true);
|
battery_params[RightIndex].Set("battery", true);
|
||||||
|
|
||||||
camera_params = Common::ParamPackage{"engine:camera,camera:1"};
|
camera_params = Common::ParamPackage{"engine:camera,camera:1"};
|
||||||
|
nfc_params = Common::ParamPackage{"engine:virtual_amiibo,nfc:1"};
|
||||||
|
|
||||||
output_params[LeftIndex] = left_joycon;
|
output_params[LeftIndex] = left_joycon;
|
||||||
output_params[RightIndex] = right_joycon;
|
output_params[RightIndex] = right_joycon;
|
||||||
output_params[2] = camera_params;
|
output_params[2] = camera_params;
|
||||||
|
output_params[3] = nfc_params;
|
||||||
output_params[LeftIndex].Set("output", true);
|
output_params[LeftIndex].Set("output", true);
|
||||||
output_params[RightIndex].Set("output", true);
|
output_params[RightIndex].Set("output", true);
|
||||||
output_params[2].Set("output", true);
|
output_params[2].Set("output", true);
|
||||||
|
output_params[3].Set("output", true);
|
||||||
|
|
||||||
LoadTASParams();
|
LoadTASParams();
|
||||||
|
|
||||||
|
@ -155,6 +158,7 @@ void EmulatedController::LoadDevices() {
|
||||||
std::transform(battery_params.begin(), battery_params.end(), battery_devices.begin(),
|
std::transform(battery_params.begin(), battery_params.end(), battery_devices.begin(),
|
||||||
Common::Input::CreateDevice<Common::Input::InputDevice>);
|
Common::Input::CreateDevice<Common::Input::InputDevice>);
|
||||||
camera_devices = Common::Input::CreateDevice<Common::Input::InputDevice>(camera_params);
|
camera_devices = Common::Input::CreateDevice<Common::Input::InputDevice>(camera_params);
|
||||||
|
nfc_devices = Common::Input::CreateDevice<Common::Input::InputDevice>(nfc_params);
|
||||||
std::transform(output_params.begin(), output_params.end(), output_devices.begin(),
|
std::transform(output_params.begin(), output_params.end(), output_devices.begin(),
|
||||||
Common::Input::CreateDevice<Common::Input::OutputDevice>);
|
Common::Input::CreateDevice<Common::Input::OutputDevice>);
|
||||||
|
|
||||||
|
@ -284,6 +288,16 @@ void EmulatedController::ReloadInput() {
|
||||||
camera_devices->ForceUpdate();
|
camera_devices->ForceUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nfc_devices) {
|
||||||
|
if (npad_id_type == NpadIdType::Handheld || npad_id_type == NpadIdType::Player1) {
|
||||||
|
nfc_devices->SetCallback({
|
||||||
|
.on_change =
|
||||||
|
[this](const Common::Input::CallbackStatus& callback) { SetNfc(callback); },
|
||||||
|
});
|
||||||
|
nfc_devices->ForceUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Use a common UUID for TAS
|
// Use a common UUID for TAS
|
||||||
static constexpr Common::UUID TAS_UUID = Common::UUID{
|
static constexpr Common::UUID TAS_UUID = Common::UUID{
|
||||||
{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xA5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
|
{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xA5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
|
||||||
|
@ -339,6 +353,8 @@ void EmulatedController::UnloadInput() {
|
||||||
for (auto& stick : tas_stick_devices) {
|
for (auto& stick : tas_stick_devices) {
|
||||||
stick.reset();
|
stick.reset();
|
||||||
}
|
}
|
||||||
|
camera_devices.reset();
|
||||||
|
nfc_devices.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmulatedController::EnableConfiguration() {
|
void EmulatedController::EnableConfiguration() {
|
||||||
|
@ -903,6 +919,25 @@ void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback
|
||||||
TriggerOnChange(ControllerTriggerType::IrSensor, true);
|
TriggerOnChange(ControllerTriggerType::IrSensor, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) {
|
||||||
|
std::unique_lock lock{mutex};
|
||||||
|
controller.nfc_values = TransformToNfc(callback);
|
||||||
|
|
||||||
|
if (is_configuring) {
|
||||||
|
lock.unlock();
|
||||||
|
TriggerOnChange(ControllerTriggerType::Nfc, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
controller.nfc_state = {
|
||||||
|
controller.nfc_values.state,
|
||||||
|
controller.nfc_values.data,
|
||||||
|
};
|
||||||
|
|
||||||
|
lock.unlock();
|
||||||
|
TriggerOnChange(ControllerTriggerType::Nfc, true);
|
||||||
|
}
|
||||||
|
|
||||||
bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) {
|
bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) {
|
||||||
if (device_index >= output_devices.size()) {
|
if (device_index >= output_devices.size()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -980,6 +1015,10 @@ bool EmulatedController::TestVibration(std::size_t device_index) {
|
||||||
bool EmulatedController::SetPollingMode(Common::Input::PollingMode polling_mode) {
|
bool EmulatedController::SetPollingMode(Common::Input::PollingMode polling_mode) {
|
||||||
LOG_INFO(Service_HID, "Set polling mode {}", polling_mode);
|
LOG_INFO(Service_HID, "Set polling mode {}", polling_mode);
|
||||||
auto& output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
|
auto& output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
|
||||||
|
auto& nfc_output_device = output_devices[3];
|
||||||
|
|
||||||
|
nfc_output_device->SetPollingMode(polling_mode);
|
||||||
|
|
||||||
return output_device->SetPollingMode(polling_mode) == Common::Input::PollingError::None;
|
return output_device->SetPollingMode(polling_mode) == Common::Input::PollingError::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1000,6 +1039,32 @@ bool EmulatedController::SetCameraFormat(
|
||||||
camera_format)) == Common::Input::CameraError::None;
|
camera_format)) == Common::Input::CameraError::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EmulatedController::HasNfc() const {
|
||||||
|
const auto& nfc_output_device = output_devices[3];
|
||||||
|
|
||||||
|
switch (npad_type) {
|
||||||
|
case NpadStyleIndex::JoyconRight:
|
||||||
|
case NpadStyleIndex::JoyconDual:
|
||||||
|
case NpadStyleIndex::ProController:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool has_virtual_nfc =
|
||||||
|
npad_id_type == NpadIdType::Player1 || npad_id_type == NpadIdType::Handheld;
|
||||||
|
const bool is_virtual_nfc_supported =
|
||||||
|
nfc_output_device->SupportsNfc() != Common::Input::NfcState::NotSupported;
|
||||||
|
|
||||||
|
return is_connected && (has_virtual_nfc && is_virtual_nfc_supported);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EmulatedController::WriteNfc(const std::vector<u8>& data) {
|
||||||
|
auto& nfc_output_device = output_devices[3];
|
||||||
|
|
||||||
|
return nfc_output_device->WriteNfcData(data) == Common::Input::NfcState::Success;
|
||||||
|
}
|
||||||
|
|
||||||
void EmulatedController::SetLedPattern() {
|
void EmulatedController::SetLedPattern() {
|
||||||
for (auto& device : output_devices) {
|
for (auto& device : output_devices) {
|
||||||
if (!device) {
|
if (!device) {
|
||||||
|
@ -1363,6 +1428,11 @@ const CameraState& EmulatedController::GetCamera() const {
|
||||||
return controller.camera_state;
|
return controller.camera_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const NfcState& EmulatedController::GetNfc() const {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
return controller.nfc_state;
|
||||||
|
}
|
||||||
|
|
||||||
NpadColor EmulatedController::GetNpadColor(u32 color) {
|
NpadColor EmulatedController::GetNpadColor(u32 color) {
|
||||||
return {
|
return {
|
||||||
.r = static_cast<u8>((color >> 16) & 0xFF),
|
.r = static_cast<u8>((color >> 16) & 0xFF),
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
namespace Core::HID {
|
namespace Core::HID {
|
||||||
const std::size_t max_emulated_controllers = 2;
|
const std::size_t max_emulated_controllers = 2;
|
||||||
const std::size_t output_devices = 3;
|
const std::size_t output_devices_size = 4;
|
||||||
struct ControllerMotionInfo {
|
struct ControllerMotionInfo {
|
||||||
Common::Input::MotionStatus raw_status{};
|
Common::Input::MotionStatus raw_status{};
|
||||||
MotionInput emulated{};
|
MotionInput emulated{};
|
||||||
|
@ -37,7 +37,8 @@ using TriggerDevices =
|
||||||
using BatteryDevices =
|
using BatteryDevices =
|
||||||
std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
|
std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
|
||||||
using CameraDevices = std::unique_ptr<Common::Input::InputDevice>;
|
using CameraDevices = std::unique_ptr<Common::Input::InputDevice>;
|
||||||
using OutputDevices = std::array<std::unique_ptr<Common::Input::OutputDevice>, output_devices>;
|
using NfcDevices = std::unique_ptr<Common::Input::InputDevice>;
|
||||||
|
using OutputDevices = std::array<std::unique_ptr<Common::Input::OutputDevice>, output_devices_size>;
|
||||||
|
|
||||||
using ButtonParams = std::array<Common::ParamPackage, Settings::NativeButton::NumButtons>;
|
using ButtonParams = std::array<Common::ParamPackage, Settings::NativeButton::NumButtons>;
|
||||||
using StickParams = std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs>;
|
using StickParams = std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs>;
|
||||||
|
@ -45,7 +46,8 @@ using ControllerMotionParams = std::array<Common::ParamPackage, Settings::Native
|
||||||
using TriggerParams = std::array<Common::ParamPackage, Settings::NativeTrigger::NumTriggers>;
|
using TriggerParams = std::array<Common::ParamPackage, Settings::NativeTrigger::NumTriggers>;
|
||||||
using BatteryParams = std::array<Common::ParamPackage, max_emulated_controllers>;
|
using BatteryParams = std::array<Common::ParamPackage, max_emulated_controllers>;
|
||||||
using CameraParams = Common::ParamPackage;
|
using CameraParams = Common::ParamPackage;
|
||||||
using OutputParams = std::array<Common::ParamPackage, output_devices>;
|
using NfcParams = Common::ParamPackage;
|
||||||
|
using OutputParams = std::array<Common::ParamPackage, output_devices_size>;
|
||||||
|
|
||||||
using ButtonValues = std::array<Common::Input::ButtonStatus, Settings::NativeButton::NumButtons>;
|
using ButtonValues = std::array<Common::Input::ButtonStatus, Settings::NativeButton::NumButtons>;
|
||||||
using SticksValues = std::array<Common::Input::StickStatus, Settings::NativeAnalog::NumAnalogs>;
|
using SticksValues = std::array<Common::Input::StickStatus, Settings::NativeAnalog::NumAnalogs>;
|
||||||
|
@ -55,6 +57,7 @@ using ControllerMotionValues = std::array<ControllerMotionInfo, Settings::Native
|
||||||
using ColorValues = std::array<Common::Input::BodyColorStatus, max_emulated_controllers>;
|
using ColorValues = std::array<Common::Input::BodyColorStatus, max_emulated_controllers>;
|
||||||
using BatteryValues = std::array<Common::Input::BatteryStatus, max_emulated_controllers>;
|
using BatteryValues = std::array<Common::Input::BatteryStatus, max_emulated_controllers>;
|
||||||
using CameraValues = Common::Input::CameraStatus;
|
using CameraValues = Common::Input::CameraStatus;
|
||||||
|
using NfcValues = Common::Input::NfcStatus;
|
||||||
using VibrationValues = std::array<Common::Input::VibrationStatus, max_emulated_controllers>;
|
using VibrationValues = std::array<Common::Input::VibrationStatus, max_emulated_controllers>;
|
||||||
|
|
||||||
struct AnalogSticks {
|
struct AnalogSticks {
|
||||||
|
@ -80,6 +83,11 @@ struct CameraState {
|
||||||
std::size_t sample{};
|
std::size_t sample{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct NfcState {
|
||||||
|
Common::Input::NfcState state{};
|
||||||
|
std::vector<u8> data{};
|
||||||
|
};
|
||||||
|
|
||||||
struct ControllerMotion {
|
struct ControllerMotion {
|
||||||
Common::Vec3f accel{};
|
Common::Vec3f accel{};
|
||||||
Common::Vec3f gyro{};
|
Common::Vec3f gyro{};
|
||||||
|
@ -107,6 +115,7 @@ struct ControllerStatus {
|
||||||
BatteryValues battery_values{};
|
BatteryValues battery_values{};
|
||||||
VibrationValues vibration_values{};
|
VibrationValues vibration_values{};
|
||||||
CameraValues camera_values{};
|
CameraValues camera_values{};
|
||||||
|
NfcValues nfc_values{};
|
||||||
|
|
||||||
// Data for HID serices
|
// Data for HID serices
|
||||||
HomeButtonState home_button_state{};
|
HomeButtonState home_button_state{};
|
||||||
|
@ -119,6 +128,7 @@ struct ControllerStatus {
|
||||||
ControllerColors colors_state{};
|
ControllerColors colors_state{};
|
||||||
BatteryLevelState battery_state{};
|
BatteryLevelState battery_state{};
|
||||||
CameraState camera_state{};
|
CameraState camera_state{};
|
||||||
|
NfcState nfc_state{};
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ControllerTriggerType {
|
enum class ControllerTriggerType {
|
||||||
|
@ -130,6 +140,7 @@ enum class ControllerTriggerType {
|
||||||
Battery,
|
Battery,
|
||||||
Vibration,
|
Vibration,
|
||||||
IrSensor,
|
IrSensor,
|
||||||
|
Nfc,
|
||||||
Connected,
|
Connected,
|
||||||
Disconnected,
|
Disconnected,
|
||||||
Type,
|
Type,
|
||||||
|
@ -315,6 +326,9 @@ public:
|
||||||
/// Returns the latest camera status from the controller
|
/// Returns the latest camera status from the controller
|
||||||
const CameraState& GetCamera() const;
|
const CameraState& GetCamera() const;
|
||||||
|
|
||||||
|
/// Returns the latest ntag status from the controller
|
||||||
|
const NfcState& GetNfc() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a specific vibration to the output device
|
* Sends a specific vibration to the output device
|
||||||
* @return true if vibration had no errors
|
* @return true if vibration had no errors
|
||||||
|
@ -341,6 +355,12 @@ public:
|
||||||
*/
|
*/
|
||||||
bool SetCameraFormat(Core::IrSensor::ImageTransferProcessorFormat camera_format);
|
bool SetCameraFormat(Core::IrSensor::ImageTransferProcessorFormat camera_format);
|
||||||
|
|
||||||
|
/// Returns true if the device has nfc support
|
||||||
|
bool HasNfc() const;
|
||||||
|
|
||||||
|
/// Returns true if the nfc tag was written
|
||||||
|
bool WriteNfc(const std::vector<u8>& data);
|
||||||
|
|
||||||
/// Returns the led pattern corresponding to this emulated controller
|
/// Returns the led pattern corresponding to this emulated controller
|
||||||
LedPattern GetLedPattern() const;
|
LedPattern GetLedPattern() const;
|
||||||
|
|
||||||
|
@ -424,6 +444,12 @@ private:
|
||||||
*/
|
*/
|
||||||
void SetCamera(const Common::Input::CallbackStatus& callback);
|
void SetCamera(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
|
* Converts a color format from bgra to rgba
|
||||||
* @param color in bgra format
|
* @param color in bgra format
|
||||||
|
@ -458,6 +484,7 @@ private:
|
||||||
TriggerParams trigger_params;
|
TriggerParams trigger_params;
|
||||||
BatteryParams battery_params;
|
BatteryParams battery_params;
|
||||||
CameraParams camera_params;
|
CameraParams camera_params;
|
||||||
|
NfcParams nfc_params;
|
||||||
OutputParams output_params;
|
OutputParams output_params;
|
||||||
|
|
||||||
ButtonDevices button_devices;
|
ButtonDevices button_devices;
|
||||||
|
@ -466,6 +493,7 @@ private:
|
||||||
TriggerDevices trigger_devices;
|
TriggerDevices trigger_devices;
|
||||||
BatteryDevices battery_devices;
|
BatteryDevices battery_devices;
|
||||||
CameraDevices camera_devices;
|
CameraDevices camera_devices;
|
||||||
|
NfcDevices nfc_devices;
|
||||||
OutputDevices output_devices;
|
OutputDevices output_devices;
|
||||||
|
|
||||||
// TAS related variables
|
// TAS related variables
|
||||||
|
|
|
@ -287,6 +287,20 @@ Common::Input::CameraStatus TransformToCamera(const Common::Input::CallbackStatu
|
||||||
return camera;
|
return camera;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Common::Input::NfcStatus TransformToNfc(const Common::Input::CallbackStatus& callback) {
|
||||||
|
Common::Input::NfcStatus nfc{};
|
||||||
|
switch (callback.type) {
|
||||||
|
case Common::Input::InputType::Nfc:
|
||||||
|
nfc = callback.nfc_status;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_ERROR(Input, "Conversion from type {} to NFC not implemented", callback.type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nfc;
|
||||||
|
}
|
||||||
|
|
||||||
void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value) {
|
void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value) {
|
||||||
const auto& properties = analog.properties;
|
const auto& properties = analog.properties;
|
||||||
float& raw_value = analog.raw_value;
|
float& raw_value = analog.raw_value;
|
||||||
|
|
|
@ -84,6 +84,14 @@ Common::Input::AnalogStatus TransformToAnalog(const Common::Input::CallbackStatu
|
||||||
*/
|
*/
|
||||||
Common::Input::CameraStatus TransformToCamera(const Common::Input::CallbackStatus& callback);
|
Common::Input::CameraStatus TransformToCamera(const Common::Input::CallbackStatus& callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts raw input data into a valid nfc status.
|
||||||
|
*
|
||||||
|
* @param callback Supported callbacks: Nfc.
|
||||||
|
* @return A valid CameraObject object.
|
||||||
|
*/
|
||||||
|
Common::Input::NfcStatus TransformToNfc(const Common::Input::CallbackStatus& callback);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts raw analog data into a valid analog value
|
* Converts raw analog data into a valid analog value
|
||||||
* @param analog An analog object containing raw data and properties
|
* @param analog An analog object containing raw data and properties
|
||||||
|
|
Loading…
Reference in a new issue