summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorJordan Woyak <jordan.woyak@gmail.com>2019-10-23 17:20:42 -0500
committerJordan Woyak <jordan.woyak@gmail.com>2020-09-25 20:29:18 -0500
commitb3acc7403f33033bfce6db92ea4b8ec6fc968665 (patch)
tree3b9a068a5d9ccdead090880b4781a674cd4c361b /Source/Core
parente6ba495486b2c7ac337fa4ecd62597a0f9a56e51 (diff)
InputCommon: Support detecting combinations of inputs. (Hotkeys)
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/DolphinQt/Config/Mapping/MappingCommon.cpp24
-rw-r--r--Source/Core/InputCommon/ControllerInterface/Device.cpp33
-rw-r--r--Source/Core/InputCommon/ControllerInterface/Device.h2
3 files changed, 44 insertions, 15 deletions
diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingCommon.cpp b/Source/Core/DolphinQt/Config/Mapping/MappingCommon.cpp
index bbd15ad831..7963fc22d1 100644
--- a/Source/Core/DolphinQt/Config/Mapping/MappingCommon.cpp
+++ b/Source/Core/DolphinQt/Config/Mapping/MappingCommon.cpp
@@ -68,7 +68,7 @@ QString DetectExpression(QPushButton* button, ciface::Core::DeviceContainer& dev
// Avoid that the button press itself is registered as an event
Common::SleepCurrentThread(50);
- const auto [device, input] = device_container.DetectInput(INPUT_DETECT_TIME, device_strings);
+ const auto detections = device_container.DetectInput(INPUT_DETECT_TIME, device_strings);
const auto timer = new QTimer(button);
@@ -83,14 +83,24 @@ QString DetectExpression(QPushButton* button, ciface::Core::DeviceContainer& dev
button->setText(old_text);
- if (!input)
- return {};
+ QString full_expression;
- ciface::Core::DeviceQualifier device_qualifier;
- device_qualifier.FromDevice(device.get());
+ for (auto [device, input] : detections)
+ {
+ ciface::Core::DeviceQualifier device_qualifier;
+ device_qualifier.FromDevice(device.get());
+
+ if (!full_expression.isEmpty())
+ full_expression += QChar::fromLatin1('+');
+
+ full_expression += MappingCommon::GetExpressionForControl(
+ QString::fromStdString(input->GetName()), device_qualifier, default_device, quote);
+ }
+
+ if (detections.size() > 1)
+ return QStringLiteral("@(%1)").arg(std::move(full_expression));
- return MappingCommon::GetExpressionForControl(QString::fromStdString(input->GetName()),
- device_qualifier, default_device, quote);
+ return full_expression;
}
void TestOutput(QPushButton* button, OutputReference* reference)
diff --git a/Source/Core/InputCommon/ControllerInterface/Device.cpp b/Source/Core/InputCommon/ControllerInterface/Device.cpp
index ebed1ad421..cd056af0d8 100644
--- a/Source/Core/InputCommon/ControllerInterface/Device.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/Device.cpp
@@ -18,6 +18,7 @@
namespace ciface::Core
{
// Compared to an input's current state (ideally 1.0) minus abs(initial_state) (ideally 0.0).
+// Note: Detect() logic assumes this is greater than 0.5.
constexpr ControlState INPUT_DETECT_THRESHOLD = 0.55;
Device::~Device()
@@ -253,13 +254,14 @@ bool DeviceContainer::HasConnectedDevice(const DeviceQualifier& qualifier) const
// Inputs are considered if they are first seen in a neutral state.
// This is useful for crazy flightsticks that have certain buttons that are always held down
// and also properly handles detection when using "FullAnalogSurface" inputs.
-// Upon input, return the detected Device and Input, else return nullptrs
-std::pair<std::shared_ptr<Device>, Device::Input*>
+// Detects multiple inputs if they are pressed before others are released.
+// Upon input, return the detected Device and Input pairs, else return an empty container
+std::vector<std::pair<std::shared_ptr<Device>, Device::Input*>>
DeviceContainer::DetectInput(u32 wait_ms, const std::vector<std::string>& device_strings) const
{
struct InputState
{
- ciface::Core::Device::Input& input;
+ ciface::Core::Device::Input* input;
ControlState initial_state;
};
@@ -291,7 +293,7 @@ DeviceContainer::DetectInput(u32 wait_ms, const std::vector<std::string>& device
// Undesirable axes will have negative values here when trying to map a
// "FullAnalogSurface".
- input_states.push_back({*input, input->GetState()});
+ input_states.push_back({input, input->GetState()});
}
if (!input_states.empty())
@@ -301,6 +303,8 @@ DeviceContainer::DetectInput(u32 wait_ms, const std::vector<std::string>& device
if (device_states.empty())
return {};
+ std::vector<std::pair<std::shared_ptr<Device>, Device::Input*>> detections;
+
u32 time = 0;
while (time < wait_ms)
{
@@ -309,16 +313,31 @@ DeviceContainer::DetectInput(u32 wait_ms, const std::vector<std::string>& device
for (auto& device_state : device_states)
{
- for (auto& input_state : device_state.input_states)
+ for (std::size_t i = 0; i != device_state.input_states.size(); ++i)
{
+ auto& input_state = device_state.input_states[i];
+
// We want an input that was initially 0.0 and currently 1.0.
const auto detection_score =
- (input_state.input.GetState() - std::abs(input_state.initial_state));
+ (input_state.input->GetState() - std::abs(input_state.initial_state));
if (detection_score > INPUT_DETECT_THRESHOLD)
- return {device_state.device, &input_state.input};
+ {
+ // We found an input. Add it to our detections.
+ detections.emplace_back(device_state.device, input_state.input);
+
+ // And remove from input_states to prevent more detections.
+ device_state.input_states.erase(device_state.input_states.begin() + i--);
+ }
}
}
+
+ for (auto& detection : detections)
+ {
+ // If one of our detected inputs is released we are done.
+ if (detection.second->GetState() < (1 - INPUT_DETECT_THRESHOLD))
+ return detections;
+ }
}
// No input was detected. :'(
diff --git a/Source/Core/InputCommon/ControllerInterface/Device.h b/Source/Core/InputCommon/ControllerInterface/Device.h
index d923d97076..43e61e53fd 100644
--- a/Source/Core/InputCommon/ControllerInterface/Device.h
+++ b/Source/Core/InputCommon/ControllerInterface/Device.h
@@ -194,7 +194,7 @@ public:
bool HasConnectedDevice(const DeviceQualifier& qualifier) const;
- std::pair<std::shared_ptr<Device>, Device::Input*>
+ std::vector<std::pair<std::shared_ptr<Device>, Device::Input*>>
DetectInput(u32 wait_ms, const std::vector<std::string>& device_strings) const;
protected: