diff options
Diffstat (limited to 'src/core/hid')
-rw-r--r-- | src/core/hid/emulated_controller.cpp | 373 | ||||
-rw-r--r-- | src/core/hid/emulated_controller.h | 70 | ||||
-rw-r--r-- | src/core/hid/emulated_devices.cpp | 46 | ||||
-rw-r--r-- | src/core/hid/emulated_devices.h | 18 | ||||
-rw-r--r-- | src/core/hid/input_converter.cpp | 12 | ||||
-rw-r--r-- | src/core/hid/input_converter.h | 10 |
6 files changed, 375 insertions, 154 deletions
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 7a01f3f4c..631aa6ad2 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include <algorithm> +#include <common/scope_exit.h> #include "common/polyfill_ranges.h" #include "common/thread.h" @@ -11,6 +12,7 @@ namespace Core::HID { constexpr s32 HID_JOYSTICK_MAX = 0x7fff; constexpr s32 HID_TRIGGER_MAX = 0x7fff; +constexpr u32 TURBO_BUTTON_DELAY = 4; // Use a common UUID for TAS and Virtual Gamepad constexpr Common::UUID TAS_UUID = Common::UUID{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xA5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; @@ -93,6 +95,7 @@ void EmulatedController::ReloadFromSettings() { motion_params[index] = Common::ParamPackage(player.motions[index]); } + controller.color_values = {}; controller.colors_state.fullkey = { .body = GetNpadColor(player.body_color_left), .button = GetNpadColor(player.button_color_left), @@ -106,6 +109,8 @@ void EmulatedController::ReloadFromSettings() { .button = GetNpadColor(player.button_color_right), }; + ring_params[0] = Common::ParamPackage(Settings::values.ringcon_analogs); + // Other or debug controller should always be a pro controller if (npad_id_type != NpadIdType::Other) { SetNpadStyleIndex(MapSettingsTypeToNPad(player.controller_type)); @@ -132,18 +137,28 @@ void EmulatedController::LoadDevices() { trigger_params[LeftIndex] = button_params[Settings::NativeButton::ZL]; trigger_params[RightIndex] = button_params[Settings::NativeButton::ZR]; + color_params[LeftIndex] = left_joycon; + color_params[RightIndex] = right_joycon; + color_params[LeftIndex].Set("color", true); + color_params[RightIndex].Set("color", true); + battery_params[LeftIndex] = left_joycon; battery_params[RightIndex] = right_joycon; battery_params[LeftIndex].Set("battery", true); battery_params[RightIndex].Set("battery", true); - camera_params = Common::ParamPackage{"engine:camera,camera:1"}; - nfc_params = Common::ParamPackage{"engine:virtual_amiibo,nfc:1"}; + camera_params[0] = right_joycon; + camera_params[0].Set("camera", true); + camera_params[1] = Common::ParamPackage{"engine:camera,camera:1"}; + ring_params[1] = Common::ParamPackage{"engine:joycon,axis_x:100,axis_y:101"}; + nfc_params[0] = Common::ParamPackage{"engine:virtual_amiibo,nfc:1"}; + nfc_params[1] = right_joycon; + nfc_params[1].Set("nfc", true); output_params[LeftIndex] = left_joycon; output_params[RightIndex] = right_joycon; - output_params[2] = camera_params; - output_params[3] = nfc_params; + output_params[2] = camera_params[1]; + output_params[3] = nfc_params[0]; output_params[LeftIndex].Set("output", true); output_params[RightIndex].Set("output", true); output_params[2].Set("output", true); @@ -159,8 +174,11 @@ void EmulatedController::LoadDevices() { Common::Input::CreateInputDevice); std::ranges::transform(battery_params, battery_devices.begin(), Common::Input::CreateInputDevice); - camera_devices = Common::Input::CreateInputDevice(camera_params); - nfc_devices = Common::Input::CreateInputDevice(nfc_params); + std::ranges::transform(color_params, color_devices.begin(), Common::Input::CreateInputDevice); + std::ranges::transform(camera_params, camera_devices.begin(), Common::Input::CreateInputDevice); + std::ranges::transform(ring_params, ring_analog_devices.begin(), + Common::Input::CreateInputDevice); + std::ranges::transform(nfc_params, nfc_devices.begin(), Common::Input::CreateInputDevice); std::ranges::transform(output_params, output_devices.begin(), Common::Input::CreateOutputDevice); @@ -322,6 +340,19 @@ void EmulatedController::ReloadInput() { battery_devices[index]->ForceUpdate(); } + for (std::size_t index = 0; index < color_devices.size(); ++index) { + if (!color_devices[index]) { + continue; + } + color_devices[index]->SetCallback({ + .on_change = + [this, index](const Common::Input::CallbackStatus& callback) { + SetColors(callback, index); + }, + }); + color_devices[index]->ForceUpdate(); + } + for (std::size_t index = 0; index < motion_devices.size(); ++index) { if (!motion_devices[index]) { continue; @@ -335,22 +366,37 @@ void EmulatedController::ReloadInput() { motion_devices[index]->ForceUpdate(); } - if (camera_devices) { - camera_devices->SetCallback({ + for (std::size_t index = 0; index < camera_devices.size(); ++index) { + if (!camera_devices[index]) { + continue; + } + camera_devices[index]->SetCallback({ .on_change = [this](const Common::Input::CallbackStatus& callback) { SetCamera(callback); }, }); - camera_devices->ForceUpdate(); + camera_devices[index]->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(); + for (std::size_t index = 0; index < ring_analog_devices.size(); ++index) { + if (!ring_analog_devices[index]) { + continue; + } + ring_analog_devices[index]->SetCallback({ + .on_change = + [this](const Common::Input::CallbackStatus& callback) { SetRingAnalog(callback); }, + }); + ring_analog_devices[index]->ForceUpdate(); + } + + for (std::size_t index = 0; index < nfc_devices.size(); ++index) { + if (!nfc_devices[index]) { + continue; } + nfc_devices[index]->SetCallback({ + .on_change = + [this](const Common::Input::CallbackStatus& callback) { SetNfc(callback); }, + }); + nfc_devices[index]->ForceUpdate(); } // Register TAS devices. No need to force update @@ -402,6 +448,7 @@ void EmulatedController::ReloadInput() { }, }); } + turbo_button_state = 0; } void EmulatedController::UnloadInput() { @@ -420,6 +467,9 @@ void EmulatedController::UnloadInput() { for (auto& battery : battery_devices) { battery.reset(); } + for (auto& color : color_devices) { + color.reset(); + } for (auto& output : output_devices) { output.reset(); } @@ -435,8 +485,15 @@ void EmulatedController::UnloadInput() { for (auto& stick : virtual_stick_devices) { stick.reset(); } - camera_devices.reset(); - nfc_devices.reset(); + for (auto& camera : camera_devices) { + camera.reset(); + } + for (auto& ring : ring_analog_devices) { + ring.reset(); + } + for (auto& nfc : nfc_devices) { + nfc.reset(); + } } void EmulatedController::EnableConfiguration() { @@ -448,6 +505,11 @@ void EmulatedController::EnableConfiguration() { void EmulatedController::DisableConfiguration() { is_configuring = false; + // Get Joycon colors before turning on the controller + for (const auto& color_device : color_devices) { + color_device->ForceUpdate(); + } + // Apply temporary npad type to the real controller if (tmp_npad_type != npad_type) { if (is_connected) { @@ -501,6 +563,9 @@ void EmulatedController::SaveCurrentConfig() { for (std::size_t index = 0; index < player.motions.size(); ++index) { player.motions[index] = motion_params[index].Serialize(); } + if (npad_id_type == NpadIdType::Player1) { + Settings::values.ringcon_analogs = ring_params[0].Serialize(); + } } void EmulatedController::RestoreConfig() { @@ -624,6 +689,7 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback } current_status.toggle = new_status.toggle; + current_status.turbo = new_status.turbo; current_status.uuid = uuid; // Update button status with current @@ -772,17 +838,21 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback, if (index >= controller.stick_values.size()) { return; } - std::unique_lock lock{mutex}; + auto trigger_guard = + SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Stick, !is_configuring); }); + std::scoped_lock lock{mutex}; const auto stick_value = TransformToStick(callback); // Only read stick values that have the same uuid or are over the threshold to avoid flapping if (controller.stick_values[index].uuid != uuid) { const bool is_tas = uuid == TAS_UUID; if (is_tas && stick_value.x.value == 0 && stick_value.y.value == 0) { + trigger_guard.Cancel(); return; } if (!is_tas && !stick_value.down && !stick_value.up && !stick_value.left && !stick_value.right) { + trigger_guard.Cancel(); return; } } @@ -793,8 +863,6 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback, if (is_configuring) { controller.analog_stick_state.left = {}; controller.analog_stick_state.right = {}; - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Stick, false); return; } @@ -819,9 +887,6 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback, controller.npad_button_state.stick_r_down.Assign(controller.stick_values[index].down); break; } - - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Stick, true); } void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callback, @@ -829,7 +894,9 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac if (index >= controller.trigger_values.size()) { return; } - std::unique_lock lock{mutex}; + auto trigger_guard = + SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Trigger, !is_configuring); }); + std::scoped_lock lock{mutex}; const auto trigger_value = TransformToTrigger(callback); // Only read trigger values that have the same uuid or are pressed once @@ -845,13 +912,12 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac if (is_configuring) { controller.gc_trigger_state.left = 0; controller.gc_trigger_state.right = 0; - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Trigger, false); return; } // Only GC controllers have analog triggers if (npad_type != NpadStyleIndex::GameCube) { + trigger_guard.Cancel(); return; } @@ -868,9 +934,6 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac controller.npad_button_state.zr.Assign(trigger.pressed.value); break; } - - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Trigger, true); } void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback, @@ -878,7 +941,8 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback if (index >= controller.motion_values.size()) { return; } - std::unique_lock lock{mutex}; + SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Motion, !is_configuring); }); + std::scoped_lock lock{mutex}; auto& raw_status = controller.motion_values[index].raw_status; auto& emulated = controller.motion_values[index].emulated; @@ -899,8 +963,6 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback force_update_motion = raw_status.force_update; if (is_configuring) { - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Motion, false); return; } @@ -910,9 +972,56 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback motion.rotation = emulated.GetRotations(); motion.orientation = emulated.GetOrientation(); motion.is_at_rest = !emulated.IsMoving(motion_sensitivity); +} - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Motion, true); +void EmulatedController::SetColors(const Common::Input::CallbackStatus& callback, + std::size_t index) { + if (index >= controller.color_values.size()) { + return; + } + auto trigger_guard = + SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Color, !is_configuring); }); + std::scoped_lock lock{mutex}; + controller.color_values[index] = TransformToColor(callback); + + if (is_configuring) { + return; + } + + if (controller.color_values[index].body == 0) { + trigger_guard.Cancel(); + return; + } + + controller.colors_state.fullkey = { + .body = GetNpadColor(controller.color_values[index].body), + .button = GetNpadColor(controller.color_values[index].buttons), + }; + if (npad_type == NpadStyleIndex::ProController) { + controller.colors_state.left = { + .body = GetNpadColor(controller.color_values[index].left_grip), + .button = GetNpadColor(controller.color_values[index].buttons), + }; + controller.colors_state.right = { + .body = GetNpadColor(controller.color_values[index].right_grip), + .button = GetNpadColor(controller.color_values[index].buttons), + }; + } else { + switch (index) { + case LeftIndex: + controller.colors_state.left = { + .body = GetNpadColor(controller.color_values[index].body), + .button = GetNpadColor(controller.color_values[index].buttons), + }; + break; + case RightIndex: + controller.colors_state.right = { + .body = GetNpadColor(controller.color_values[index].body), + .button = GetNpadColor(controller.color_values[index].buttons), + }; + break; + } + } } void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callback, @@ -920,12 +1029,11 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac if (index >= controller.battery_values.size()) { return; } - std::unique_lock lock{mutex}; + SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Battery, !is_configuring); }); + std::scoped_lock lock{mutex}; controller.battery_values[index] = TransformToBattery(callback); if (is_configuring) { - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Battery, false); return; } @@ -981,18 +1089,14 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac }; break; } - - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Battery, true); } void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback) { - std::unique_lock lock{mutex}; + SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::IrSensor, !is_configuring); }); + std::scoped_lock lock{mutex}; controller.camera_values = TransformToCamera(callback); if (is_configuring) { - lock.unlock(); - TriggerOnChange(ControllerTriggerType::IrSensor, false); return; } @@ -1000,18 +1104,28 @@ void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback controller.camera_state.format = static_cast<Core::IrSensor::ImageTransferProcessorFormat>(controller.camera_values.format); controller.camera_state.data = controller.camera_values.data; +} - lock.unlock(); - TriggerOnChange(ControllerTriggerType::IrSensor, true); +void EmulatedController::SetRingAnalog(const Common::Input::CallbackStatus& callback) { + SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::RingController, !is_configuring); }); + std::scoped_lock lock{mutex}; + const auto force_value = TransformToStick(callback); + + controller.ring_analog_value = force_value.x; + + if (is_configuring) { + return; + } + + controller.ring_analog_state.force = force_value.x.value; } void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) { - std::unique_lock lock{mutex}; + SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Nfc, !is_configuring); }); + std::scoped_lock lock{mutex}; controller.nfc_values = TransformToNfc(callback); if (is_configuring) { - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Nfc, false); return; } @@ -1019,9 +1133,6 @@ void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) { controller.nfc_values.state, controller.nfc_values.data, }; - - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Nfc, true); } bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) { @@ -1053,7 +1164,7 @@ bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue v .type = type, }; return output_devices[device_index]->SetVibration(status) == - Common::Input::VibrationError::None; + Common::Input::DriverResult::Success; } bool EmulatedController::IsVibrationEnabled(std::size_t device_index) { @@ -1075,16 +1186,32 @@ bool EmulatedController::IsVibrationEnabled(std::size_t device_index) { return output_devices[device_index]->IsVibrationEnabled(); } -bool EmulatedController::SetPollingMode(Common::Input::PollingMode polling_mode) { - LOG_INFO(Service_HID, "Set polling mode {}", polling_mode); - auto& output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; +Common::Input::DriverResult EmulatedController::SetPollingMode( + EmulatedDeviceIndex device_index, Common::Input::PollingMode polling_mode) { + LOG_INFO(Service_HID, "Set polling mode {}, device_index={}", polling_mode, device_index); + + auto& left_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Left)]; + auto& right_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; auto& nfc_output_device = output_devices[3]; - const auto virtual_nfc_result = nfc_output_device->SetPollingMode(polling_mode); - const auto mapped_nfc_result = output_device->SetPollingMode(polling_mode); + if (device_index == EmulatedDeviceIndex::LeftIndex) { + return left_output_device->SetPollingMode(polling_mode); + } + + if (device_index == EmulatedDeviceIndex::RightIndex) { + const auto virtual_nfc_result = nfc_output_device->SetPollingMode(polling_mode); + const auto mapped_nfc_result = right_output_device->SetPollingMode(polling_mode); - return virtual_nfc_result == Common::Input::PollingError::None || - mapped_nfc_result == Common::Input::PollingError::None; + if (virtual_nfc_result == Common::Input::DriverResult::Success) { + return virtual_nfc_result; + } + return mapped_nfc_result; + } + + left_output_device->SetPollingMode(polling_mode); + right_output_device->SetPollingMode(polling_mode); + nfc_output_device->SetPollingMode(polling_mode); + return Common::Input::DriverResult::Success; } bool EmulatedController::SetCameraFormat( @@ -1095,13 +1222,22 @@ bool EmulatedController::SetCameraFormat( auto& camera_output_device = output_devices[2]; if (right_output_device->SetCameraFormat(static_cast<Common::Input::CameraFormat>( - camera_format)) == Common::Input::CameraError::None) { + camera_format)) == Common::Input::DriverResult::Success) { return true; } // Fallback to Qt camera if native device doesn't have support return camera_output_device->SetCameraFormat(static_cast<Common::Input::CameraFormat>( - camera_format)) == Common::Input::CameraError::None; + camera_format)) == Common::Input::DriverResult::Success; +} + +Common::ParamPackage EmulatedController::GetRingParam() const { + return ring_params[0]; +} + +void EmulatedController::SetRingParam(Common::ParamPackage param) { + ring_params[0] = std::move(param); + ReloadInput(); } bool EmulatedController::HasNfc() const { @@ -1255,39 +1391,35 @@ void EmulatedController::Connect(bool use_temporary_value) { return; } - std::unique_lock lock{mutex}; + auto trigger_guard = + SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Connected, !is_configuring); }); + std::scoped_lock lock{mutex}; if (is_configuring) { tmp_is_connected = true; - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Connected, false); return; } if (is_connected) { + trigger_guard.Cancel(); return; } is_connected = true; - - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Connected, true); } void EmulatedController::Disconnect() { - std::unique_lock lock{mutex}; + auto trigger_guard = + SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Disconnected, !is_configuring); }); + std::scoped_lock lock{mutex}; if (is_configuring) { tmp_is_connected = false; - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Disconnected, false); return; } if (!is_connected) { + trigger_guard.Cancel(); return; } is_connected = false; - - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Disconnected, true); } bool EmulatedController::IsConnected(bool get_temporary_value) const { @@ -1312,19 +1444,21 @@ NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) c } void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) { - std::unique_lock lock{mutex}; + auto trigger_guard = + SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Type, !is_configuring); }); + std::scoped_lock lock{mutex}; if (is_configuring) { if (tmp_npad_type == npad_type_) { + trigger_guard.Cancel(); return; } tmp_npad_type = npad_type_; - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Type, false); return; } if (npad_type == npad_type_) { + trigger_guard.Cancel(); return; } if (is_connected) { @@ -1332,9 +1466,6 @@ void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) { NpadIdTypeToIndex(npad_id_type)); } npad_type = npad_type_; - - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Type, true); } LedPattern EmulatedController::GetLedPattern() const { @@ -1395,6 +1526,10 @@ CameraValues EmulatedController::GetCameraValues() const { return controller.camera_values; } +RingAnalogValue EmulatedController::GetRingSensorValues() const { + return controller.ring_analog_value; +} + HomeButtonState EmulatedController::GetHomeButtons() const { std::scoped_lock lock{mutex}; if (is_configuring) { @@ -1416,7 +1551,7 @@ NpadButtonState EmulatedController::GetNpadButtons() const { if (is_configuring) { return {}; } - return controller.npad_button_state; + return {controller.npad_button_state.raw & GetTurboButtonMask()}; } DebugPadButton EmulatedController::GetDebugPadButtons() const { @@ -1428,7 +1563,7 @@ DebugPadButton EmulatedController::GetDebugPadButtons() const { } AnalogSticks EmulatedController::GetSticks() const { - std::unique_lock lock{mutex}; + std::scoped_lock lock{mutex}; if (is_configuring) { return {}; @@ -1478,6 +1613,10 @@ const CameraState& EmulatedController::GetCamera() const { return controller.camera_state; } +RingSensorForce EmulatedController::GetRingSensorForce() const { + return controller.ring_analog_state; +} + const NfcState& EmulatedController::GetNfc() const { std::scoped_lock lock{mutex}; return controller.nfc_state; @@ -1520,4 +1659,74 @@ void EmulatedController::DeleteCallback(int key) { } callback_list.erase(iterator); } + +void EmulatedController::TurboButtonUpdate() { + turbo_button_state = (turbo_button_state + 1) % (TURBO_BUTTON_DELAY * 2); +} + +NpadButton EmulatedController::GetTurboButtonMask() const { + // Apply no mask when disabled + if (turbo_button_state < TURBO_BUTTON_DELAY) { + return {NpadButton::All}; + } + + NpadButtonState button_mask{}; + for (std::size_t index = 0; index < controller.button_values.size(); ++index) { + if (!controller.button_values[index].turbo) { + continue; + } + + switch (index) { + case Settings::NativeButton::A: + button_mask.a.Assign(1); + break; + case Settings::NativeButton::B: + button_mask.b.Assign(1); + break; + case Settings::NativeButton::X: + button_mask.x.Assign(1); + break; + case Settings::NativeButton::Y: + button_mask.y.Assign(1); + break; + case Settings::NativeButton::L: + button_mask.l.Assign(1); + break; + case Settings::NativeButton::R: + button_mask.r.Assign(1); + break; + case Settings::NativeButton::ZL: + button_mask.zl.Assign(1); + break; + case Settings::NativeButton::ZR: + button_mask.zr.Assign(1); + break; + case Settings::NativeButton::DLeft: + button_mask.left.Assign(1); + break; + case Settings::NativeButton::DUp: + button_mask.up.Assign(1); + break; + case Settings::NativeButton::DRight: + button_mask.right.Assign(1); + break; + case Settings::NativeButton::DDown: + button_mask.down.Assign(1); + break; + case Settings::NativeButton::SL: + button_mask.left_sl.Assign(1); + button_mask.right_sl.Assign(1); + break; + case Settings::NativeButton::SR: + button_mask.left_sr.Assign(1); + button_mask.right_sr.Assign(1); + break; + default: + break; + } + } + + return static_cast<NpadButton>(~button_mask.raw); +} + } // namespace Core::HID diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index a398543a6..b02bf35c4 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -35,19 +35,27 @@ 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::unique_ptr<Common::Input::InputDevice>; -using NfcDevices = std::unique_ptr<Common::Input::InputDevice>; +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 = Common::ParamPackage; -using NfcParams = Common::ParamPackage; +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>; @@ -58,6 +66,7 @@ using ControllerMotionValues = std::array<ControllerMotionInfo, Settings::Native 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>; @@ -84,6 +93,10 @@ struct CameraState { std::size_t sample{}; }; +struct RingSensorForce { + f32 force; +}; + struct NfcState { Common::Input::NfcState state{}; std::vector<u8> data{}; @@ -116,6 +129,7 @@ struct ControllerStatus { BatteryValues battery_values{}; VibrationValues vibration_values{}; CameraValues camera_values{}; + RingAnalogValue ring_analog_value{}; NfcValues nfc_values{}; // Data for HID serices @@ -129,6 +143,7 @@ struct ControllerStatus { ControllerColors colors_state{}; BatteryLevelState battery_state{}; CameraState camera_state{}; + RingSensorForce ring_analog_state{}; NfcState nfc_state{}; }; @@ -141,6 +156,7 @@ enum class ControllerTriggerType { Battery, Vibration, IrSensor, + RingController, Nfc, Connected, Disconnected, @@ -294,6 +310,9 @@ public: /// 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; @@ -324,6 +343,9 @@ public: /// 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; @@ -341,10 +363,12 @@ public: /** * 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 true if SetPollingMode was successfull + * @return driver result from this command */ - bool SetPollingMode(Common::Input::PollingMode polling_mode); + Common::Input::DriverResult SetPollingMode(EmulatedDeviceIndex device_index, + Common::Input::PollingMode polling_mode); /** * Sets the desired camera format to be polled from a controller @@ -353,6 +377,15 @@ public: */ 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; @@ -378,6 +411,9 @@ public: */ void DeleteCallback(int key); + /// Swaps the state of the turbo buttons + void TurboButtonUpdate(); + private: /// creates input devices from params void LoadDevices(); @@ -433,9 +469,16 @@ private: 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 Button ID of the to be updated + * @param index battery ID of the to be updated */ void SetBattery(const Common::Input::CallbackStatus& callback, std::size_t index); @@ -446,6 +489,12 @@ private: 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 */ @@ -465,6 +514,8 @@ private: */ 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}; @@ -474,6 +525,7 @@ private: bool system_buttons_enabled{true}; f32 motion_sensitivity{0.01f}; bool force_update_motion{false}; + u32 turbo_button_state{0}; // Temporary values to avoid doing changes while the controller is in configuring mode NpadStyleIndex tmp_npad_type{NpadStyleIndex::None}; @@ -484,7 +536,9 @@ private: ControllerMotionParams motion_params; TriggerParams trigger_params; BatteryParams battery_params; + ColorParams color_params; CameraParams camera_params; + RingAnalogParams ring_params; NfcParams nfc_params; OutputParams output_params; @@ -493,7 +547,9 @@ private: 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; diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp index e421828d2..836f32c0f 100644 --- a/src/core/hid/emulated_devices.cpp +++ b/src/core/hid/emulated_devices.cpp @@ -14,7 +14,6 @@ EmulatedDevices::EmulatedDevices() = default; EmulatedDevices::~EmulatedDevices() = default; void EmulatedDevices::ReloadFromSettings() { - ring_params = Common::ParamPackage(Settings::values.ringcon_analogs); ReloadInput(); } @@ -66,8 +65,6 @@ void EmulatedDevices::ReloadInput() { key_index++; } - ring_analog_device = Common::Input::CreateInputDevice(ring_params); - for (std::size_t index = 0; index < mouse_button_devices.size(); ++index) { if (!mouse_button_devices[index]) { continue; @@ -122,13 +119,6 @@ void EmulatedDevices::ReloadInput() { }, }); } - - if (ring_analog_device) { - ring_analog_device->SetCallback({ - .on_change = - [this](const Common::Input::CallbackStatus& callback) { SetRingAnalog(callback); }, - }); - } } void EmulatedDevices::UnloadInput() { @@ -145,7 +135,6 @@ void EmulatedDevices::UnloadInput() { for (auto& button : keyboard_modifier_devices) { button.reset(); } - ring_analog_device.reset(); } void EmulatedDevices::EnableConfiguration() { @@ -165,7 +154,6 @@ void EmulatedDevices::SaveCurrentConfig() { if (!is_configuring) { return; } - Settings::values.ringcon_analogs = ring_params.Serialize(); } void EmulatedDevices::RestoreConfig() { @@ -175,15 +163,6 @@ void EmulatedDevices::RestoreConfig() { ReloadFromSettings(); } -Common::ParamPackage EmulatedDevices::GetRingParam() const { - return ring_params; -} - -void EmulatedDevices::SetRingParam(Common::ParamPackage param) { - ring_params = std::move(param); - ReloadInput(); -} - void EmulatedDevices::SetKeyboardButton(const Common::Input::CallbackStatus& callback, std::size_t index) { if (index >= device_status.keyboard_values.size()) { @@ -430,23 +409,6 @@ void EmulatedDevices::SetMouseStick(const Common::Input::CallbackStatus& callbac TriggerOnChange(DeviceTriggerType::Mouse); } -void EmulatedDevices::SetRingAnalog(const Common::Input::CallbackStatus& callback) { - std::lock_guard lock{mutex}; - const auto force_value = TransformToStick(callback); - - device_status.ring_analog_value = force_value.x; - - if (is_configuring) { - device_status.ring_analog_value = {}; - TriggerOnChange(DeviceTriggerType::RingController); - return; - } - - device_status.ring_analog_state.force = force_value.x.value; - - TriggerOnChange(DeviceTriggerType::RingController); -} - KeyboardValues EmulatedDevices::GetKeyboardValues() const { std::scoped_lock lock{mutex}; return device_status.keyboard_values; @@ -462,10 +424,6 @@ MouseButtonValues EmulatedDevices::GetMouseButtonsValues() const { return device_status.mouse_button_values; } -RingAnalogValue EmulatedDevices::GetRingSensorValues() const { - return device_status.ring_analog_value; -} - KeyboardKey EmulatedDevices::GetKeyboard() const { std::scoped_lock lock{mutex}; return device_status.keyboard_state; @@ -491,10 +449,6 @@ AnalogStickState EmulatedDevices::GetMouseWheel() const { return device_status.mouse_wheel_state; } -RingSensorForce EmulatedDevices::GetRingSensorForce() const { - return device_status.ring_analog_state; -} - void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) { std::scoped_lock lock{callback_mutex}; for (const auto& poller_pair : callback_list) { diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h index 4cdbf9dc6..76f9150df 100644 --- a/src/core/hid/emulated_devices.h +++ b/src/core/hid/emulated_devices.h @@ -26,11 +26,9 @@ using MouseButtonDevices = std::array<std::unique_ptr<Common::Input::InputDevice using MouseAnalogDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeMouseWheel::NumMouseWheels>; using MouseStickDevice = std::unique_ptr<Common::Input::InputDevice>; -using RingAnalogDevice = std::unique_ptr<Common::Input::InputDevice>; using MouseButtonParams = std::array<Common::ParamPackage, Settings::NativeMouseButton::NumMouseButtons>; -using RingAnalogParams = Common::ParamPackage; using KeyboardValues = std::array<Common::Input::ButtonStatus, Settings::NativeKeyboard::NumKeyboardKeys>; @@ -41,17 +39,12 @@ using MouseButtonValues = using MouseAnalogValues = std::array<Common::Input::AnalogStatus, Settings::NativeMouseWheel::NumMouseWheels>; using MouseStickValue = Common::Input::TouchStatus; -using RingAnalogValue = Common::Input::AnalogStatus; struct MousePosition { f32 x; f32 y; }; -struct RingSensorForce { - f32 force; -}; - struct DeviceStatus { // Data from input_common KeyboardValues keyboard_values{}; @@ -59,7 +52,6 @@ struct DeviceStatus { MouseButtonValues mouse_button_values{}; MouseAnalogValues mouse_analog_values{}; MouseStickValue mouse_stick_value{}; - RingAnalogValue ring_analog_value{}; // Data for HID serices KeyboardKey keyboard_state{}; @@ -67,7 +59,6 @@ struct DeviceStatus { MouseButton mouse_button_state{}; MousePosition mouse_position_state{}; AnalogStickState mouse_wheel_state{}; - RingSensorForce ring_analog_state{}; }; enum class DeviceTriggerType { @@ -138,9 +129,6 @@ public: /// Returns the latest status of button input from the mouse with parameters MouseButtonValues GetMouseButtonsValues() const; - /// Returns the latest status of analog input from the ring sensor with parameters - RingAnalogValue GetRingSensorValues() const; - /// Returns the latest status of button input from the keyboard KeyboardKey GetKeyboard() const; @@ -156,9 +144,6 @@ public: /// Returns the latest mouse wheel change AnalogStickState GetMouseWheel() const; - /// Returns the latest ringcon force sensor value - RingSensorForce GetRingSensorForce() const; - /** * Adds a callback to the list of events * @param update_callback InterfaceUpdateCallback that will be triggered @@ -224,14 +209,11 @@ private: bool is_configuring{false}; - RingAnalogParams ring_params; - KeyboardDevices keyboard_devices; KeyboardModifierDevices keyboard_modifier_devices; MouseButtonDevices mouse_button_devices; MouseAnalogDevices mouse_analog_devices; MouseStickDevice mouse_stick_device; - RingAnalogDevice ring_analog_device; mutable std::mutex mutex; mutable std::mutex callback_mutex; diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index 502692875..3f7b8c090 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp @@ -304,6 +304,18 @@ Common::Input::NfcStatus TransformToNfc(const Common::Input::CallbackStatus& cal return nfc; } +Common::Input::BodyColorStatus TransformToColor(const Common::Input::CallbackStatus& callback) { + switch (callback.type) { + case Common::Input::InputType::Color: + return callback.color_status; + break; + default: + LOG_ERROR(Input, "Conversion from type {} to color not implemented", callback.type); + return {}; + break; + } +} + void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value) { const auto& properties = analog.properties; float& raw_value = analog.raw_value; diff --git a/src/core/hid/input_converter.h b/src/core/hid/input_converter.h index b7eb6e660..c51c03e57 100644 --- a/src/core/hid/input_converter.h +++ b/src/core/hid/input_converter.h @@ -88,11 +88,19 @@ Common::Input::CameraStatus TransformToCamera(const Common::Input::CallbackStatu * Converts raw input data into a valid nfc status. * * @param callback Supported callbacks: Nfc. - * @return A valid CameraObject object. + * @return A valid data tag vector. */ Common::Input::NfcStatus TransformToNfc(const Common::Input::CallbackStatus& callback); /** + * Converts raw input data into a valid color status. + * + * @param callback Supported callbacks: Color. + * @return A valid Color object. + */ +Common::Input::BodyColorStatus TransformToColor(const Common::Input::CallbackStatus& callback); + +/** * Converts raw analog data into a valid analog value * @param analog An analog object containing raw data and properties * @param clamp_value determines if the value needs to be clamped between -1.0f and 1.0f. |