diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingButton.cpp b/Source/Core/DolphinQt/Config/Mapping/MappingButton.cpp index d0e1ce4bbe..24e7be9bf8 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingButton.cpp +++ b/Source/Core/DolphinQt/Config/Mapping/MappingButton.cpp @@ -65,8 +65,9 @@ static QString RefToDisplayString(ControlReference* ref) return expression; } -MappingButton::MappingButton(MappingWidget* parent, ControlReference* ref) - : ElidedButton(RefToDisplayString(ref)), m_mapping_window(parent->GetParent()), m_reference(ref) +MappingButton::MappingButton(MappingWidget* parent, ControlReference* ref, ControlType control_type) + : ElidedButton{RefToDisplayString(ref)}, m_mapping_window{parent->GetParent()}, + m_reference{ref}, m_control_type{control_type} { if (m_reference->IsInput()) { @@ -141,3 +142,8 @@ ControlReference* MappingButton::GetControlReference() { return m_reference; } + +auto MappingButton::GetControlType() const -> ControlType +{ + return m_control_type; +} diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingButton.h b/Source/Core/DolphinQt/Config/Mapping/MappingButton.h index 733bdf3e9e..7cac489ad0 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingButton.h +++ b/Source/Core/DolphinQt/Config/Mapping/MappingButton.h @@ -15,9 +15,17 @@ class MappingButton : public ElidedButton { Q_OBJECT public: - MappingButton(MappingWidget* widget, ControlReference* ref); + enum class ControlType + { + NormalInput, + ModifierInput, + Output, + }; + + MappingButton(MappingWidget* widget, ControlReference* ref, ControlType type); ControlReference* GetControlReference(); + ControlType GetControlType() const; signals: void ConfigChanged(); @@ -32,4 +40,5 @@ private: MappingWindow* const m_mapping_window; ControlReference* const m_reference; + const ControlType m_control_type; }; diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingCommon.cpp b/Source/Core/DolphinQt/Config/Mapping/MappingCommon.cpp index 54a0db59ef..d94502b104 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingCommon.cpp +++ b/Source/Core/DolphinQt/Config/Mapping/MappingCommon.cpp @@ -25,6 +25,11 @@ constexpr auto INPUT_DETECT_MAXIMUM_TIME = std::chrono::seconds(5); // Ignore the mouse-click when queuing more buttons with "alternate mappings" enabled. constexpr auto INPUT_DETECT_ENDING_IGNORE_TIME = std::chrono::milliseconds(50); +bool ContainsAnalogInput(const ciface::Core::InputDetector::Results& results) +{ + return std::ranges::any_of(results, [](auto& detection) { return detection.smoothness > 1; }); +} + class MappingProcessor : public QWidget { public: @@ -75,24 +80,40 @@ public: m_input_detector->Update(INPUT_DETECT_INITIAL_TIME, confirmation_time, INPUT_DETECT_MAXIMUM_TIME); - if (m_input_detector->IsComplete()) - { - auto* const button = m_clicked_mapping_buttons.back(); + if (!m_input_detector->IsComplete()) + return; - if (!FinalizeMapping(m_input_detector->TakeResults())) + auto* const button = m_clicked_mapping_buttons.front(); + + auto results = m_input_detector->TakeResults(); + if (!FinalizeMapping(&results)) + { + // No inputs detected. Cancel this and any other queued mappings. + CancelMapping(); + } + else if (m_parent->IsIterativeMappingEnabled() && m_clicked_mapping_buttons.empty()) + { + button->QueueNextButtonMapping(); + + if (m_clicked_mapping_buttons.empty()) + return; + + // Skip "Modifier" mappings when using analog inputs. + auto* next_button = m_clicked_mapping_buttons.front(); + if (next_button->GetControlType() == MappingButton::ControlType::ModifierInput && + ContainsAnalogInput(results)) { - // No inputs detected. Cancel this and any other queued mappings. - CancelMapping(); - } - else if (m_parent->IsIterativeMappingEnabled() && m_clicked_mapping_buttons.empty()) - { - button->QueueNextButtonMapping(); + // Clear "Modifier" mapping and queue the next button. + SetButtonExpression(next_button, ""); + UnQueueInputDetection(next_button); + next_button->QueueNextButtonMapping(); } } } - bool FinalizeMapping(ciface::Core::InputDetector::Results detections) + bool FinalizeMapping(ciface::Core::InputDetector::Results* detections_ptr) { + auto& detections = *detections_ptr; if (!ciface::MappingCommon::ContainsCompleteDetection(detections)) return false; @@ -100,18 +121,22 @@ public: const auto& default_device = m_parent->GetController()->GetDefaultDevice(); auto& button = m_clicked_mapping_buttons.front(); - auto* const control_reference = button->GetControlReference(); + SetButtonExpression( + button, BuildExpression(detections, default_device, ciface::MappingCommon::Quote::On)); - control_reference->SetExpression( - BuildExpression(detections, default_device, ciface::MappingCommon::Quote::On)); - m_parent->Save(); - - m_parent->GetController()->UpdateSingleControlReference(g_controller_interface, - control_reference); UnQueueInputDetection(button); return true; } + void SetButtonExpression(MappingButton* button, const std::string& expression) + { + auto* const control_reference = button->GetControlReference(); + control_reference->SetExpression(expression); + m_parent->Save(); + m_parent->GetController()->UpdateSingleControlReference(g_controller_interface, + control_reference); + } + void UpdateInputDetectionStartTimer() { m_input_detector.reset(); @@ -146,7 +171,7 @@ public: auto results = m_input_detector->TakeResults(); ciface::MappingCommon::RemoveDetectionsAfterTimePoint( &results, ciface::Core::DeviceContainer::Clock::now() - INPUT_DETECT_ENDING_IGNORE_TIME); - FinalizeMapping(std::move(results)); + FinalizeMapping(&results); } UpdateInputDetectionStartTimer(); } diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingWidget.cpp b/Source/Core/DolphinQt/Config/Mapping/MappingWidget.cpp index 442fff464f..036e9c512e 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingWidget.cpp +++ b/Source/Core/DolphinQt/Config/Mapping/MappingWidget.cpp @@ -313,7 +313,16 @@ QGroupBox* MappingWidget::CreateControlsBox(const QString& name, ControllerEmu:: void MappingWidget::CreateControl(const ControllerEmu::Control* control, QFormLayout* layout, bool indicator) { - auto* const button = new MappingButton(this, control->control_ref.get()); + // I know this check is terrible, but it's just UI code. + const bool is_modifier = control->name == "Modifier"; + + using ControlType = MappingButton::ControlType; + const auto control_type = + control->control_ref->IsInput() ? + (is_modifier ? ControlType::ModifierInput : ControlType::NormalInput) : + ControlType::Output; + + auto* const button = new MappingButton(this, control->control_ref.get(), control_type); if (control->control_ref->IsInput()) {