diff --git a/Source/Core/Core/HotkeyManager.cpp b/Source/Core/Core/HotkeyManager.cpp index b9dab79224..89c394deb7 100644 --- a/Source/Core/Core/HotkeyManager.cpp +++ b/Source/Core/Core/HotkeyManager.cpp @@ -344,7 +344,7 @@ void HotkeyManager::LoadDefaults(const ControllerInterface& ciface) auto set_key_expression = [this](int index, const std::string& expression) { m_keys[FindGroupByID(index)] ->controls[GetIndexForGroup(FindGroupByID(index), index)] - ->control_ref->expression = expression; + ->control_ref->SetExpression(expression); }; // General hotkeys diff --git a/Source/Core/DolphinQt2/Config/Mapping/IOWindow.cpp b/Source/Core/DolphinQt2/Config/Mapping/IOWindow.cpp index ae40b29c17..294cf5878f 100644 --- a/Source/Core/DolphinQt2/Config/Mapping/IOWindow.cpp +++ b/Source/Core/DolphinQt2/Config/Mapping/IOWindow.cpp @@ -110,7 +110,7 @@ void IOWindow::CreateMainLayout() void IOWindow::Update() { - m_expression_text->setPlainText(QString::fromStdString(m_reference->expression)); + m_expression_text->setPlainText(QString::fromStdString(m_reference->GetExpression())); m_range_spinbox->setValue(m_reference->range * SLIDER_TICK_COUNT); m_range_slider->setValue(m_reference->range * SLIDER_TICK_COUNT); @@ -164,7 +164,7 @@ void IOWindow::OnDialogButtonPressed(QAbstractButton* button) return; } - m_reference->expression = m_expression_text->toPlainText().toStdString(); + m_reference->SetExpression(m_expression_text->toPlainText().toStdString()); if (button != m_apply_button) accept(); diff --git a/Source/Core/DolphinQt2/Config/Mapping/MappingButton.cpp b/Source/Core/DolphinQt2/Config/Mapping/MappingButton.cpp index 7c01a527a2..d30be53ec5 100644 --- a/Source/Core/DolphinQt2/Config/Mapping/MappingButton.cpp +++ b/Source/Core/DolphinQt2/Config/Mapping/MappingButton.cpp @@ -27,7 +27,7 @@ static QString EscapeAmpersand(QString&& string) } MappingButton::MappingButton(MappingWidget* widget, ControlReference* ref) - : ElidedButton(EscapeAmpersand(QString::fromStdString(ref->expression))), m_parent(widget), + : ElidedButton(EscapeAmpersand(QString::fromStdString(ref->GetExpression()))), m_parent(widget), m_reference(ref) { Connect(); @@ -66,7 +66,7 @@ void MappingButton::OnButtonPressed() if (!expr.isEmpty()) { - m_reference->expression = expr.toStdString(); + m_reference->SetExpression(expr.toStdString()); Update(); } else @@ -78,13 +78,13 @@ void MappingButton::OnButtonPressed() void MappingButton::OnButtonTimeout() { - setText(EscapeAmpersand(QString::fromStdString(m_reference->expression))); + setText(EscapeAmpersand(QString::fromStdString(m_reference->GetExpression()))); } void MappingButton::Clear() { m_parent->Update(); - m_reference->expression.clear(); + m_reference->SetExpression(""); Update(); } @@ -92,7 +92,7 @@ void MappingButton::Update() { const auto lock = ControllerEmu::EmulatedController::GetStateLock(); m_reference->UpdateReference(g_controller_interface, m_parent->GetParent()->GetDeviceQualifier()); - setText(EscapeAmpersand(QString::fromStdString(m_reference->expression))); + setText(EscapeAmpersand(QString::fromStdString(m_reference->GetExpression()))); m_parent->SaveSettings(); } diff --git a/Source/Core/DolphinWX/Input/InputConfigDiag.cpp b/Source/Core/DolphinWX/Input/InputConfigDiag.cpp index 5d8bf9615e..1e6cba569d 100644 --- a/Source/Core/DolphinWX/Input/InputConfigDiag.cpp +++ b/Source/Core/DolphinWX/Input/InputConfigDiag.cpp @@ -70,7 +70,7 @@ #include "InputCommon/ControllerInterface/Device.h" #include "InputCommon/InputConfig.h" -using namespace ciface::ExpressionParser; +using ciface::ExpressionParser::ParseStatus; void InputConfigDialog::ConfigExtension(wxCommandEvent& event) { @@ -243,7 +243,7 @@ ControlButton::ControlButton(wxWindow* const parent, ControlReference* const _re m_configured_width(FromDIP(width)) { if (label.empty()) - SetLabelText(StrToWxStr(_ref->expression)); + SetLabelText(StrToWxStr(_ref->GetExpression())); else SetLabel(StrToWxStr(label)); } @@ -336,7 +336,7 @@ void ControlDialog::SelectControl(const std::string& name) void ControlDialog::UpdateGUI() { // update textbox - textctrl->SetValue(StrToWxStr(control_reference->expression)); + textctrl->SetValue(StrToWxStr(control_reference->GetExpression())); // updates the "bound controls:" label m_bound_label->SetLabel( @@ -347,11 +347,12 @@ void ControlDialog::UpdateGUI() case ParseStatus::SyntaxError: m_error_label->SetLabel(_("Syntax error")); break; - case ParseStatus::NoDevice: - m_error_label->SetLabel(_("Device not found")); + case ParseStatus::Successful: + m_error_label->SetLabel(control_reference->BoundCount() > 0 ? "" : _("Device not found")); break; - default: + case ParseStatus::EmptyExpression: m_error_label->SetLabel(""); + break; } }; @@ -364,7 +365,7 @@ void InputConfigDialog::UpdateGUI() { for (ControlButton* button : cgBox->control_buttons) { - button->SetLabelText(StrToWxStr(button->control_reference->expression)); + button->SetLabelText(StrToWxStr(button->control_reference->GetExpression())); } for (PadSetting* padSetting : cgBox->options) @@ -399,7 +400,7 @@ void InputConfigDialog::LoadDefaults(wxCommandEvent&) bool ControlDialog::Validate() { - control_reference->expression = WxStrToStr(textctrl->GetValue()); + control_reference->SetExpression(WxStrToStr(textctrl->GetValue())); const auto lock = ControllerEmu::EmulatedController::GetStateLock(); control_reference->UpdateReference(g_controller_interface, @@ -408,7 +409,7 @@ bool ControlDialog::Validate() UpdateGUI(); const auto parse_status = control_reference->GetParseStatus(); - return parse_status == ParseStatus::Successful || parse_status == ParseStatus::NoDevice; + return parse_status == ParseStatus::Successful || parse_status == ParseStatus::EmptyExpression; } void InputConfigDialog::SetDevice(wxCommandEvent&) @@ -438,7 +439,7 @@ void ControlDialog::SetDevice(wxCommandEvent&) void ControlDialog::ClearControl(wxCommandEvent&) { - control_reference->expression.clear(); + control_reference->SetExpression(""); const auto lock = ControllerEmu::EmulatedController::GetStateLock(); control_reference->UpdateReference(g_controller_interface, @@ -497,7 +498,7 @@ void ControlDialog::SetSelectedControl(wxCommandEvent&) return; textctrl->WriteText(expr); - control_reference->expression = textctrl->GetValue(); + control_reference->SetExpression(WxStrToStr(textctrl->GetValue())); const auto lock = ControllerEmu::EmulatedController::GetStateLock(); control_reference->UpdateReference(g_controller_interface, @@ -533,7 +534,7 @@ void ControlDialog::AppendControl(wxCommandEvent& event) } textctrl->WriteText(expr); - control_reference->expression = textctrl->GetValue(); + control_reference->SetExpression(WxStrToStr(textctrl->GetValue())); const auto lock = ControllerEmu::EmulatedController::GetStateLock(); control_reference->UpdateReference(g_controller_interface, @@ -637,7 +638,7 @@ void InputConfigDialog::ConfigControl(wxEvent& event) void InputConfigDialog::ClearControl(wxEvent& event) { ControlButton* const btn = (ControlButton*)event.GetEventObject(); - btn->control_reference->expression.clear(); + btn->control_reference->SetExpression(""); btn->control_reference->range = 1.0; controller->UpdateReferences(g_controller_interface); @@ -716,7 +717,7 @@ bool InputConfigDialog::DetectButton(ControlButton* button) wxString control_name = ctrl->GetName(); wxString expr; GetExpressionForControl(expr, control_name); - button->control_reference->expression = expr; + button->control_reference->SetExpression(WxStrToStr(expr)); const auto lock = ControllerEmu::EmulatedController::GetStateLock(); button->control_reference->UpdateReference(g_controller_interface, controller->default_device); diff --git a/Source/Core/InputCommon/ControlReference/ControlReference.cpp b/Source/Core/InputCommon/ControlReference/ControlReference.cpp index e4162e22a7..c7d652f15b 100644 --- a/Source/Core/InputCommon/ControlReference/ControlReference.cpp +++ b/Source/Core/InputCommon/ControlReference/ControlReference.cpp @@ -25,21 +25,20 @@ bool ControlReference::InputGateOn() // UpdateReference // // Updates a controlreference's binded devices/controls -// need to call this to re-parse a control reference's expression after changing it +// need to call this to re-bind a control reference after changing its expression // void ControlReference::UpdateReference(const ciface::Core::DeviceContainer& devices, const ciface::Core::DeviceQualifier& default_device) { - Expression* expr; ControlFinder finder(devices, default_device, IsInput()); - m_parse_status = ParseExpression(expression, finder, &expr); - m_parsed_expression.reset(expr); + if (m_parsed_expression) + m_parsed_expression->UpdateReferences(finder); } int ControlReference::BoundCount() const { if (m_parsed_expression) - return m_parsed_expression->num_controls; + return m_parsed_expression->CountNumControls(); else return 0; } @@ -49,6 +48,17 @@ ParseStatus ControlReference::GetParseStatus() const return m_parse_status; } +std::string ControlReference::GetExpression() const +{ + return m_expression; +} + +void ControlReference::SetExpression(std::string expr) +{ + m_expression = std::move(expr); + std::tie(m_parse_status, m_parsed_expression) = ParseExpression(m_expression); +} + ControlReference::ControlReference() : range(1), m_parsed_expression(nullptr) { } diff --git a/Source/Core/InputCommon/ControlReference/ControlReference.h b/Source/Core/InputCommon/ControlReference/ControlReference.h index 48ce6434e1..6740ed8be0 100644 --- a/Source/Core/InputCommon/ControlReference/ControlReference.h +++ b/Source/Core/InputCommon/ControlReference/ControlReference.h @@ -34,12 +34,14 @@ public: ciface::ExpressionParser::ParseStatus GetParseStatus() const; void UpdateReference(const ciface::Core::DeviceContainer& devices, const ciface::Core::DeviceQualifier& default_device); + std::string GetExpression() const; + void SetExpression(std::string expr); ControlState range; - std::string expression; protected: ControlReference(); + std::string m_expression; std::unique_ptr m_parsed_expression; ciface::ExpressionParser::ParseStatus m_parse_status; }; diff --git a/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp b/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp index d520015cf3..85eb86d598 100644 --- a/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp +++ b/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp @@ -10,6 +10,7 @@ #include #include +#include "Common/StringUtil.h" #include "InputCommon/ControlReference/ExpressionParser.h" using namespace ciface::Core; @@ -207,64 +208,42 @@ public: } }; -class ExpressionNode -{ -public: - virtual ~ExpressionNode() {} - virtual ControlState GetValue() const { return 0; } - virtual void SetValue(ControlState state) {} - virtual int CountNumControls() const { return 0; } - virtual operator std::string() const { return ""; } -}; - -class DummyExpression : public ExpressionNode -{ -public: - std::string name; - - DummyExpression(const std::string& name_) : name(name_) {} - ControlState GetValue() const override { return 0.0; } - void SetValue(ControlState value) override {} - int CountNumControls() const override { return 0; } - operator std::string() const override { return "`" + name + "`"; } -}; - -class ControlExpression : public ExpressionNode +class ControlExpression : public Expression { public: ControlQualifier qualifier; - Device::Control* control; - - ControlExpression(ControlQualifier qualifier_, std::shared_ptr device, - Device::Control* control_) - : qualifier(qualifier_), control(control_), m_device(device) - { - } - - ControlState GetValue() const override { return control->ToInput()->GetState(); } - void SetValue(ControlState value) override { control->ToOutput()->SetState(value); } - int CountNumControls() const override { return 1; } - operator std::string() const override { return "`" + (std::string)qualifier + "`"; } -private: + Device::Control* control = nullptr; + // Keep a shared_ptr to the device so the control pointer doesn't become invalid std::shared_ptr m_device; + + explicit ControlExpression(ControlQualifier qualifier_) : qualifier(qualifier_) {} + ControlState GetValue() const override { return control ? control->ToInput()->GetState() : 0.0; } + void SetValue(ControlState value) override + { + if (control) + control->ToOutput()->SetState(value); + } + int CountNumControls() const override { return control ? 1 : 0; } + void UpdateReferences(ControlFinder& finder) override + { + m_device = finder.FindDevice(qualifier); + control = finder.FindControl(qualifier); + } + operator std::string() const override { return "`" + static_cast(qualifier) + "`"; } }; -class BinaryExpression : public ExpressionNode +class BinaryExpression : public Expression { public: TokenType op; - ExpressionNode* lhs; - ExpressionNode* rhs; + std::unique_ptr lhs; + std::unique_ptr rhs; - BinaryExpression(TokenType op_, ExpressionNode* lhs_, ExpressionNode* rhs_) - : op(op_), lhs(lhs_), rhs(rhs_) + BinaryExpression(TokenType op_, std::unique_ptr&& lhs_, + std::unique_ptr&& rhs_) + : op(op_), lhs(std::move(lhs_)), rhs(std::move(rhs_)) { } - virtual ~BinaryExpression() - { - delete lhs; - delete rhs; - } ControlState GetValue() const override { @@ -297,20 +276,28 @@ public: return lhs->CountNumControls() + rhs->CountNumControls(); } + void UpdateReferences(ControlFinder& finder) override + { + lhs->UpdateReferences(finder); + rhs->UpdateReferences(finder); + } + operator std::string() const override { return OpName(op) + "(" + (std::string)(*lhs) + ", " + (std::string)(*rhs) + ")"; } }; -class UnaryExpression : public ExpressionNode +class UnaryExpression : public Expression { public: TokenType op; - ExpressionNode* inner; + std::unique_ptr inner; - UnaryExpression(TokenType op_, ExpressionNode* inner_) : op(op_), inner(inner_) {} - virtual ~UnaryExpression() { delete inner; } + UnaryExpression(TokenType op_, std::unique_ptr&& inner_) + : op(op_), inner(std::move(inner_)) + { + } ControlState GetValue() const override { ControlState value = inner->GetValue(); @@ -338,9 +325,50 @@ public: } int CountNumControls() const override { return inner->CountNumControls(); } + void UpdateReferences(ControlFinder& finder) override { inner->UpdateReferences(finder); } operator std::string() const override { return OpName(op) + "(" + (std::string)(*inner) + ")"; } }; +// This class proxies all methods to its either left-hand child if it has bound controls, or its +// right-hand child. Its intended use is for supporting old-style barewords expressions. +class CoalesceExpression : public Expression +{ +public: + CoalesceExpression(std::unique_ptr&& lhs, std::unique_ptr&& rhs) + : m_lhs(std::move(lhs)), m_rhs(std::move(rhs)) + { + } + + ControlState GetValue() const override { return GetActiveChild()->GetValue(); } + void SetValue(ControlState value) override + { + m_lhs->SetValue(GetActiveChild() == m_lhs ? value : 0.0); + m_rhs->SetValue(GetActiveChild() == m_rhs ? value : 0.0); + } + + int CountNumControls() const override { return GetActiveChild()->CountNumControls(); } + operator std::string() const override + { + return "Coalesce(" + static_cast(*m_lhs) + ", " + + static_cast(*m_rhs) + ')'; + } + + void UpdateReferences(ControlFinder& finder) override + { + m_lhs->UpdateReferences(finder); + m_rhs->UpdateReferences(finder); + } + +private: + const std::unique_ptr& GetActiveChild() const + { + return m_lhs->CountNumControls() > 0 ? m_lhs : m_rhs; + } + + std::unique_ptr m_lhs; + std::unique_ptr m_rhs; +}; + std::shared_ptr ControlFinder::FindDevice(ControlQualifier qualifier) const { if (qualifier.has_device) @@ -361,29 +389,25 @@ Device::Control* ControlFinder::FindControl(ControlQualifier qualifier) const return device->FindOutput(qualifier.control_name); } +struct ParseResult +{ + ParseResult(ParseStatus status_, std::unique_ptr&& expr_ = {}) + : status(status_), expr(std::move(expr_)) + { + } + + ParseStatus status; + std::unique_ptr expr; +}; + class Parser { public: - Parser(std::vector tokens_, ControlFinder& finder_) : tokens(tokens_), finder(finder_) - { - m_it = tokens.begin(); - } - - ParseStatus Parse(Expression** expr_out) - { - ExpressionNode* node; - ParseStatus status = Toplevel(&node); - if (status != ParseStatus::Successful) - return status; - - *expr_out = new Expression(node); - return ParseStatus::Successful; - } - + explicit Parser(std::vector tokens_) : tokens(tokens_) { m_it = tokens.begin(); } + ParseResult Parse() { return Toplevel(); } private: std::vector tokens; std::vector::iterator m_it; - ControlFinder& finder; Token Chew() { return *m_it++; } Token Peek() { return *m_it; } @@ -393,28 +417,17 @@ private: return tok.type == type; } - ParseStatus Atom(ExpressionNode** expr_out) + ParseResult Atom() { Token tok = Chew(); switch (tok.type) { case TOK_CONTROL: - { - std::shared_ptr device = finder.FindDevice(tok.qualifier); - Device::Control* control = finder.FindControl(tok.qualifier); - if (control == nullptr) - { - *expr_out = new DummyExpression(tok.qualifier); - return ParseStatus::NoDevice; - } - - *expr_out = new ControlExpression(tok.qualifier, device, control); - return ParseStatus::Successful; - } + return {ParseStatus::Successful, std::make_unique(tok.qualifier)}; case TOK_LPAREN: - return Paren(expr_out); + return Paren(); default: - return ParseStatus::SyntaxError; + return {ParseStatus::SyntaxError}; } } @@ -429,20 +442,19 @@ private: } } - ParseStatus Unary(ExpressionNode** expr_out) + ParseResult Unary() { if (IsUnaryExpression(Peek().type)) { Token tok = Chew(); - ExpressionNode* atom_expr; - ParseStatus status = Atom(&atom_expr); - if (status == ParseStatus::SyntaxError) - return status; - *expr_out = new UnaryExpression(tok.type, atom_expr); - return ParseStatus::Successful; + ParseResult result = Atom(); + if (result.status == ParseStatus::SyntaxError) + return result; + return {ParseStatus::Successful, + std::make_unique(tok.type, std::move(result.expr))}; } - return Atom(expr_out); + return Atom(); } bool IsBinaryToken(TokenType type) @@ -458,113 +470,83 @@ private: } } - ParseStatus Binary(ExpressionNode** expr_out) + ParseResult Binary() { - ParseStatus status = Unary(expr_out); - if (status == ParseStatus::SyntaxError) - return status; + ParseResult result = Unary(); + if (result.status == ParseStatus::SyntaxError) + return result; + std::unique_ptr expr = std::move(result.expr); while (IsBinaryToken(Peek().type)) { Token tok = Chew(); - ExpressionNode* unary_expr; - status = Unary(&unary_expr); - if (status == ParseStatus::SyntaxError) + ParseResult unary_result = Unary(); + if (unary_result.status == ParseStatus::SyntaxError) { - delete *expr_out; - return status; + return unary_result; } - *expr_out = new BinaryExpression(tok.type, *expr_out, unary_expr); + expr = std::make_unique(tok.type, std::move(expr), + std::move(unary_result.expr)); } - return ParseStatus::Successful; + return {ParseStatus::Successful, std::move(expr)}; } - ParseStatus Paren(ExpressionNode** expr_out) + ParseResult Paren() { - ParseStatus status; - // lparen already chewed - if ((status = Toplevel(expr_out)) != ParseStatus::Successful) - return status; + ParseResult result = Toplevel(); + if (result.status != ParseStatus::Successful) + return result; if (!Expects(TOK_RPAREN)) { - delete *expr_out; - return ParseStatus::SyntaxError; + return {ParseStatus::SyntaxError}; } - return ParseStatus::Successful; + return result; } - ParseStatus Toplevel(ExpressionNode** expr_out) { return Binary(expr_out); } + ParseResult Toplevel() { return Binary(); } }; -ControlState Expression::GetValue() const +static ParseResult ParseComplexExpression(const std::string& str) { - return node->GetValue(); -} - -void Expression::SetValue(ControlState value) -{ - node->SetValue(value); -} - -Expression::Expression(ExpressionNode* node_) -{ - node = node_; - num_controls = node->CountNumControls(); -} - -Expression::~Expression() -{ - delete node; -} - -static ParseStatus ParseExpressionInner(const std::string& str, ControlFinder& finder, - Expression** expr_out) -{ - ParseStatus status; - Expression* expr; - *expr_out = nullptr; - - if (str == "") - return ParseStatus::Successful; - Lexer l(str); std::vector tokens; - status = l.Tokenize(tokens); - if (status != ParseStatus::Successful) - return status; + ParseStatus tokenize_status = l.Tokenize(tokens); + if (tokenize_status != ParseStatus::Successful) + return {tokenize_status}; - Parser p(tokens, finder); - status = p.Parse(&expr); - if (status != ParseStatus::Successful) - return status; - - *expr_out = expr; - return ParseStatus::Successful; + return Parser(std::move(tokens)).Parse(); } -ParseStatus ParseExpression(const std::string& str, ControlFinder& finder, Expression** expr_out) +static std::unique_ptr ParseBarewordExpression(const std::string& str) { - // Add compatibility with old simple expressions, which are simple - // barewords control names. - ControlQualifier qualifier; qualifier.control_name = str; qualifier.has_device = false; - std::shared_ptr device = finder.FindDevice(qualifier); - Device::Control* control = finder.FindControl(qualifier); - if (control) + return std::make_unique(qualifier); +} + +std::pair> ParseExpression(const std::string& str) +{ + if (StripSpaces(str).empty()) + return std::make_pair(ParseStatus::EmptyExpression, nullptr); + + auto bareword_expr = ParseBarewordExpression(str); + ParseResult complex_result = ParseComplexExpression(str); + + if (complex_result.status != ParseStatus::Successful) { - *expr_out = new Expression(new ControlExpression(qualifier, device, control)); - return ParseStatus::Successful; + return std::make_pair(complex_result.status, std::move(bareword_expr)); } - return ParseExpressionInner(str, finder, expr_out); + auto combined_expr = std::make_unique(std::move(bareword_expr), + std::move(complex_result.expr)); + return std::make_pair(complex_result.status, std::move(combined_expr)); } } } diff --git a/Source/Core/InputCommon/ControlReference/ExpressionParser.h b/Source/Core/InputCommon/ControlReference/ExpressionParser.h index f07c9a1326..398b273e0f 100644 --- a/Source/Core/InputCommon/ControlReference/ExpressionParser.h +++ b/Source/Core/InputCommon/ControlReference/ExpressionParser.h @@ -6,6 +6,7 @@ #include #include +#include #include "InputCommon/ControllerInterface/Device.h" namespace ciface @@ -46,26 +47,24 @@ private: bool is_input; }; -class ExpressionNode; class Expression { public: - Expression() : node(nullptr) {} - Expression(ExpressionNode* node); - ~Expression(); - ControlState GetValue() const; - void SetValue(ControlState state); - int num_controls; - ExpressionNode* node; + virtual ~Expression() = default; + virtual ControlState GetValue() const = 0; + virtual void SetValue(ControlState state) = 0; + virtual int CountNumControls() const = 0; + virtual void UpdateReferences(ControlFinder& finder) = 0; + virtual operator std::string() const = 0; }; enum class ParseStatus { Successful, SyntaxError, - NoDevice, + EmptyExpression, }; -ParseStatus ParseExpression(const std::string& expr, ControlFinder& finder, Expression** expr_out); +std::pair> ParseExpression(const std::string& expr); } } diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.cpp index fd905ccf1e..24d4a4c36e 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.cpp +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.cpp @@ -54,8 +54,12 @@ void ControlGroup::LoadConfig(IniFile::Section* sec, const std::string& defdev, for (auto& c : controls) { - // control expression - sec->Get(group + c->name, &c->control_ref->expression, ""); + { + // control expression + std::string expression; + sec->Get(group + c->name, &expression, ""); + c->control_ref->SetExpression(std::move(expression)); + } // range sec->Get(group + c->name + "/Range", &c->control_ref->range, 100.0); @@ -109,7 +113,7 @@ void ControlGroup::SaveConfig(IniFile::Section* sec, const std::string& defdev, for (auto& c : controls) { // control expression - sec->Set(group + c->name, c->control_ref->expression, ""); + sec->Set(group + c->name, c->control_ref->GetExpression(), ""); // range sec->Set(group + c->name + "/Range", c->control_ref->range * 100.0, 100.0); @@ -128,6 +132,6 @@ void ControlGroup::SaveConfig(IniFile::Section* sec, const std::string& defdev, void ControlGroup::SetControlExpression(int index, const std::string& expression) { - controls.at(index)->control_ref->expression = expression; + controls.at(index)->control_ref->SetExpression(expression); } } // namespace ControllerEmu