From 52547379c99f290118641f29168cfae5cc94db51 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Tue, 22 Oct 2019 19:12:55 -0500 Subject: [PATCH] ExpressionParser: Add Hotkey syntax. --- .../ControlReference/ExpressionParser.cpp | 97 +++++++++++++++++++ .../ControlReference/ExpressionParser.h | 1 + 2 files changed, 98 insertions(+) diff --git a/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp b/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp index 1b1a24753c..0533b88a16 100644 --- a/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp +++ b/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include #include #include #include @@ -112,6 +113,8 @@ Token Lexer::NextToken() return Token(TOK_LPAREN); case ')': return Token(TOK_RPAREN); + case '@': + return Token(TOK_HOTKEY); case '&': return Token(TOK_AND); case '|': @@ -374,6 +377,63 @@ protected: ControlState* m_value_ptr{}; }; +class HotkeyExpression : public Expression +{ +public: + HotkeyExpression(std::vector> inputs) + : m_inputs(std::move(inputs)) + { + } + + ControlState GetValue() const override + { + if (m_inputs.empty()) + return 0; + + const bool modifiers_pressed = std::all_of(m_inputs.begin(), std::prev(m_inputs.end()), + [](const std::unique_ptr& input) { + // TODO: kill magic number. + return input->GetValue() > 0.5; + }); + + if (modifiers_pressed) + { + // TODO: kill magic number. + const bool final_input_pressed = (**m_inputs.rbegin()).GetValue() > 0.5; + + if (m_is_ready) + return final_input_pressed; + + if (!final_input_pressed) + m_is_ready = true; + } + else + m_is_ready = false; + + return 0; + } + + void SetValue(ControlState) override {} + + int CountNumControls() const override + { + int result = 0; + for (auto& input : m_inputs) + result += input->CountNumControls(); + return result; + } + + void UpdateReferences(ControlEnvironment& env) override + { + for (auto& input : m_inputs) + input->UpdateReferences(env); + } + +private: + std::vector> m_inputs; + mutable bool m_is_ready = false; +}; + // 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 @@ -600,6 +660,10 @@ private: { return ParseParens(); } + case TOK_HOTKEY: + { + return ParseHotkeys(); + } case TOK_SUB: { // An atom was expected but we got a subtraction symbol. @@ -684,6 +748,39 @@ private: return result; } + ParseResult ParseHotkeys() + { + Token tok = Chew(); + if (tok.type != TOK_LPAREN) + return ParseResult::MakeErrorResult(tok, _trans("Expected opening paren.")); + + std::vector> inputs; + + while (true) + { + tok = Chew(); + + if (tok.type != TOK_CONTROL && tok.type != TOK_BAREWORD) + return ParseResult::MakeErrorResult(tok, _trans("Expected name of input.")); + + ControlQualifier cq; + cq.FromString(tok.data); + inputs.emplace_back(std::make_unique(std::move(cq))); + + tok = Chew(); + + if (tok.type == TOK_ADD) + continue; + + if (tok.type == TOK_RPAREN) + break; + + return ParseResult::MakeErrorResult(tok, _trans("Expected + or closing paren.")); + } + + return ParseResult::MakeSuccessfulResult(std::make_unique(std::move(inputs))); + } + ParseResult ParseToplevel() { return ParseBinary(); } }; // namespace ExpressionParser diff --git a/Source/Core/InputCommon/ControlReference/ExpressionParser.h b/Source/Core/InputCommon/ControlReference/ExpressionParser.h index c0d807bf17..a879528d4b 100644 --- a/Source/Core/InputCommon/ControlReference/ExpressionParser.h +++ b/Source/Core/InputCommon/ControlReference/ExpressionParser.h @@ -26,6 +26,7 @@ enum TokenType TOK_VARIABLE, TOK_BAREWORD, TOK_COMMENT, + TOK_HOTKEY, // Binary Ops: TOK_BINARY_OPS_BEGIN, TOK_AND = TOK_BINARY_OPS_BEGIN,