mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-14 21:37:52 -07:00
InputCommon: Support detecting combinations of inputs. (Hotkeys)
This commit is contained in:
parent
e6ba495486
commit
b3acc7403f
@ -68,7 +68,7 @@ QString DetectExpression(QPushButton* button, ciface::Core::DeviceContainer& dev
|
|||||||
// Avoid that the button press itself is registered as an event
|
// Avoid that the button press itself is registered as an event
|
||||||
Common::SleepCurrentThread(50);
|
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);
|
const auto timer = new QTimer(button);
|
||||||
|
|
||||||
@ -83,14 +83,24 @@ QString DetectExpression(QPushButton* button, ciface::Core::DeviceContainer& dev
|
|||||||
|
|
||||||
button->setText(old_text);
|
button->setText(old_text);
|
||||||
|
|
||||||
if (!input)
|
QString full_expression;
|
||||||
return {};
|
|
||||||
|
|
||||||
ciface::Core::DeviceQualifier device_qualifier;
|
for (auto [device, input] : detections)
|
||||||
device_qualifier.FromDevice(device.get());
|
{
|
||||||
|
ciface::Core::DeviceQualifier device_qualifier;
|
||||||
|
device_qualifier.FromDevice(device.get());
|
||||||
|
|
||||||
return MappingCommon::GetExpressionForControl(QString::fromStdString(input->GetName()),
|
if (!full_expression.isEmpty())
|
||||||
device_qualifier, default_device, quote);
|
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 full_expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestOutput(QPushButton* button, OutputReference* reference)
|
void TestOutput(QPushButton* button, OutputReference* reference)
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
namespace ciface::Core
|
namespace ciface::Core
|
||||||
{
|
{
|
||||||
// Compared to an input's current state (ideally 1.0) minus abs(initial_state) (ideally 0.0).
|
// 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;
|
constexpr ControlState INPUT_DETECT_THRESHOLD = 0.55;
|
||||||
|
|
||||||
Device::~Device()
|
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.
|
// 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
|
// This is useful for crazy flightsticks that have certain buttons that are always held down
|
||||||
// and also properly handles detection when using "FullAnalogSurface" inputs.
|
// and also properly handles detection when using "FullAnalogSurface" inputs.
|
||||||
// Upon input, return the detected Device and Input, else return nullptrs
|
// Detects multiple inputs if they are pressed before others are released.
|
||||||
std::pair<std::shared_ptr<Device>, Device::Input*>
|
// 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
|
DeviceContainer::DetectInput(u32 wait_ms, const std::vector<std::string>& device_strings) const
|
||||||
{
|
{
|
||||||
struct InputState
|
struct InputState
|
||||||
{
|
{
|
||||||
ciface::Core::Device::Input& input;
|
ciface::Core::Device::Input* input;
|
||||||
ControlState initial_state;
|
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
|
// Undesirable axes will have negative values here when trying to map a
|
||||||
// "FullAnalogSurface".
|
// "FullAnalogSurface".
|
||||||
input_states.push_back({*input, input->GetState()});
|
input_states.push_back({input, input->GetState()});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!input_states.empty())
|
if (!input_states.empty())
|
||||||
@ -301,6 +303,8 @@ DeviceContainer::DetectInput(u32 wait_ms, const std::vector<std::string>& device
|
|||||||
if (device_states.empty())
|
if (device_states.empty())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
std::vector<std::pair<std::shared_ptr<Device>, Device::Input*>> detections;
|
||||||
|
|
||||||
u32 time = 0;
|
u32 time = 0;
|
||||||
while (time < wait_ms)
|
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& 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.
|
// We want an input that was initially 0.0 and currently 1.0.
|
||||||
const auto detection_score =
|
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)
|
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. :'(
|
// No input was detected. :'(
|
||||||
|
@ -194,7 +194,7 @@ public:
|
|||||||
|
|
||||||
bool HasConnectedDevice(const DeviceQualifier& qualifier) const;
|
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;
|
DetectInput(u32 wait_ms, const std::vector<std::string>& device_strings) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
Loading…
Reference in New Issue
Block a user