summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJMC47 <JMC4789@gmail.com>2025-02-15 12:59:23 -0500
committerGitHub <noreply@github.com>2025-02-15 12:59:23 -0500
commita8fae9b82683dd0ea766cb8c282b414707962255 (patch)
tree6ab551bcd3d7ef3459f369bf45206577c60d5231
parentc360ea0d9d5caaa0d305711eb1a86ad30d6353da (diff)
parent6e7e808b6614f98674dba7290bea2ea044c4d5d2 (diff)
Merge pull request #13320 from jordan-woyak/detect-alternations
DolphinQt/Mapping: Add setting to enable waiting for alternate mappings.
-rw-r--r--Source/Core/DolphinQt/Config/Mapping/MappingCommon.cpp57
-rw-r--r--Source/Core/DolphinQt/Config/Mapping/MappingWindow.cpp19
-rw-r--r--Source/Core/DolphinQt/Config/Mapping/MappingWindow.h6
-rw-r--r--Source/Core/InputCommon/ControllerInterface/CoreDevice.cpp6
-rw-r--r--Source/Core/InputCommon/ControllerInterface/CoreDevice.h7
-rw-r--r--Source/Core/InputCommon/ControllerInterface/MappingCommon.cpp27
-rw-r--r--Source/Core/InputCommon/ControllerInterface/MappingCommon.h13
7 files changed, 91 insertions, 44 deletions
diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingCommon.cpp b/Source/Core/DolphinQt/Config/Mapping/MappingCommon.cpp
index edce169c28..37407f2298 100644
--- a/Source/Core/DolphinQt/Config/Mapping/MappingCommon.cpp
+++ b/Source/Core/DolphinQt/Config/Mapping/MappingCommon.cpp
@@ -19,8 +19,10 @@
namespace MappingCommon
{
constexpr auto INPUT_DETECT_INITIAL_TIME = std::chrono::seconds(3);
-constexpr auto INPUT_DETECT_CONFIRMATION_TIME = std::chrono::milliseconds(0);
+constexpr auto INPUT_DETECT_CONFIRMATION_TIME = std::chrono::milliseconds(750);
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);
class MappingProcessor : public QWidget
{
@@ -50,7 +52,7 @@ public:
button->StartMapping();
std::vector device_strings{default_device.ToString()};
- if (m_parent->IsMappingAllDevices())
+ if (m_parent->IsCreateOtherDeviceMappingsEnabled())
device_strings = g_controller_interface.GetAllDeviceStrings();
m_input_detector = std::make_unique<ciface::Core::InputDetector>();
@@ -63,33 +65,39 @@ public:
if (!m_input_detector)
return;
- m_input_detector->Update(INPUT_DETECT_INITIAL_TIME, INPUT_DETECT_CONFIRMATION_TIME,
+ const auto confirmation_time =
+ INPUT_DETECT_CONFIRMATION_TIME * (m_parent->IsWaitForAlternateMappingsEnabled() ? 1 : 0);
+
+ m_input_detector->Update(INPUT_DETECT_INITIAL_TIME, confirmation_time,
INPUT_DETECT_MAXIMUM_TIME);
if (m_input_detector->IsComplete())
{
- auto detections = m_input_detector->TakeResults();
- ciface::MappingCommon::RemoveSpuriousTriggerCombinations(&detections);
-
// No inputs detected. Cancel this and any other queued mappings.
- if (detections.empty())
- {
+ if (!FinalizeMapping(m_input_detector->TakeResults()))
CancelMapping();
- return;
- }
+ }
+ }
- const auto& default_device = m_parent->GetController()->GetDefaultDevice();
- auto& button = m_clicked_mapping_buttons.front();
- auto* const control_reference = button->GetControlReference();
+ bool FinalizeMapping(ciface::Core::InputDetector::Results detections)
+ {
+ if (!ciface::MappingCommon::ContainsCompleteDetection(detections))
+ return false;
- control_reference->SetExpression(
- BuildExpression(detections, default_device, ciface::MappingCommon::Quote::On));
- m_parent->Save();
+ ciface::MappingCommon::RemoveSpuriousTriggerCombinations(&detections);
- m_parent->GetController()->UpdateSingleControlReference(g_controller_interface,
- control_reference);
- UnQueueInputDetection(button);
- }
+ const auto& default_device = m_parent->GetController()->GetDefaultDevice();
+ auto& button = m_clicked_mapping_buttons.front();
+ auto* const control_reference = button->GetControlReference();
+
+ 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 UpdateInputDetectionStartTimer()
@@ -121,6 +129,15 @@ public:
button->setText(QStringLiteral("[ ... ]"));
m_clicked_mapping_buttons.push_back(button);
+
+ if (m_input_detector)
+ {
+ // Ignore the mouse-click that queued this new detection and finalize the current mapping.
+ auto results = m_input_detector->TakeResults();
+ ciface::MappingCommon::RemoveDetectionsAfterTimePoint(
+ &results, ciface::Core::DeviceContainer::Clock::now() - INPUT_DETECT_ENDING_IGNORE_TIME);
+ FinalizeMapping(std::move(results));
+ }
UpdateInputDetectionStartTimer();
}
diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingWindow.cpp b/Source/Core/DolphinQt/Config/Mapping/MappingWindow.cpp
index 46b4b1f302..665d5e9659 100644
--- a/Source/Core/DolphinQt/Config/Mapping/MappingWindow.cpp
+++ b/Source/Core/DolphinQt/Config/Mapping/MappingWindow.cpp
@@ -111,11 +111,15 @@ void MappingWindow::CreateDevicesLayout()
const auto refresh_action = new QAction(tr("Refresh"), options);
connect(refresh_action, &QAction::triggered, this, &MappingWindow::RefreshDevices);
- m_all_devices_action = new QAction(tr("Create mappings for other devices"), options);
- m_all_devices_action->setCheckable(true);
+ m_other_device_mappings = new QAction(tr("Create Mappings for Other Devices"), options);
+ m_other_device_mappings->setCheckable(true);
+
+ m_wait_for_alternate_mappings = new QAction(tr("Wait for Alternate Input Mappings"), options);
+ m_wait_for_alternate_mappings->setCheckable(true);
options->addAction(refresh_action);
- options->addAction(m_all_devices_action);
+ options->addAction(m_other_device_mappings);
+ options->addAction(m_wait_for_alternate_mappings);
options->setDefaultAction(refresh_action);
m_devices_combo->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
@@ -354,9 +358,14 @@ void MappingWindow::OnSelectDevice(int)
m_controller->UpdateReferences(g_controller_interface);
}
-bool MappingWindow::IsMappingAllDevices() const
+bool MappingWindow::IsCreateOtherDeviceMappingsEnabled() const
+{
+ return m_other_device_mappings->isChecked();
+}
+
+bool MappingWindow::IsWaitForAlternateMappingsEnabled() const
{
- return m_all_devices_action->isChecked();
+ return m_wait_for_alternate_mappings->isChecked();
}
void MappingWindow::RefreshDevices()
diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingWindow.h b/Source/Core/DolphinQt/Config/Mapping/MappingWindow.h
index e51df977f3..10bf590f35 100644
--- a/Source/Core/DolphinQt/Config/Mapping/MappingWindow.h
+++ b/Source/Core/DolphinQt/Config/Mapping/MappingWindow.h
@@ -51,7 +51,8 @@ public:
int GetPort() const;
ControllerEmu::EmulatedController* GetController() const;
- bool IsMappingAllDevices() const;
+ bool IsCreateOtherDeviceMappingsEnabled() const;
+ bool IsWaitForAlternateMappingsEnabled() const;
void ShowExtensionMotionTabs(bool show);
void ActivateExtensionTab();
@@ -103,7 +104,8 @@ private:
QGroupBox* m_devices_box;
QHBoxLayout* m_devices_layout;
QComboBox* m_devices_combo;
- QAction* m_all_devices_action;
+ QAction* m_other_device_mappings;
+ QAction* m_wait_for_alternate_mappings;
// Profiles
QGroupBox* m_profiles_box;
diff --git a/Source/Core/InputCommon/ControllerInterface/CoreDevice.cpp b/Source/Core/InputCommon/ControllerInterface/CoreDevice.cpp
index b9141658e6..3a29d4c98f 100644
--- a/Source/Core/InputCommon/ControllerInterface/CoreDevice.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/CoreDevice.cpp
@@ -491,7 +491,7 @@ void InputDetector::Update(std::chrono::milliseconds initial_wait,
Detection new_detection;
new_detection.device = device_state.device;
new_detection.input = input_state.input;
- new_detection.press_time = Clock::now();
+ new_detection.press_time = now;
new_detection.smoothness = smoothness;
// We found an input. Add it to our detections.
@@ -516,12 +516,12 @@ bool InputDetector::IsComplete() const
return !m_state;
}
-auto InputDetector::GetResults() const -> const std::vector<Detection>&
+auto InputDetector::GetResults() const -> const Results&
{
return m_detections;
}
-auto InputDetector::TakeResults() -> std::vector<Detection>
+auto InputDetector::TakeResults() -> Results
{
return std::move(m_detections);
}
diff --git a/Source/Core/InputCommon/ControllerInterface/CoreDevice.h b/Source/Core/InputCommon/ControllerInterface/CoreDevice.h
index 0370fce894..92f53df9fa 100644
--- a/Source/Core/InputCommon/ControllerInterface/CoreDevice.h
+++ b/Source/Core/InputCommon/ControllerInterface/CoreDevice.h
@@ -250,6 +250,7 @@ class InputDetector
{
public:
using Detection = DeviceContainer::InputDetection;
+ using Results = std::vector<Detection>;
InputDetector();
~InputDetector();
@@ -259,16 +260,16 @@ public:
std::chrono::milliseconds maximum_wait);
bool IsComplete() const;
- const std::vector<Detection>& GetResults() const;
+ const Results& GetResults() const;
// move-return'd to prevent copying.
- std::vector<Detection> TakeResults();
+ Results TakeResults();
private:
struct Impl;
Clock::time_point m_start_time;
- std::vector<Detection> m_detections;
+ Results m_detections;
std::unique_ptr<Impl> m_state;
};
diff --git a/Source/Core/InputCommon/ControllerInterface/MappingCommon.cpp b/Source/Core/InputCommon/ControllerInterface/MappingCommon.cpp
index cb06a7ed30..3765ef24a6 100644
--- a/Source/Core/InputCommon/ControllerInterface/MappingCommon.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/MappingCommon.cpp
@@ -51,11 +51,10 @@ std::string GetExpressionForControl(const std::string& control_name,
return expr;
}
-std::string
-BuildExpression(const std::vector<ciface::Core::DeviceContainer::InputDetection>& detections,
- const ciface::Core::DeviceQualifier& default_device, Quote quote)
+std::string BuildExpression(const Core::InputDetector::Results& detections,
+ const ciface::Core::DeviceQualifier& default_device, Quote quote)
{
- std::vector<const ciface::Core::DeviceContainer::InputDetection*> pressed_inputs;
+ std::vector<const Core::InputDetector::Detection*> pressed_inputs;
std::vector<std::string> alternations;
@@ -135,8 +134,7 @@ BuildExpression(const std::vector<ciface::Core::DeviceContainer::InputDetection>
return fmt::to_string(fmt::join(alternations, "|"));
}
-void RemoveSpuriousTriggerCombinations(
- std::vector<ciface::Core::DeviceContainer::InputDetection>* detections)
+void RemoveSpuriousTriggerCombinations(Core::InputDetector::Results* detections)
{
const auto is_spurious = [&](const auto& detection) {
return std::ranges::any_of(*detections, [&](const auto& d) {
@@ -149,4 +147,21 @@ void RemoveSpuriousTriggerCombinations(
std::erase_if(*detections, is_spurious);
}
+void RemoveDetectionsAfterTimePoint(Core::InputDetector::Results* results,
+ Core::DeviceContainer::Clock::time_point after)
+{
+ const auto is_after_time = [&](const Core::InputDetector::Detection& detection) {
+ return detection.release_time.value_or(after) >= after;
+ };
+
+ std::erase_if(*results, is_after_time);
+}
+
+bool ContainsCompleteDetection(const Core::InputDetector::Results& results)
+{
+ return std::ranges::any_of(results, [](const Core::InputDetector::Detection& detection) {
+ return detection.release_time.has_value();
+ });
+}
+
} // namespace ciface::MappingCommon
diff --git a/Source/Core/InputCommon/ControllerInterface/MappingCommon.h b/Source/Core/InputCommon/ControllerInterface/MappingCommon.h
index 1822125557..f58813a50c 100644
--- a/Source/Core/InputCommon/ControllerInterface/MappingCommon.h
+++ b/Source/Core/InputCommon/ControllerInterface/MappingCommon.h
@@ -17,13 +17,16 @@ enum class Quote
};
std::string GetExpressionForControl(const std::string& control_name,
- const ciface::Core::DeviceQualifier& control_device,
- const ciface::Core::DeviceQualifier& default_device,
+ const Core::DeviceQualifier& control_device,
+ const Core::DeviceQualifier& default_device,
Quote quote = Quote::On);
-std::string BuildExpression(const std::vector<ciface::Core::DeviceContainer::InputDetection>&,
- const ciface::Core::DeviceQualifier& default_device, Quote quote);
+std::string BuildExpression(const Core::InputDetector::Results&,
+ const Core::DeviceQualifier& default_device, Quote quote);
-void RemoveSpuriousTriggerCombinations(std::vector<ciface::Core::DeviceContainer::InputDetection>*);
+void RemoveSpuriousTriggerCombinations(Core::InputDetector::Results*);
+void RemoveDetectionsAfterTimePoint(Core::InputDetector::Results*,
+ Core::DeviceContainer::Clock::time_point after);
+bool ContainsCompleteDetection(const Core::InputDetector::Results&);
} // namespace ciface::MappingCommon