diff options
Diffstat (limited to 'src/core/hid/emulated_controller.cpp')
-rw-r--r-- | src/core/hid/emulated_controller.cpp | 377 |
1 files changed, 213 insertions, 164 deletions
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 7e05666d6..c3f21066c 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -353,14 +353,17 @@ void EmulatedController::DisableConfiguration() { } void EmulatedController::EnableSystemButtons() { + std::scoped_lock lock{mutex}; system_buttons_enabled = true; } void EmulatedController::DisableSystemButtons() { + std::scoped_lock lock{mutex}; system_buttons_enabled = false; } void EmulatedController::ResetSystemButtons() { + std::scoped_lock lock{mutex}; controller.home_button_state.home.Assign(false); controller.capture_button_state.capture.Assign(false); } @@ -494,139 +497,141 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback if (index >= controller.button_values.size()) { return; } - { - std::lock_guard lock{mutex}; - bool value_changed = false; - const auto new_status = TransformToButton(callback); - auto& current_status = controller.button_values[index]; + std::unique_lock lock{mutex}; + bool value_changed = false; + const auto new_status = TransformToButton(callback); + auto& current_status = controller.button_values[index]; - // Only read button values that have the same uuid or are pressed once - if (current_status.uuid != uuid) { - if (!new_status.value) { - return; - } + // Only read button values that have the same uuid or are pressed once + if (current_status.uuid != uuid) { + if (!new_status.value) { + return; } + } - current_status.toggle = new_status.toggle; - current_status.uuid = uuid; - - // 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; - } + current_status.toggle = new_status.toggle; + current_status.uuid = uuid; - // Unlock button ready for next press - if (!new_status.value && current_status.locked) { - current_status.locked = false; - } + // 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; } - - if (!value_changed) { - return; + } 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; } - if (is_configuring) { - controller.npad_button_state.raw = NpadButton::None; - controller.debug_pad_button_state.raw = 0; - TriggerOnChange(ControllerTriggerType::Button, false); - return; + // Unlock button ready for next press + if (!new_status.value && current_status.locked) { + current_status.locked = false; } + } - switch (index) { - case Settings::NativeButton::A: - controller.npad_button_state.a.Assign(current_status.value); - controller.debug_pad_button_state.a.Assign(current_status.value); - break; - case Settings::NativeButton::B: - controller.npad_button_state.b.Assign(current_status.value); - controller.debug_pad_button_state.b.Assign(current_status.value); - break; - case Settings::NativeButton::X: - controller.npad_button_state.x.Assign(current_status.value); - controller.debug_pad_button_state.x.Assign(current_status.value); - break; - case Settings::NativeButton::Y: - controller.npad_button_state.y.Assign(current_status.value); - controller.debug_pad_button_state.y.Assign(current_status.value); - break; - case Settings::NativeButton::LStick: - controller.npad_button_state.stick_l.Assign(current_status.value); - break; - case Settings::NativeButton::RStick: - controller.npad_button_state.stick_r.Assign(current_status.value); - break; - case Settings::NativeButton::L: - controller.npad_button_state.l.Assign(current_status.value); - controller.debug_pad_button_state.l.Assign(current_status.value); - break; - case Settings::NativeButton::R: - controller.npad_button_state.r.Assign(current_status.value); - controller.debug_pad_button_state.r.Assign(current_status.value); - break; - case Settings::NativeButton::ZL: - controller.npad_button_state.zl.Assign(current_status.value); - controller.debug_pad_button_state.zl.Assign(current_status.value); - break; - case Settings::NativeButton::ZR: - controller.npad_button_state.zr.Assign(current_status.value); - controller.debug_pad_button_state.zr.Assign(current_status.value); - break; - case Settings::NativeButton::Plus: - controller.npad_button_state.plus.Assign(current_status.value); - controller.debug_pad_button_state.plus.Assign(current_status.value); - break; - case Settings::NativeButton::Minus: - controller.npad_button_state.minus.Assign(current_status.value); - controller.debug_pad_button_state.minus.Assign(current_status.value); - break; - case Settings::NativeButton::DLeft: - controller.npad_button_state.left.Assign(current_status.value); - controller.debug_pad_button_state.d_left.Assign(current_status.value); - break; - case Settings::NativeButton::DUp: - controller.npad_button_state.up.Assign(current_status.value); - controller.debug_pad_button_state.d_up.Assign(current_status.value); - break; - case Settings::NativeButton::DRight: - controller.npad_button_state.right.Assign(current_status.value); - controller.debug_pad_button_state.d_right.Assign(current_status.value); - break; - case Settings::NativeButton::DDown: - controller.npad_button_state.down.Assign(current_status.value); - controller.debug_pad_button_state.d_down.Assign(current_status.value); - break; - case Settings::NativeButton::SL: - controller.npad_button_state.left_sl.Assign(current_status.value); - controller.npad_button_state.right_sl.Assign(current_status.value); - break; - case Settings::NativeButton::SR: - controller.npad_button_state.left_sr.Assign(current_status.value); - controller.npad_button_state.right_sr.Assign(current_status.value); - break; - case Settings::NativeButton::Home: - if (!system_buttons_enabled) { - break; - } - controller.home_button_state.home.Assign(current_status.value); + if (!value_changed) { + return; + } + + if (is_configuring) { + controller.npad_button_state.raw = NpadButton::None; + controller.debug_pad_button_state.raw = 0; + lock.unlock(); + TriggerOnChange(ControllerTriggerType::Button, false); + return; + } + + switch (index) { + case Settings::NativeButton::A: + controller.npad_button_state.a.Assign(current_status.value); + controller.debug_pad_button_state.a.Assign(current_status.value); + break; + case Settings::NativeButton::B: + controller.npad_button_state.b.Assign(current_status.value); + controller.debug_pad_button_state.b.Assign(current_status.value); + break; + case Settings::NativeButton::X: + controller.npad_button_state.x.Assign(current_status.value); + controller.debug_pad_button_state.x.Assign(current_status.value); + break; + case Settings::NativeButton::Y: + controller.npad_button_state.y.Assign(current_status.value); + controller.debug_pad_button_state.y.Assign(current_status.value); + break; + case Settings::NativeButton::LStick: + controller.npad_button_state.stick_l.Assign(current_status.value); + break; + case Settings::NativeButton::RStick: + controller.npad_button_state.stick_r.Assign(current_status.value); + break; + case Settings::NativeButton::L: + controller.npad_button_state.l.Assign(current_status.value); + controller.debug_pad_button_state.l.Assign(current_status.value); + break; + case Settings::NativeButton::R: + controller.npad_button_state.r.Assign(current_status.value); + controller.debug_pad_button_state.r.Assign(current_status.value); + break; + case Settings::NativeButton::ZL: + controller.npad_button_state.zl.Assign(current_status.value); + controller.debug_pad_button_state.zl.Assign(current_status.value); + break; + case Settings::NativeButton::ZR: + controller.npad_button_state.zr.Assign(current_status.value); + controller.debug_pad_button_state.zr.Assign(current_status.value); + break; + case Settings::NativeButton::Plus: + controller.npad_button_state.plus.Assign(current_status.value); + controller.debug_pad_button_state.plus.Assign(current_status.value); + break; + case Settings::NativeButton::Minus: + controller.npad_button_state.minus.Assign(current_status.value); + controller.debug_pad_button_state.minus.Assign(current_status.value); + break; + case Settings::NativeButton::DLeft: + controller.npad_button_state.left.Assign(current_status.value); + controller.debug_pad_button_state.d_left.Assign(current_status.value); + break; + case Settings::NativeButton::DUp: + controller.npad_button_state.up.Assign(current_status.value); + controller.debug_pad_button_state.d_up.Assign(current_status.value); + break; + case Settings::NativeButton::DRight: + controller.npad_button_state.right.Assign(current_status.value); + controller.debug_pad_button_state.d_right.Assign(current_status.value); + break; + case Settings::NativeButton::DDown: + controller.npad_button_state.down.Assign(current_status.value); + controller.debug_pad_button_state.d_down.Assign(current_status.value); + break; + case Settings::NativeButton::SL: + controller.npad_button_state.left_sl.Assign(current_status.value); + controller.npad_button_state.right_sl.Assign(current_status.value); + break; + case Settings::NativeButton::SR: + controller.npad_button_state.left_sr.Assign(current_status.value); + controller.npad_button_state.right_sr.Assign(current_status.value); + break; + case Settings::NativeButton::Home: + if (!system_buttons_enabled) { break; - case Settings::NativeButton::Screenshot: - if (!system_buttons_enabled) { - break; - } - controller.capture_button_state.capture.Assign(current_status.value); + } + controller.home_button_state.home.Assign(current_status.value); + break; + case Settings::NativeButton::Screenshot: + if (!system_buttons_enabled) { break; } + controller.capture_button_state.capture.Assign(current_status.value); + break; } + + lock.unlock(); + if (!is_connected) { if (npad_id_type == NpadIdType::Player1 && npad_type != NpadStyleIndex::Handheld) { Connect(); @@ -643,7 +648,7 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback, if (index >= controller.stick_values.size()) { return; } - std::lock_guard lock{mutex}; + std::unique_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 @@ -659,6 +664,7 @@ 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; } @@ -685,6 +691,7 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback, break; } + lock.unlock(); TriggerOnChange(ControllerTriggerType::Stick, true); } @@ -693,7 +700,7 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac if (index >= controller.trigger_values.size()) { return; } - std::lock_guard lock{mutex}; + std::unique_lock lock{mutex}; const auto trigger_value = TransformToTrigger(callback); // Only read trigger values that have the same uuid or are pressed once @@ -709,6 +716,7 @@ 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; } @@ -727,6 +735,7 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac break; } + lock.unlock(); TriggerOnChange(ControllerTriggerType::Trigger, true); } @@ -735,7 +744,7 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback if (index >= controller.motion_values.size()) { return; } - std::lock_guard lock{mutex}; + std::unique_lock lock{mutex}; auto& raw_status = controller.motion_values[index].raw_status; auto& emulated = controller.motion_values[index].emulated; @@ -756,6 +765,7 @@ 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; } @@ -767,6 +777,7 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback motion.orientation = emulated.GetOrientation(); motion.is_at_rest = !emulated.IsMoving(motion_sensitivity); + lock.unlock(); TriggerOnChange(ControllerTriggerType::Motion, true); } @@ -775,10 +786,11 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac if (index >= controller.battery_values.size()) { return; } - std::lock_guard lock{mutex}; + std::unique_lock lock{mutex}; controller.battery_values[index] = TransformToBattery(callback); if (is_configuring) { + lock.unlock(); TriggerOnChange(ControllerTriggerType::Battery, false); return; } @@ -835,6 +847,8 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac }; break; } + + lock.unlock(); TriggerOnChange(ControllerTriggerType::Battery, true); } @@ -932,6 +946,7 @@ void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles) } bool EmulatedController::IsControllerFullkey(bool use_temporary_value) const { + std::scoped_lock lock{mutex}; const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; switch (type) { case NpadStyleIndex::ProController: @@ -947,6 +962,7 @@ bool EmulatedController::IsControllerFullkey(bool use_temporary_value) const { } bool EmulatedController::IsControllerSupported(bool use_temporary_value) const { + std::scoped_lock lock{mutex}; const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; switch (type) { case NpadStyleIndex::ProController: @@ -982,40 +998,44 @@ void EmulatedController::Connect(bool use_temporary_value) { LOG_ERROR(Service_HID, "Controller type {} is not supported", type); return; } - { - std::lock_guard lock{mutex}; - if (is_configuring) { - tmp_is_connected = true; - TriggerOnChange(ControllerTriggerType::Connected, false); - return; - } - if (is_connected) { - return; - } - is_connected = true; + std::unique_lock lock{mutex}; + if (is_configuring) { + tmp_is_connected = true; + lock.unlock(); + TriggerOnChange(ControllerTriggerType::Connected, false); + return; + } + + if (is_connected) { + return; } + is_connected = true; + + lock.unlock(); TriggerOnChange(ControllerTriggerType::Connected, true); } void EmulatedController::Disconnect() { - { - std::lock_guard lock{mutex}; - if (is_configuring) { - tmp_is_connected = false; - TriggerOnChange(ControllerTriggerType::Disconnected, false); - return; - } + std::unique_lock lock{mutex}; + if (is_configuring) { + tmp_is_connected = false; + lock.unlock(); + TriggerOnChange(ControllerTriggerType::Disconnected, false); + return; + } - if (!is_connected) { - return; - } - is_connected = false; + if (!is_connected) { + return; } + is_connected = false; + + lock.unlock(); TriggerOnChange(ControllerTriggerType::Disconnected, true); } bool EmulatedController::IsConnected(bool get_temporary_value) const { + std::scoped_lock lock{mutex}; if (get_temporary_value && is_configuring) { return tmp_is_connected; } @@ -1029,10 +1049,12 @@ bool EmulatedController::IsVibrationEnabled() const { } NpadIdType EmulatedController::GetNpadIdType() const { + std::scoped_lock lock{mutex}; return npad_id_type; } NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) const { + std::scoped_lock lock{mutex}; if (get_temporary_value && is_configuring) { return tmp_npad_type; } @@ -1040,27 +1062,28 @@ NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) c } void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) { - { - std::lock_guard lock{mutex}; + std::unique_lock lock{mutex}; - if (is_configuring) { - if (tmp_npad_type == npad_type_) { - return; - } - tmp_npad_type = npad_type_; - TriggerOnChange(ControllerTriggerType::Type, false); + if (is_configuring) { + if (tmp_npad_type == npad_type_) { return; } + tmp_npad_type = npad_type_; + lock.unlock(); + TriggerOnChange(ControllerTriggerType::Type, false); + return; + } - if (npad_type == npad_type_) { - return; - } - if (is_connected) { - LOG_WARNING(Service_HID, "Controller {} type changed while it's connected", - NpadIdTypeToIndex(npad_id_type)); - } - npad_type = npad_type_; + if (npad_type == npad_type_) { + return; + } + if (is_connected) { + LOG_WARNING(Service_HID, "Controller {} type changed while it's connected", + NpadIdTypeToIndex(npad_id_type)); } + npad_type = npad_type_; + + lock.unlock(); TriggerOnChange(ControllerTriggerType::Type, true); } @@ -1088,30 +1111,37 @@ LedPattern EmulatedController::GetLedPattern() const { } ButtonValues EmulatedController::GetButtonsValues() const { + std::scoped_lock lock{mutex}; return controller.button_values; } SticksValues EmulatedController::GetSticksValues() const { + std::scoped_lock lock{mutex}; return controller.stick_values; } TriggerValues EmulatedController::GetTriggersValues() const { + std::scoped_lock lock{mutex}; return controller.trigger_values; } ControllerMotionValues EmulatedController::GetMotionValues() const { + std::scoped_lock lock{mutex}; return controller.motion_values; } ColorValues EmulatedController::GetColorsValues() const { + std::scoped_lock lock{mutex}; return controller.color_values; } BatteryValues EmulatedController::GetBatteryValues() const { + std::scoped_lock lock{mutex}; return controller.battery_values; } HomeButtonState EmulatedController::GetHomeButtons() const { + std::scoped_lock lock{mutex}; if (is_configuring) { return {}; } @@ -1119,6 +1149,7 @@ HomeButtonState EmulatedController::GetHomeButtons() const { } CaptureButtonState EmulatedController::GetCaptureButtons() const { + std::scoped_lock lock{mutex}; if (is_configuring) { return {}; } @@ -1126,6 +1157,7 @@ CaptureButtonState EmulatedController::GetCaptureButtons() const { } NpadButtonState EmulatedController::GetNpadButtons() const { + std::scoped_lock lock{mutex}; if (is_configuring) { return {}; } @@ -1133,6 +1165,7 @@ NpadButtonState EmulatedController::GetNpadButtons() const { } DebugPadButton EmulatedController::GetDebugPadButtons() const { + std::scoped_lock lock{mutex}; if (is_configuring) { return {}; } @@ -1140,20 +1173,27 @@ DebugPadButton EmulatedController::GetDebugPadButtons() const { } AnalogSticks EmulatedController::GetSticks() const { + std::unique_lock lock{mutex}; + if (is_configuring) { return {}; } + // Some drivers like stick from buttons need constant refreshing for (auto& device : stick_devices) { if (!device) { continue; } + lock.unlock(); device->SoftUpdate(); + lock.lock(); } + return controller.analog_stick_state; } NpadGcTriggerState EmulatedController::GetTriggers() const { + std::scoped_lock lock{mutex}; if (is_configuring) { return {}; } @@ -1161,26 +1201,35 @@ NpadGcTriggerState EmulatedController::GetTriggers() const { } MotionState EmulatedController::GetMotions() const { + std::unique_lock lock{mutex}; + + // Some drivers like mouse motion need constant refreshing if (force_update_motion) { for (auto& device : motion_devices) { if (!device) { continue; } + lock.unlock(); device->ForceUpdate(); + lock.lock(); } } + return controller.motion_state; } ControllerColors EmulatedController::GetColors() const { + std::scoped_lock lock{mutex}; return controller.colors_state; } BatteryLevelState EmulatedController::GetBattery() const { + std::scoped_lock lock{mutex}; return controller.battery_state; } void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) { + std::scoped_lock lock{callback_mutex}; for (const auto& poller_pair : callback_list) { const ControllerUpdateCallback& poller = poller_pair.second; if (!is_npad_service_update && poller.is_npad_service) { @@ -1193,13 +1242,13 @@ void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npa } int EmulatedController::SetCallback(ControllerUpdateCallback update_callback) { - std::lock_guard lock{mutex}; + std::scoped_lock lock{callback_mutex}; callback_list.insert_or_assign(last_callback_key, std::move(update_callback)); return last_callback_key++; } void EmulatedController::DeleteCallback(int key) { - std::lock_guard lock{mutex}; + 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); |