diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingWidget.cpp b/Source/Core/DolphinQt/Config/Mapping/MappingWidget.cpp index 5eadb359b4..d1e09ac973 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingWidget.cpp +++ b/Source/Core/DolphinQt/Config/Mapping/MappingWidget.cpp @@ -332,6 +332,9 @@ MappingWidget::CreateSettingAdvancedMappingButton(ControllerEmu::NumericSettingB if (setting.IsSimpleValue()) setting.SetExpressionFromValue(); + // Ensure the UI has the game-controller indicator while editing the expression. + ConfigChanged(); + IOWindow io(this, GetController(), &setting.GetInputReference(), IOWindow::Type::Input); SetQWidgetWindowDecorations(&io); io.exec(); diff --git a/Source/Core/InputCommon/ControlReference/ControlReference.h b/Source/Core/InputCommon/ControlReference/ControlReference.h index f12e354bb3..984ab2cd0f 100644 --- a/Source/Core/InputCommon/ControlReference/ControlReference.h +++ b/Source/Core/InputCommon/ControlReference/ControlReference.h @@ -9,6 +9,12 @@ #include "InputCommon/ControlReference/ExpressionParser.h" #include "InputCommon/ControllerInterface/CoreDevice.h" +namespace ControllerEmu +{ +template +T ControlStateCast(ControlState value); +} + // ControlReference // // These are what you create to actually use the inputs, InputReference or OutputReference. @@ -31,7 +37,10 @@ public: virtual bool IsInput() const = 0; template - T GetState(); + T GetState() + { + return ControllerEmu::ControlStateCast(State()); + } int BoundCount() const; ciface::ExpressionParser::ParseStatus GetParseStatus() const; @@ -51,24 +60,27 @@ protected: ciface::ExpressionParser::ParseStatus::EmptyExpression; }; +namespace ControllerEmu +{ template <> -inline bool ControlReference::GetState() +inline bool ControlStateCast(ControlState value) { // Round to nearest of 0 or 1. - return std::lround(State()) > 0; + return std::lround(value) > 0; } template <> -inline int ControlReference::GetState() +inline int ControlStateCast(ControlState value) { - return std::lround(State()); + return std::lround(value); } template <> -inline ControlState ControlReference::GetState() +inline ControlState ControlStateCast(ControlState value) { - return State(); + return value; } +} // namespace ControllerEmu // // InputReference diff --git a/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp b/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp index 30a261d13d..b76c170a2f 100644 --- a/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp +++ b/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp @@ -830,6 +830,12 @@ private: // Interpret it as a unary minus function. return ParseFunctionArguments("minus", MakeFunctionExpression("minus"), tok); } + case TOK_ADD: + { + // An atom was expected but we got an addition symbol. + // Interpret it as a unary plus. + return ParseFunctionArguments("plus", MakeFunctionExpression("plus"), tok); + } default: { return ParseResult::MakeErrorResult(tok, _trans("Expected start of expression.")); diff --git a/Source/Core/InputCommon/ControlReference/FunctionExpression.cpp b/Source/Core/InputCommon/ControlReference/FunctionExpression.cpp index 46cfc37beb..15d8c72c0c 100644 --- a/Source/Core/InputCommon/ControlReference/FunctionExpression.cpp +++ b/Source/Core/InputCommon/ControlReference/FunctionExpression.cpp @@ -375,6 +375,22 @@ private: } }; +// usage: plus(expression) +class UnaryPlusExpression : public FunctionExpression +{ +private: + ArgumentValidation + ValidateArguments(const std::vector>& args) override + { + if (args.size() == 1) + return ArgumentsAreValid{}; + else + return ExpectedArguments{"expression"}; + } + + ControlState GetValue() const override { return GetArg(0).GetValue(); } +}; + // usage: deadzone(input, amount) class DeadzoneExpression : public FunctionExpression { @@ -689,6 +705,8 @@ std::unique_ptr MakeFunctionExpression(std::string_view name return std::make_unique(); if (name == "minus") return std::make_unique(); + if (name == "plus") + return std::make_unique(); if (name == "deadzone") return std::make_unique(); if (name == "smooth") diff --git a/Source/Core/InputCommon/ControllerEmu/Setting/NumericSetting.cpp b/Source/Core/InputCommon/ControllerEmu/Setting/NumericSetting.cpp index ec28a4d6f6..f551e39b44 100644 --- a/Source/Core/InputCommon/ControllerEmu/Setting/NumericSetting.cpp +++ b/Source/Core/InputCommon/ControllerEmu/Setting/NumericSetting.cpp @@ -3,7 +3,7 @@ #include "InputCommon/ControllerEmu/Setting/NumericSetting.h" -#include +#include namespace ControllerEmu { @@ -11,6 +11,11 @@ NumericSettingBase::NumericSettingBase(const NumericSettingDetails& details) : m { } +// Explicit instantiations so generic definitions can exist outside of the header. +template class NumericSetting; +template class NumericSetting; +template class NumericSetting; + const char* NumericSettingBase::GetININame() const { return m_details.ini_name; @@ -36,28 +41,20 @@ SettingVisibility NumericSettingBase::GetVisibility() const return m_details.visibility; } -template <> -void NumericSetting::SetExpressionFromValue() +template +void NumericSetting::SetExpressionFromValue() { - m_value.m_input.SetExpression(ValueToString(GetValue())); + // Always include -/+ sign to prevent CoalesceExpression binding. + // e.g. 1 is a valid input name for keyboard devices, +1 is not. + m_value.m_input.SetExpression(fmt::format("{:+g}", ControlState(GetValue()))); } -template <> -void NumericSetting::SetExpressionFromValue() +template +void NumericSetting::SimplifyIfPossible() { - // 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::SetExpressionFromValue() -{ - // Cast bool to prevent "true"/"false" strings. - m_value.m_input.SetExpression(ValueToString(int(GetValue()))); + ValueType value; + if (TryParse(std::string(StripWhitespace(m_value.m_input.GetExpression())), &value)) + m_value.SetValue(value); } template <> diff --git a/Source/Core/InputCommon/ControllerEmu/Setting/NumericSetting.h b/Source/Core/InputCommon/ControllerEmu/Setting/NumericSetting.h index 67d2fce1c7..b102b062e7 100644 --- a/Source/Core/InputCommon/ControllerEmu/Setting/NumericSetting.h +++ b/Source/Core/InputCommon/ControllerEmu/Setting/NumericSetting.h @@ -143,14 +143,7 @@ public: } 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 SimplifyIfPossible() override; void SetExpressionFromValue() override; InputReference& GetInputReference() override { return m_value.m_input; } const InputReference& GetInputReference() const override { return m_value.m_input; }