diff options
| author | Tilka <tilkax@gmail.com> | 2020-02-09 01:37:30 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-02-09 01:37:30 +0000 |
| commit | 2e2540317e8752b8fe2e4d549a0b5c1ab1911041 (patch) | |
| tree | c5997fb92fc14a5dbbc061a5b572da18d0877e86 /Source/Core/InputCommon | |
| parent | 7fe11c95782a305e1e03a401e54d819700b39805 (diff) | |
| parent | 0a1634bedf17f7b27a3781d8e5ac6bafb20cd546 (diff) | |
Merge pull request #8417 from jordan-woyak/setting-expressions
InputCommon: Allow controller settings specified with input expresions.
Diffstat (limited to 'Source/Core/InputCommon')
11 files changed, 162 insertions, 28 deletions
diff --git a/Source/Core/InputCommon/ControlReference/ControlReference.h b/Source/Core/InputCommon/ControlReference/ControlReference.h index 539c7f4927..80c4a65d51 100644 --- a/Source/Core/InputCommon/ControlReference/ControlReference.h +++ b/Source/Core/InputCommon/ControlReference/ControlReference.h @@ -7,6 +7,7 @@ #include <memory> #include "InputCommon/ControlReference/ExpressionParser.h" +#include "InputCommon/ControlReference/FunctionExpression.h" #include "InputCommon/ControllerInterface/Device.h" // ControlReference @@ -30,6 +31,9 @@ public: virtual ControlState State(const ControlState state = 0) = 0; virtual bool IsInput() const = 0; + template <typename T> + T GetState(); + int BoundCount() const; ciface::ExpressionParser::ParseStatus GetParseStatus() const; void UpdateReference(ciface::ExpressionParser::ControlEnvironment& env); @@ -45,6 +49,18 @@ protected: ciface::ExpressionParser::ParseStatus m_parse_status; }; +template <> +inline bool ControlReference::GetState<bool>() +{ + return State() > ciface::ExpressionParser::CONDITION_THRESHOLD; +} + +template <typename T> +T ControlReference::GetState() +{ + return State(); +} + // // InputReference // diff --git a/Source/Core/InputCommon/ControlReference/FunctionExpression.cpp b/Source/Core/InputCommon/ControlReference/FunctionExpression.cpp index 75f78526e6..4d8e2866db 100644 --- a/Source/Core/InputCommon/ControlReference/FunctionExpression.cpp +++ b/Source/Core/InputCommon/ControlReference/FunctionExpression.cpp @@ -10,8 +10,6 @@ namespace ciface::ExpressionParser { -constexpr ControlState CONDITION_THRESHOLD = 0.5; - using Clock = std::chrono::steady_clock; using FSec = std::chrono::duration<ControlState>; diff --git a/Source/Core/InputCommon/ControlReference/FunctionExpression.h b/Source/Core/InputCommon/ControlReference/FunctionExpression.h index e247d9a623..3b29baa9ae 100644 --- a/Source/Core/InputCommon/ControlReference/FunctionExpression.h +++ b/Source/Core/InputCommon/ControlReference/FunctionExpression.h @@ -15,6 +15,8 @@ namespace ciface::ExpressionParser { +constexpr ControlState CONDITION_THRESHOLD = 0.5; + class FunctionExpression : public Expression { public: diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Attachments.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Attachments.cpp index e104918fe2..6f980d8c60 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Attachments.cpp +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Attachments.cpp @@ -17,12 +17,22 @@ void Attachments::AddAttachment(std::unique_ptr<EmulatedController> att) u32 Attachments::GetSelectedAttachment() const { - return m_selected_attachment; + const u32 value = m_selection_value.GetValue(); + + if (value < m_attachments.size()) + return value; + + return 0; } void Attachments::SetSelectedAttachment(u32 val) { - m_selected_attachment = val; + m_selection_setting.SetValue(val); +} + +NumericSetting<int>& Attachments::GetSelectionSetting() +{ + return m_selection_setting; } const std::vector<std::unique_ptr<EmulatedController>>& Attachments::GetAttachmentList() const diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Attachments.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Attachments.h index 81e76eccfe..f92bd8b1fd 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Attachments.h +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Attachments.h @@ -12,6 +12,7 @@ #include "Common/CommonTypes.h" #include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h" #include "InputCommon/ControllerEmu/ControllerEmu.h" +#include "InputCommon/ControllerEmu/Setting/NumericSetting.h" namespace ControllerEmu { @@ -27,11 +28,14 @@ public: u32 GetSelectedAttachment() const; void SetSelectedAttachment(u32 val); + NumericSetting<int>& GetSelectionSetting(); + const std::vector<std::unique_ptr<EmulatedController>>& GetAttachmentList() const; private: - std::vector<std::unique_ptr<EmulatedController>> m_attachments; + SettingValue<int> m_selection_value; + NumericSetting<int> m_selection_setting = {&m_selection_value, {""}, 0, 0, 0}; - std::atomic<u32> m_selected_attachment = {}; + std::vector<std::unique_ptr<EmulatedController>> m_attachments; }; } // namespace ControllerEmu diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Buttons.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Buttons.h index c2311415e5..9560a37843 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Buttons.h +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Buttons.h @@ -24,13 +24,11 @@ public: { for (auto& control : controls) { - if (control->control_ref->State() > ACTIVATION_THRESHOLD) + if (control->control_ref->GetState<bool>()) *buttons |= *bitmasks; bitmasks++; } } - - static constexpr ControlState ACTIVATION_THRESHOLD = 0.5; }; } // namespace ControllerEmu diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.cpp index 40ccae24f7..1a262a8dfd 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.cpp +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.cpp @@ -74,15 +74,19 @@ void ControlGroup::LoadConfig(IniFile::Section* sec, const std::string& defdev, ext->SetSelectedAttachment(0); u32 n = 0; - std::string extname; - sec->Get(base + name, &extname, ""); + std::string attachment_text; + sec->Get(base + name, &attachment_text, ""); + + // First assume attachment string is a valid expression. + // If it instead matches one of the names of our attachments it is overridden below. + ext->GetSelectionSetting().GetInputReference().SetExpression(attachment_text); for (auto& ai : ext->GetAttachmentList()) { ai->SetDefaultDevice(defdev); ai->LoadConfig(sec, base + ai->GetName() + "/"); - if (ai->GetName() == extname) + if (ai->GetName() == attachment_text) ext->SetSelectedAttachment(n); n++; @@ -114,8 +118,16 @@ void ControlGroup::SaveConfig(IniFile::Section* sec, const std::string& defdev, if (type == GroupType::Attachments) { auto* const ext = static_cast<Attachments*>(this); - sec->Set(base + name, ext->GetAttachmentList()[ext->GetSelectedAttachment()]->GetName(), - "None"); + + if (ext->GetSelectionSetting().IsSimpleValue()) + { + sec->Set(base + name, ext->GetAttachmentList()[ext->GetSelectedAttachment()]->GetName(), + "None"); + } + else + { + sec->Set(base + name, ext->GetSelectionSetting().GetInputReference().GetExpression(), "None"); + } for (auto& ai : ext->GetAttachmentList()) ai->SaveConfig(sec, base + ai->GetName() + "/"); diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/ModifySettingsButton.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/ModifySettingsButton.cpp index 908de81a96..a902034795 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/ModifySettingsButton.cpp +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/ModifySettingsButton.cpp @@ -35,19 +35,19 @@ void ModifySettingsButton::GetState() { for (size_t i = 0; i < controls.size(); ++i) { - ControlState state = controls[i]->control_ref->State(); + const bool state = controls[i]->control_ref->GetState<bool>(); if (!associated_settings_toggle[i]) { // not toggled - associated_settings[i] = state > ACTIVATION_THRESHOLD; + associated_settings[i] = state; } else { // toggle (loading savestates does not en-/disable toggle) // after we passed the threshold, we en-/disable. but after that, we don't change it // anymore - if (!threshold_exceeded[i] && state > ACTIVATION_THRESHOLD) + if (!threshold_exceeded[i] && state) { associated_settings[i] = !associated_settings[i]; @@ -59,7 +59,7 @@ void ModifySettingsButton::GetState() threshold_exceeded[i] = true; } - if (state < ACTIVATION_THRESHOLD) + if (!state) threshold_exceeded[i] = false; } } diff --git a/Source/Core/InputCommon/ControllerEmu/ControllerEmu.cpp b/Source/Core/InputCommon/ControllerEmu/ControllerEmu.cpp index c5ff0705a2..a9c5844b48 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControllerEmu.cpp +++ b/Source/Core/InputCommon/ControllerEmu/ControllerEmu.cpp @@ -14,6 +14,7 @@ #include "InputCommon/ControllerEmu/Control/Control.h" #include "InputCommon/ControllerEmu/ControlGroup/Attachments.h" #include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h" +#include "InputCommon/ControllerEmu/Setting/NumericSetting.h" #include "InputCommon/ControllerInterface/ControllerInterface.h" namespace ControllerEmu @@ -54,10 +55,17 @@ void EmulatedController::UpdateReferences(ciface::ExpressionParser::ControlEnvir for (auto& control : ctrlGroup->controls) control->control_ref->UpdateReference(env); + for (auto& setting : ctrlGroup->numeric_settings) + setting->GetInputReference().UpdateReference(env); + // Attachments: if (ctrlGroup->type == GroupType::Attachments) { - for (auto& attachment : static_cast<Attachments*>(ctrlGroup.get())->GetAttachmentList()) + auto* const attachments = static_cast<Attachments*>(ctrlGroup.get()); + + attachments->GetSelectionSetting().GetInputReference().UpdateReference(env); + + for (auto& attachment : attachments->GetAttachmentList()) attachment->UpdateReferences(env); } } diff --git a/Source/Core/InputCommon/ControllerEmu/Setting/NumericSetting.cpp b/Source/Core/InputCommon/ControllerEmu/Setting/NumericSetting.cpp index 3459040824..ab45b64595 100644 --- a/Source/Core/InputCommon/ControllerEmu/Setting/NumericSetting.cpp +++ b/Source/Core/InputCommon/ControllerEmu/Setting/NumericSetting.cpp @@ -4,6 +4,8 @@ #include "InputCommon/ControllerEmu/Setting/NumericSetting.h" +#include <sstream> + namespace ControllerEmu { NumericSettingBase::NumericSettingBase(const NumericSettingDetails& details) : m_details(details) @@ -26,6 +28,36 @@ const char* NumericSettingBase::GetUIDescription() const } template <> +void NumericSetting<int>::SetExpressionFromValue() +{ + m_value.m_input.SetExpression(ValueToString(GetValue())); +} + +template <> +void NumericSetting<double>::SetExpressionFromValue() +{ + // We must use a dot decimal separator for expression parser. + std::ostringstream ss; + ss.imbue(std::locale::classic()); + ss << GetValue(); + + m_value.m_input.SetExpression(ss.str()); +} + +template <> +void NumericSetting<bool>::SetExpressionFromValue() +{ + // Cast bool to prevent "true"/"false" strings. + m_value.m_input.SetExpression(ValueToString(int(GetValue()))); +} + +template <> +SettingType NumericSetting<int>::GetType() const +{ + return SettingType::Int; +} + +template <> SettingType NumericSetting<double>::GetType() const { return SettingType::Double; diff --git a/Source/Core/InputCommon/ControllerEmu/Setting/NumericSetting.h b/Source/Core/InputCommon/ControllerEmu/Setting/NumericSetting.h index 108b228049..c7298391f4 100644 --- a/Source/Core/InputCommon/ControllerEmu/Setting/NumericSetting.h +++ b/Source/Core/InputCommon/ControllerEmu/Setting/NumericSetting.h @@ -9,12 +9,14 @@ #include "Common/CommonTypes.h" #include "Common/IniFile.h" +#include "InputCommon/ControlReference/ControlReference.h" #include "InputCommon/ControllerInterface/Device.h" namespace ControllerEmu { enum class SettingType { + Int, Double, Bool, }; @@ -52,6 +54,17 @@ public: virtual void LoadFromIni(const IniFile::Section& section, const std::string& group_name) = 0; virtual void SaveToIni(IniFile::Section& section, const std::string& group_name) const = 0; + virtual InputReference& GetInputReference() = 0; + virtual const InputReference& GetInputReference() const = 0; + + virtual bool IsSimpleValue() const = 0; + + // Convert a literal expression e.g. "7.0" to a regular value. (disables expression parsing) + virtual void SimplifyIfPossible() = 0; + + // Convert a regular value to an expression. (used before expression editing) + virtual void SetExpressionFromValue() = 0; + virtual SettingType GetType() const = 0; const char* GetUIName() const; @@ -66,13 +79,14 @@ template <typename T> class SettingValue; template <typename T> -class NumericSetting : public NumericSettingBase +class NumericSetting final : public NumericSettingBase { public: using ValueType = T; - static_assert(std::is_same<ValueType, double>() || std::is_same<ValueType, bool>(), - "NumericSetting is only implemented for double and bool."); + static_assert(std::is_same<ValueType, int>() || std::is_same<ValueType, double>() || + std::is_same<ValueType, bool>(), + "NumericSetting is only implemented for int, double, and bool."); NumericSetting(SettingValue<ValueType>* value, const NumericSettingDetails& details, ValueType default_value, ValueType min_value, ValueType max_value) @@ -84,16 +98,39 @@ public: void LoadFromIni(const IniFile::Section& section, const std::string& group_name) override { - ValueType value; - section.Get(group_name + m_details.ini_name, &value, m_default_value); - SetValue(value); + std::string str_value; + if (section.Get(group_name + m_details.ini_name, &str_value)) + { + m_value.m_input.SetExpression(std::move(str_value)); + SimplifyIfPossible(); + } + else + { + SetValue(m_default_value); + } } void SaveToIni(IniFile::Section& section, const std::string& group_name) const override { - section.Set(group_name + m_details.ini_name, GetValue(), m_default_value); + if (IsSimpleValue()) + section.Set(group_name + m_details.ini_name, GetValue(), m_default_value); + else + section.Set(group_name + m_details.ini_name, m_value.m_input.GetExpression(), ""); + } + + bool IsSimpleValue() const override { return m_value.IsSimpleValue(); } + + void SimplifyIfPossible() override + { + ValueType value; + if (TryParse(m_value.m_input.GetExpression(), &value)) + m_value.SetValue(value); } + void SetExpressionFromValue() override; + InputReference& GetInputReference() override { return m_value.m_input; } + const InputReference& GetInputReference() const override { return m_value.m_input; } + ValueType GetValue() const { return m_value.GetValue(); } void SetValue(ValueType value) { m_value.SetValue(value); } @@ -119,13 +156,30 @@ class SettingValue friend class NumericSetting<T>; public: - ValueType GetValue() const { return m_value; } + ValueType GetValue() const + { + if (IsSimpleValue()) + return m_value; + else + return m_input.GetState<ValueType>(); + } + + bool IsSimpleValue() const { return m_input.GetExpression().empty(); } private: - void SetValue(ValueType value) { m_value = value; } + void SetValue(ValueType value) + { + m_value = value; + + // Clear the expression to use our new "simple" value. + m_input.SetExpression(""); + } // Values are R/W by both UI and CPU threads. std::atomic<ValueType> m_value = {}; + + // Unfortunately InputReference's state grabbing is non-const requiring mutable here. + mutable InputReference m_input; }; } // namespace ControllerEmu |
