summaryrefslogtreecommitdiff
path: root/Source/Core/InputCommon/ControllerInterface
diff options
context:
space:
mode:
authorJMC47 <JMC4789@gmail.com>2019-03-13 19:00:24 -0400
committerGitHub <noreply@github.com>2019-03-13 19:00:24 -0400
commit011ecd92e8e2b0b78471cc7ad394b6ed1f7a451e (patch)
treeee12d70ff3889b093c2696715eace0952aee8ccb /Source/Core/InputCommon/ControllerInterface
parentbc9e9caf19749778d01b9721a1ff92acccf70fac (diff)
parentc389d68186ea7fa95d763d7bb55bc09e5a45c4cd (diff)
Merge pull request #7829 from jordan-woyak/detect-input-improve
ControllerInterface/DolphinQt: Improve input detection.
Diffstat (limited to 'Source/Core/InputCommon/ControllerInterface')
-rw-r--r--Source/Core/InputCommon/ControllerInterface/DInput/DInputJoystick.cpp2
-rw-r--r--Source/Core/InputCommon/ControllerInterface/Device.cpp95
-rw-r--r--Source/Core/InputCommon/ControllerInterface/Device.h24
-rw-r--r--Source/Core/InputCommon/ControllerInterface/XInput/XInput.cpp6
-rw-r--r--Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp2
5 files changed, 112 insertions, 17 deletions
diff --git a/Source/Core/InputCommon/ControllerInterface/DInput/DInputJoystick.cpp b/Source/Core/InputCommon/ControllerInterface/DInput/DInputJoystick.cpp
index 21e39bc416..400f9b078c 100644
--- a/Source/Core/InputCommon/ControllerInterface/DInput/DInputJoystick.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/DInput/DInputJoystick.cpp
@@ -259,7 +259,7 @@ std::string Joystick::Hat::GetName() const
ControlState Joystick::Axis::GetState() const
{
- return std::max(0.0, ControlState(m_axis - m_base) / m_range);
+ return ControlState(m_axis - m_base) / m_range;
}
ControlState Joystick::Button::GetState() const
diff --git a/Source/Core/InputCommon/ControllerInterface/Device.cpp b/Source/Core/InputCommon/ControllerInterface/Device.cpp
index b8d73d9ab8..14f5cb23d9 100644
--- a/Source/Core/InputCommon/ControllerInterface/Device.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/Device.cpp
@@ -4,22 +4,22 @@
#include "InputCommon/ControllerInterface/Device.h"
+#include <cmath>
#include <memory>
#include <sstream>
#include <string>
#include <tuple>
#include "Common/StringUtil.h"
+#include "Common/Thread.h"
namespace ciface
{
namespace Core
{
-//
-// Device :: ~Device
-//
-// Destructor, delete all inputs/outputs on device destruction
-//
+// Compared to an input's current state (ideally 1.0) minus abs(initial_state) (ideally 0.0).
+constexpr ControlState INPUT_DETECT_THRESHOLD = 0.55;
+
Device::~Device()
{
// delete inputs
@@ -68,6 +68,11 @@ Device::Output* Device::FindOutput(const std::string& name) const
return nullptr;
}
+ControlState Device::FullAnalogSurface::GetState() const
+{
+ return (1 + std::max(0.0, m_high.GetState()) - std::max(0.0, m_low.GetState())) / 2;
+}
+
//
// DeviceQualifier :: ToString
//
@@ -214,5 +219,83 @@ bool DeviceContainer::HasConnectedDevice(const DeviceQualifier& qualifier) const
const auto device = FindDevice(qualifier);
return device != nullptr && device->IsValid();
}
+
+// Wait for input on a particular device.
+// 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*>
+DeviceContainer::DetectInput(u32 wait_ms, std::vector<std::string> device_strings)
+{
+ struct InputState
+ {
+ ciface::Core::Device::Input& input;
+ ControlState initial_state;
+ };
+
+ struct DeviceState
+ {
+ std::shared_ptr<Device> device;
+
+ std::vector<InputState> input_states;
+ };
+
+ // Acquire devices and initial input states.
+ std::vector<DeviceState> device_states;
+ for (auto& device_string : device_strings)
+ {
+ DeviceQualifier dq;
+ dq.FromString(device_string);
+ auto device = FindDevice(dq);
+
+ if (!device)
+ continue;
+
+ std::vector<InputState> input_states;
+
+ for (auto* input : device->Inputs())
+ {
+ // Don't detect things like absolute cursor position.
+ if (!input->IsDetectable())
+ continue;
+
+ // Undesirable axes will have negative values here when trying to map a
+ // "FullAnalogSurface".
+ input_states.push_back({*input, input->GetState()});
+ }
+
+ if (!input_states.empty())
+ device_states.emplace_back(DeviceState{std::move(device), std::move(input_states)});
+ }
+
+ if (device_states.empty())
+ return {};
+
+ u32 time = 0;
+ while (time < wait_ms)
+ {
+ Common::SleepCurrentThread(10);
+ time += 10;
+
+ for (auto& device_state : device_states)
+ {
+ device_state.device->UpdateInput();
+ for (auto& input_state : device_state.input_states)
+ {
+ // 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));
+
+ if (detection_score > INPUT_DETECT_THRESHOLD)
+ return {device_state.device, &input_state.input};
+ }
+ }
+ }
+
+ // No input was detected. :'(
+ return {};
}
-}
+
+} // namespace Core
+} // namespace ciface
diff --git a/Source/Core/InputCommon/ControllerInterface/Device.h b/Source/Core/InputCommon/ControllerInterface/Device.h
index 7b36da934a..7d7623ba03 100644
--- a/Source/Core/InputCommon/ControllerInterface/Device.h
+++ b/Source/Core/InputCommon/ControllerInterface/Device.h
@@ -55,9 +55,22 @@ public:
class Input : public Control
{
public:
- // things like absolute axes/ absolute mouse position will override this
+ // Things like absolute axes/ absolute mouse position should override this to prevent
+ // undesirable behavior in our mapping logic.
virtual bool IsDetectable() { return true; }
+
+ // Implementations should return a value from 0.0 to 1.0 across their normal range.
+ // One input should be provided for each "direction". (e.g. 2 for each axis)
+ // If possible, negative values may be returned in situations where an opposing input is
+ // activated. (e.g. When an underlying axis, X, is currently negative, "Axis X-", will return a
+ // positive value and "Axis X+" may return a negative value.)
+ // Doing so is solely to allow our input detection logic to better detect false positives.
+ // This is necessary when making use of "FullAnalogSurface" as multiple inputs will be seen
+ // increasing from 0.0 to 1.0 as a user tries to map just one. The negative values provide a
+ // view of the underlying axis. (Negative values are clamped off before they reach
+ // expression-parser or controller-emu)
virtual ControlState GetState() const = 0;
+
Input* ToInput() override { return this; }
};
@@ -96,11 +109,7 @@ protected:
{
public:
FullAnalogSurface(Input* low, Input* high) : m_low(*low), m_high(*high) {}
- ControlState GetState() const override
- {
- return (1 + m_high.GetState() - m_low.GetState()) / 2;
- }
-
+ ControlState GetState() const override;
std::string GetName() const override { return m_low.GetName() + *m_high.GetName().rbegin(); }
private:
@@ -163,6 +172,9 @@ public:
bool HasConnectedDevice(const DeviceQualifier& qualifier) const;
+ std::pair<std::shared_ptr<Device>, Device::Input*>
+ DetectInput(u32 wait_ms, std::vector<std::string> device_strings);
+
protected:
mutable std::mutex m_devices_mutex;
std::vector<std::shared_ptr<Device>> m_devices;
diff --git a/Source/Core/InputCommon/ControllerInterface/XInput/XInput.cpp b/Source/Core/InputCommon/ControllerInterface/XInput/XInput.cpp
index 0b5cbad358..8c518335a0 100644
--- a/Source/Core/InputCommon/ControllerInterface/XInput/XInput.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/XInput/XInput.cpp
@@ -228,7 +228,7 @@ ControlState Device::Trigger::GetState() const
ControlState Device::Axis::GetState() const
{
- return std::max(0.0, ControlState(m_axis) / m_range);
+ return ControlState(m_axis) / m_range;
}
void Device::Motor::SetState(ControlState state)
@@ -236,5 +236,5 @@ void Device::Motor::SetState(ControlState state)
m_motor = (WORD)(state * m_range);
m_parent->UpdateMotors();
}
-}
-}
+} // namespace XInput
+} // namespace ciface
diff --git a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp
index 1cec2333ef..d1fa694fae 100644
--- a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp
@@ -343,7 +343,7 @@ ControlState evdevDevice::Axis::GetState() const
int value = 0;
libevdev_fetch_event_value(m_dev, EV_ABS, m_code, &value);
- return std::max(0.0, ControlState(value - m_base) / m_range);
+ return ControlState(value - m_base) / m_range;
}
evdevDevice::Effect::Effect(int fd) : m_fd(fd)