diff options
Diffstat (limited to 'Source/Core/DolphinQt/Config/Mapping/MappingCommon.cpp')
| -rw-r--r-- | Source/Core/DolphinQt/Config/Mapping/MappingCommon.cpp | 192 |
1 files changed, 127 insertions, 65 deletions
diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingCommon.cpp b/Source/Core/DolphinQt/Config/Mapping/MappingCommon.cpp index 0fdcb376af..edce169c28 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingCommon.cpp +++ b/Source/Core/DolphinQt/Config/Mapping/MappingCommon.cpp @@ -3,85 +3,147 @@ #include "DolphinQt/Config/Mapping/MappingCommon.h" -#include <chrono> +#include <deque> +#include <memory> -#include <QApplication> -#include <QPushButton> -#include <QRegularExpression> -#include <QString> #include <QTimer> -#include "DolphinQt/QtUtils/BlockUserInputFilter.h" +#include "DolphinQt/Config/Mapping/MappingButton.h" +#include "DolphinQt/Config/Mapping/MappingWindow.h" + #include "InputCommon/ControlReference/ControlReference.h" +#include "InputCommon/ControllerEmu/ControllerEmu.h" +#include "InputCommon/ControllerInterface/ControllerInterface.h" #include "InputCommon/ControllerInterface/MappingCommon.h" -#include "Common/Thread.h" - 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_MAXIMUM_TIME = std::chrono::seconds(5); -constexpr auto OUTPUT_TEST_TIME = std::chrono::seconds(2); - -QString DetectExpression(QPushButton* button, ciface::Core::DeviceContainer& device_container, - const std::vector<std::string>& device_strings, - const ciface::Core::DeviceQualifier& default_device, - ciface::MappingCommon::Quote quote) +class MappingProcessor : public QWidget { - const auto filter = new BlockUserInputFilter(button); - - button->installEventFilter(filter); - button->grabKeyboard(); - button->grabMouse(); - - const auto old_text = button->text(); - button->setText(QStringLiteral("...")); - - // The button text won't be updated if we don't process events here - QApplication::processEvents(); - - // Avoid that the button press itself is registered as an event - Common::SleepCurrentThread(50); - - auto detections = - device_container.DetectInput(device_strings, INPUT_DETECT_INITIAL_TIME, - INPUT_DETECT_CONFIRMATION_TIME, INPUT_DETECT_MAXIMUM_TIME); - - ciface::MappingCommon::RemoveSpuriousTriggerCombinations(&detections); - - const auto timer = new QTimer(button); - - timer->setSingleShot(true); - - button->connect(timer, &QTimer::timeout, [button, filter] { - button->releaseMouse(); - button->releaseKeyboard(); - button->removeEventFilter(filter); - }); - - // Prevent mappings of "space", "return", or mouse clicks from re-activating detection. - timer->start(500); - - button->setText(old_text); - - return QString::fromStdString(BuildExpression(detections, default_device, quote)); -} - -void TestOutput(QPushButton* button, OutputReference* reference) +public: + MappingProcessor(MappingWindow* parent) : QWidget{parent}, m_parent{parent} + { + using MW = MappingWindow; + using MP = MappingProcessor; + + connect(parent, &MW::Update, this, &MP::ProcessMappingButtons); + connect(parent, &MW::ConfigChanged, this, &MP::CancelMapping); + + connect(parent, &MW::UnQueueInputDetection, this, &MP::UnQueueInputDetection); + connect(parent, &MW::QueueInputDetection, this, &MP::QueueInputDetection); + connect(parent, &MW::CancelMapping, this, &MP::CancelMapping); + + m_input_detection_start_timer = new QTimer(this); + m_input_detection_start_timer->setSingleShot(true); + connect(m_input_detection_start_timer, &QTimer::timeout, this, &MP::StartInputDetection); + } + + void StartInputDetection() + { + const auto& default_device = m_parent->GetController()->GetDefaultDevice(); + auto& button = m_clicked_mapping_buttons.front(); + + button->StartMapping(); + + std::vector device_strings{default_device.ToString()}; + if (m_parent->IsMappingAllDevices()) + device_strings = g_controller_interface.GetAllDeviceStrings(); + + m_input_detector = std::make_unique<ciface::Core::InputDetector>(); + const auto lock = m_parent->GetController()->GetStateLock(); + m_input_detector->Start(g_controller_interface, device_strings); + } + + void ProcessMappingButtons() + { + if (!m_input_detector) + return; + + m_input_detector->Update(INPUT_DETECT_INITIAL_TIME, INPUT_DETECT_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()) + { + CancelMapping(); + return; + } + + 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); + } + } + + void UpdateInputDetectionStartTimer() + { + m_input_detector.reset(); + + if (m_clicked_mapping_buttons.empty()) + m_input_detection_start_timer->stop(); + else + m_input_detection_start_timer->start(INPUT_DETECT_INITIAL_DELAY); + } + + void UnQueueInputDetection(MappingButton* button) + { + std::erase(m_clicked_mapping_buttons, button); + button->ConfigChanged(); + UpdateInputDetectionStartTimer(); + } + + void QueueInputDetection(MappingButton* button) + { + // UnQueue if already queued. + if (std::erase(m_clicked_mapping_buttons, button)) + { + button->ConfigChanged(); + UpdateInputDetectionStartTimer(); + return; + } + + button->setText(QStringLiteral("[ ... ]")); + m_clicked_mapping_buttons.push_back(button); + UpdateInputDetectionStartTimer(); + } + + void CancelMapping() + { + // Signal buttons to take on their proper input expression text. + for (auto* button : m_clicked_mapping_buttons) + button->ConfigChanged(); + + m_clicked_mapping_buttons = {}; + UpdateInputDetectionStartTimer(); + } + +private: + std::deque<MappingButton*> m_clicked_mapping_buttons; + std::unique_ptr<ciface::Core::InputDetector> m_input_detector; + QTimer* m_input_detection_start_timer; + MappingWindow* const m_parent; +}; + +void CreateMappingProcessor(MappingWindow* window) { - const auto old_text = button->text(); - button->setText(QStringLiteral("...")); - - // The button text won't be updated if we don't process events here - QApplication::processEvents(); - - reference->State(1.0); - std::this_thread::sleep_for(OUTPUT_TEST_TIME); - reference->State(0.0); - - button->setText(old_text); + new MappingProcessor{window}; } } // namespace MappingCommon |
