InputCommon: Make hotkeys and input detection aware of Ctrl -> L_Ctrl / R_Ctrl hierarchy.
This commit is contained in:
parent
aae913fbc6
commit
d8ad8c3861
|
@ -93,6 +93,12 @@ QString DetectExpression(QPushButton* button, ciface::Core::DeviceContainer& dev
|
|||
if (!full_expression.isEmpty())
|
||||
full_expression += QChar::fromLatin1('+');
|
||||
|
||||
// Return the parent-most name if there is one for better hotkey strings.
|
||||
// Detection of L/R_Ctrl will be changed to just Ctrl.
|
||||
// Users can manually map L_Ctrl if they so desire.
|
||||
if (quote == Quote::On)
|
||||
input = device->GetParentMostInput(input);
|
||||
|
||||
full_expression += MappingCommon::GetExpressionForControl(
|
||||
QString::fromStdString(input->GetName()), device_qualifier, default_device, quote);
|
||||
}
|
||||
|
|
|
@ -291,9 +291,14 @@ bool HotkeySuppressions::IsSuppressedIgnoringModifiers(Device::Input* input,
|
|||
auto it = m_suppressions.lower_bound({input, nullptr});
|
||||
auto it_end = m_suppressions.lower_bound({input + 1, nullptr});
|
||||
|
||||
// We need to ignore L_Ctrl R_Ctrl when supplied Ctrl and vice-versa.
|
||||
const auto is_same_modifier = [](Device::Input* i1, Device::Input* i2) {
|
||||
return i1 == i2 || i1->IsChild(i2) || i2->IsChild(i1);
|
||||
};
|
||||
|
||||
return std::any_of(it, it_end, [&](auto& s) {
|
||||
return std::none_of(begin(ignore_modifiers), end(ignore_modifiers),
|
||||
[&](auto& m) { return m->GetInput() == s.first.second; });
|
||||
[&](auto& m) { return is_same_modifier(m->GetInput(), s.first.second); });
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,38 @@ namespace ciface::Core
|
|||
// Note: Detect() logic assumes this is greater than 0.5.
|
||||
constexpr ControlState INPUT_DETECT_THRESHOLD = 0.55;
|
||||
|
||||
class CombinedInput final : public Device::Input
|
||||
{
|
||||
public:
|
||||
using Inputs = std::pair<Device::Input*, Device::Input*>;
|
||||
|
||||
CombinedInput(std::string name, const Inputs& inputs) : m_name(std::move(name)), m_inputs(inputs)
|
||||
{
|
||||
}
|
||||
ControlState GetState() const override
|
||||
{
|
||||
ControlState result = 0;
|
||||
|
||||
if (m_inputs.first)
|
||||
result = m_inputs.first->GetState();
|
||||
|
||||
if (m_inputs.second)
|
||||
result = std::max(result, m_inputs.second->GetState());
|
||||
|
||||
return result;
|
||||
}
|
||||
std::string GetName() const override { return m_name; }
|
||||
bool IsDetectable() const override { return false; }
|
||||
bool IsChild(const Input* input) const override
|
||||
{
|
||||
return m_inputs.first == input || m_inputs.second == input;
|
||||
}
|
||||
|
||||
private:
|
||||
const std::string m_name;
|
||||
const std::pair<Device::Input*, Device::Input*> m_inputs;
|
||||
};
|
||||
|
||||
Device::~Device()
|
||||
{
|
||||
// delete inputs
|
||||
|
@ -52,6 +84,20 @@ std::string Device::GetQualifiedName() const
|
|||
return fmt::format("{}/{}/{}", GetSource(), GetId(), GetName());
|
||||
}
|
||||
|
||||
auto Device::GetParentMostInput(Input* child) const -> Input*
|
||||
{
|
||||
for (auto* input : m_inputs)
|
||||
{
|
||||
if (input->IsChild(child))
|
||||
{
|
||||
// Running recursively is currently unnecessary but it doesn't hurt.
|
||||
return GetParentMostInput(input);
|
||||
}
|
||||
}
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
Device::Input* Device::FindInput(std::string_view name) const
|
||||
{
|
||||
for (Input* input : m_inputs)
|
||||
|
@ -103,34 +149,6 @@ bool Device::FullAnalogSurface::IsMatchingName(std::string_view name) const
|
|||
return old_name == name;
|
||||
}
|
||||
|
||||
Device::CombinedInput::CombinedInput(std::string name, const Inputs& inputs)
|
||||
: m_name(std::move(name)), m_inputs(inputs)
|
||||
{
|
||||
}
|
||||
|
||||
ControlState Device::CombinedInput::GetState() const
|
||||
{
|
||||
ControlState result = 0;
|
||||
|
||||
if (m_inputs.first)
|
||||
result = m_inputs.first->GetState();
|
||||
|
||||
if (m_inputs.second)
|
||||
result = std::max(result, m_inputs.second->GetState());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string Device::CombinedInput::GetName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
bool Device::CombinedInput::IsDetectable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void Device::AddCombinedInput(std::string name, const std::pair<std::string, std::string>& inputs)
|
||||
{
|
||||
AddInput(new CombinedInput(std::move(name), {FindInput(inputs.first), FindInput(inputs.second)}));
|
||||
|
|
|
@ -85,6 +85,11 @@ public:
|
|||
virtual ControlState GetState() const = 0;
|
||||
|
||||
Input* ToInput() override { return this; }
|
||||
|
||||
// Overridden by CombinedInput,
|
||||
// so hotkey logic knows Ctrl, L_Ctrl, and R_Ctrl are the same,
|
||||
// and so input detection can return the parent name.
|
||||
virtual bool IsChild(const Input*) const { return false; }
|
||||
};
|
||||
|
||||
//
|
||||
|
@ -119,6 +124,8 @@ public:
|
|||
const std::vector<Input*>& Inputs() const { return m_inputs; }
|
||||
const std::vector<Output*>& Outputs() const { return m_outputs; }
|
||||
|
||||
Input* GetParentMostInput(Input* input) const;
|
||||
|
||||
Input* FindInput(std::string_view name) const;
|
||||
Output* FindOutput(std::string_view name) const;
|
||||
|
||||
|
@ -147,21 +154,6 @@ protected:
|
|||
AddInput(new FullAnalogSurface(high, low));
|
||||
}
|
||||
|
||||
class CombinedInput final : public Input
|
||||
{
|
||||
public:
|
||||
using Inputs = std::pair<Input*, Input*>;
|
||||
|
||||
CombinedInput(std::string name, const Inputs& inputs);
|
||||
ControlState GetState() const override;
|
||||
std::string GetName() const override;
|
||||
bool IsDetectable() override;
|
||||
|
||||
private:
|
||||
const std::string m_name;
|
||||
const std::pair<Input*, Input*> m_inputs;
|
||||
};
|
||||
|
||||
void AddCombinedInput(std::string name, const std::pair<std::string, std::string>& inputs);
|
||||
|
||||
private:
|
||||
|
|
Loading…
Reference in New Issue