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()