From 99ec667b208500f1d59d7a4650e414d28f26110b Mon Sep 17 00:00:00 2001 From: Silent Date: Sat, 14 Nov 2020 00:32:35 +0100 Subject: [PATCH] Factorize input hooks into reusable monitor classes Those monitors will need some context so this will be useful in the nearby future. --- src/duckstation-qt/CMakeLists.txt | 2 + src/duckstation-qt/duckstation-qt.vcxproj | 2 + .../duckstation-qt.vcxproj.filters | 2 + src/duckstation-qt/inputbindingdialog.cpp | 45 +------------- src/duckstation-qt/inputbindingmonitor.cpp | 60 +++++++++++++++++++ src/duckstation-qt/inputbindingmonitor.h | 45 ++++++++++++++ src/duckstation-qt/inputbindingwidgets.cpp | 55 ++--------------- 7 files changed, 118 insertions(+), 93 deletions(-) create mode 100644 src/duckstation-qt/inputbindingmonitor.cpp create mode 100644 src/duckstation-qt/inputbindingmonitor.h diff --git a/src/duckstation-qt/CMakeLists.txt b/src/duckstation-qt/CMakeLists.txt index b83be92fe..a8a5aeff3 100644 --- a/src/duckstation-qt/CMakeLists.txt +++ b/src/duckstation-qt/CMakeLists.txt @@ -55,6 +55,8 @@ set(SRCS inputbindingdialog.cpp inputbindingdialog.h inputbindingdialog.ui + inputbindingmonitor.cpp + inputbindingmonitor.h inputbindingwidgets.cpp inputbindingwidgets.h main.cpp diff --git a/src/duckstation-qt/duckstation-qt.vcxproj b/src/duckstation-qt/duckstation-qt.vcxproj index 9ef490d3c..3d7fe4e40 100644 --- a/src/duckstation-qt/duckstation-qt.vcxproj +++ b/src/duckstation-qt/duckstation-qt.vcxproj @@ -66,6 +66,7 @@ + @@ -105,6 +106,7 @@ + diff --git a/src/duckstation-qt/duckstation-qt.vcxproj.filters b/src/duckstation-qt/duckstation-qt.vcxproj.filters index 3dd288d97..82bc61a72 100644 --- a/src/duckstation-qt/duckstation-qt.vcxproj.filters +++ b/src/duckstation-qt/duckstation-qt.vcxproj.filters @@ -60,11 +60,13 @@ + + diff --git a/src/duckstation-qt/inputbindingdialog.cpp b/src/duckstation-qt/inputbindingdialog.cpp index 0edded305..294a0af19 100644 --- a/src/duckstation-qt/inputbindingdialog.cpp +++ b/src/duckstation-qt/inputbindingdialog.cpp @@ -3,6 +3,7 @@ #include "common/string_util.h" #include "core/settings.h" #include "frontend-common/controller_interface.h" +#include "inputbindingmonitor.h" #include "qthostinterface.h" #include "qtutils.h" #include @@ -210,27 +211,7 @@ void InputButtonBindingDialog::hookControllerInput() if (!controller_interface) return; - controller_interface->SetHook([this](const ControllerInterface::Hook& ei) { - if (ei.type == ControllerInterface::Hook::Type::Axis) - { - // wait until it's at least half pushed so we don't get confused between axises with small movement - if (std::abs(ei.value) < 0.5f) - return ControllerInterface::Hook::CallbackResult::ContinueMonitoring; - - // TODO: this probably should consider the "last value" - QMetaObject::invokeMethod(this, "bindToControllerAxis", Q_ARG(int, ei.controller_index), - Q_ARG(int, ei.button_or_axis_number), Q_ARG(std::optional, ei.value > 0)); - return ControllerInterface::Hook::CallbackResult::StopMonitoring; - } - else if (ei.type == ControllerInterface::Hook::Type::Button && ei.value > 0.0f) - { - QMetaObject::invokeMethod(this, "bindToControllerButton", Q_ARG(int, ei.controller_index), - Q_ARG(int, ei.button_or_axis_number)); - return ControllerInterface::Hook::CallbackResult::StopMonitoring; - } - - return ControllerInterface::Hook::CallbackResult::ContinueMonitoring; - }); + controller_interface->SetHook(InputButtonBindingMonitor(this)); } void InputButtonBindingDialog::unhookControllerInput() @@ -274,27 +255,7 @@ void InputAxisBindingDialog::hookControllerInput() if (!controller_interface) return; - controller_interface->SetHook([this](const ControllerInterface::Hook& ei) { - if (ei.type == ControllerInterface::Hook::Type::Axis) - { - // wait until it's at least half pushed so we don't get confused between axises with small movement - if (std::abs(ei.value) < 0.5f) - return ControllerInterface::Hook::CallbackResult::ContinueMonitoring; - - QMetaObject::invokeMethod(this, "bindToControllerAxis", Q_ARG(int, ei.controller_index), - Q_ARG(int, ei.button_or_axis_number), Q_ARG(std::optional, std::nullopt)); - return ControllerInterface::Hook::CallbackResult::StopMonitoring; - } - else if (ei.type == ControllerInterface::Hook::Type::Button && m_axis_type == Controller::AxisType::Half && - ei.value > 0.0f) - { - QMetaObject::invokeMethod(this, "bindToControllerButton", Q_ARG(int, ei.controller_index), - Q_ARG(int, ei.button_or_axis_number)); - return ControllerInterface::Hook::CallbackResult::StopMonitoring; - } - - return ControllerInterface::Hook::CallbackResult::ContinueMonitoring; - }); + controller_interface->SetHook(InputAxisBindingMonitor(this, m_axis_type)); } void InputAxisBindingDialog::unhookControllerInput() diff --git a/src/duckstation-qt/inputbindingmonitor.cpp b/src/duckstation-qt/inputbindingmonitor.cpp new file mode 100644 index 000000000..906ed236d --- /dev/null +++ b/src/duckstation-qt/inputbindingmonitor.cpp @@ -0,0 +1,60 @@ +#include "inputbindingmonitor.h" + +ControllerInterface::Hook::CallbackResult +InputButtonBindingMonitor::operator()(const ControllerInterface::Hook& ei) const +{ + if (ei.type == ControllerInterface::Hook::Type::Axis) + { + // wait until it's at least half pushed so we don't get confused between axises with small movement + if (std::abs(ei.value) < 0.5f) + return ControllerInterface::Hook::CallbackResult::ContinueMonitoring; + + // TODO: this probably should consider the "last value" + QMetaObject::invokeMethod(m_parent, "bindToControllerAxis", Q_ARG(int, ei.controller_index), + Q_ARG(int, ei.button_or_axis_number), Q_ARG(std::optional, ei.value > 0)); + return ControllerInterface::Hook::CallbackResult::StopMonitoring; + } + else if (ei.type == ControllerInterface::Hook::Type::Button && ei.value > 0.0f) + { + QMetaObject::invokeMethod(m_parent, "bindToControllerButton", Q_ARG(int, ei.controller_index), + Q_ARG(int, ei.button_or_axis_number)); + return ControllerInterface::Hook::CallbackResult::StopMonitoring; + } + + return ControllerInterface::Hook::CallbackResult::ContinueMonitoring; +} + +ControllerInterface::Hook::CallbackResult InputAxisBindingMonitor::operator()(const ControllerInterface::Hook& ei) const +{ + if (ei.type == ControllerInterface::Hook::Type::Axis) + { + // wait until it's at least half pushed so we don't get confused between axises with small movement + if (std::abs(ei.value) < 0.5f) + return ControllerInterface::Hook::CallbackResult::ContinueMonitoring; + + QMetaObject::invokeMethod(m_parent, "bindToControllerAxis", Q_ARG(int, ei.controller_index), + Q_ARG(int, ei.button_or_axis_number), Q_ARG(std::optional, std::nullopt)); + return ControllerInterface::Hook::CallbackResult::StopMonitoring; + } + else if (ei.type == ControllerInterface::Hook::Type::Button && m_axis_type == Controller::AxisType::Half && + ei.value > 0.0f) + { + QMetaObject::invokeMethod(m_parent, "bindToControllerButton", Q_ARG(int, ei.controller_index), + Q_ARG(int, ei.button_or_axis_number)); + return ControllerInterface::Hook::CallbackResult::StopMonitoring; + } + + return ControllerInterface::Hook::CallbackResult::ContinueMonitoring; +} + +ControllerInterface::Hook::CallbackResult +InputRumbleBindingMonitor::operator()(const ControllerInterface::Hook& ei) const +{ + if (ei.type == ControllerInterface::Hook::Type::Button && ei.value > 0.0f) + { + QMetaObject::invokeMethod(m_parent, "bindToControllerRumble", Q_ARG(int, ei.controller_index)); + return ControllerInterface::Hook::CallbackResult::StopMonitoring; + } + + return ControllerInterface::Hook::CallbackResult::ContinueMonitoring; +} \ No newline at end of file diff --git a/src/duckstation-qt/inputbindingmonitor.h b/src/duckstation-qt/inputbindingmonitor.h new file mode 100644 index 000000000..d22935535 --- /dev/null +++ b/src/duckstation-qt/inputbindingmonitor.h @@ -0,0 +1,45 @@ +#pragma once + +#include "frontend-common/controller_interface.h" +#include + +// NOTE: Those Monitor classes must be copyable to meet the requirements of std::function, but at the same time we want +// copies to be opaque to the caling code and share context. Therefore, all mutable context of the monitor (if required) +// must be enclosed in a std::shared_ptr. m_parent/m_axis_type don't mutate so they don't need to be stored as such. + +class InputButtonBindingMonitor +{ +public: + explicit InputButtonBindingMonitor(QObject* parent) : m_parent(parent) {} + + ControllerInterface::Hook::CallbackResult operator()(const ControllerInterface::Hook& ei) const; + +private: + QObject* m_parent; +}; + +class InputAxisBindingMonitor +{ +public: + explicit InputAxisBindingMonitor(QObject* parent, Controller::AxisType axis_type) + : m_parent(parent), m_axis_type(axis_type) + { + } + + ControllerInterface::Hook::CallbackResult operator()(const ControllerInterface::Hook& ei) const; + +private: + QObject* m_parent; + Controller::AxisType m_axis_type; +}; + +class InputRumbleBindingMonitor +{ +public: + explicit InputRumbleBindingMonitor(QObject* parent) : m_parent(parent) {} + + ControllerInterface::Hook::CallbackResult operator()(const ControllerInterface::Hook& ei) const; + +private: + QObject* m_parent; +}; \ No newline at end of file diff --git a/src/duckstation-qt/inputbindingwidgets.cpp b/src/duckstation-qt/inputbindingwidgets.cpp index 9d55dc16e..4c9050962 100644 --- a/src/duckstation-qt/inputbindingwidgets.cpp +++ b/src/duckstation-qt/inputbindingwidgets.cpp @@ -4,6 +4,7 @@ #include "core/settings.h" #include "frontend-common/controller_interface.h" #include "inputbindingdialog.h" +#include "inputbindingmonitor.h" #include "qthostinterface.h" #include "qtutils.h" #include @@ -236,27 +237,7 @@ void InputButtonBindingWidget::hookControllerInput() if (!controller_interface) return; - controller_interface->SetHook([this](const ControllerInterface::Hook& ei) { - if (ei.type == ControllerInterface::Hook::Type::Axis) - { - // wait until it's at least half pushed so we don't get confused between axises with small movement - if (std::abs(ei.value) < 0.5f) - return ControllerInterface::Hook::CallbackResult::ContinueMonitoring; - - // TODO: this probably should consider the "last value" - QMetaObject::invokeMethod(this, "bindToControllerAxis", Q_ARG(int, ei.controller_index), - Q_ARG(int, ei.button_or_axis_number), Q_ARG(std::optional, ei.value > 0)); - return ControllerInterface::Hook::CallbackResult::StopMonitoring; - } - else if (ei.type == ControllerInterface::Hook::Type::Button && ei.value > 0.0f) - { - QMetaObject::invokeMethod(this, "bindToControllerButton", Q_ARG(int, ei.controller_index), - Q_ARG(int, ei.button_or_axis_number)); - return ControllerInterface::Hook::CallbackResult::StopMonitoring; - } - - return ControllerInterface::Hook::CallbackResult::ContinueMonitoring; - }); + controller_interface->SetHook(InputButtonBindingMonitor(this)); } void InputButtonBindingWidget::unhookControllerInput() @@ -306,27 +287,7 @@ void InputAxisBindingWidget::hookControllerInput() if (!controller_interface) return; - controller_interface->SetHook([this](const ControllerInterface::Hook& ei) { - if (ei.type == ControllerInterface::Hook::Type::Axis) - { - // wait until it's at least half pushed so we don't get confused between axises with small movement - if (std::abs(ei.value) < 0.5f) - return ControllerInterface::Hook::CallbackResult::ContinueMonitoring; - - QMetaObject::invokeMethod(this, "bindToControllerAxis", Q_ARG(int, ei.controller_index), - Q_ARG(int, ei.button_or_axis_number), Q_ARG(std::optional, std::nullopt)); - return ControllerInterface::Hook::CallbackResult::StopMonitoring; - } - else if (ei.type == ControllerInterface::Hook::Type::Button && m_axis_type == Controller::AxisType::Half && - ei.value > 0.0f) - { - QMetaObject::invokeMethod(this, "bindToControllerButton", Q_ARG(int, ei.controller_index), - Q_ARG(int, ei.button_or_axis_number)); - return ControllerInterface::Hook::CallbackResult::StopMonitoring; - } - - return ControllerInterface::Hook::CallbackResult::ContinueMonitoring; - }); + controller_interface->SetHook(InputAxisBindingMonitor(this, m_axis_type)); } void InputAxisBindingWidget::unhookControllerInput() @@ -391,15 +352,7 @@ void InputRumbleBindingWidget::hookControllerInput() if (!controller_interface) return; - controller_interface->SetHook([this](const ControllerInterface::Hook& ei) { - if (ei.type == ControllerInterface::Hook::Type::Button && ei.value > 0.0f) - { - QMetaObject::invokeMethod(this, "bindToControllerRumble", Q_ARG(int, ei.controller_index)); - return ControllerInterface::Hook::CallbackResult::StopMonitoring; - } - - return ControllerInterface::Hook::CallbackResult::ContinueMonitoring; - }); + controller_interface->SetHook(InputRumbleBindingMonitor(this)); } void InputRumbleBindingWidget::unhookControllerInput()