| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- #pragma once
- #include <string>
- #include <vector>
- #include <map>
- #include <memory>
- #include <chrono>
- #include <optional>
- #include "lumacs/command_system.hpp" // Include the full definition of CommandResult
- // Forward declaration for CommandSystem
- namespace lumacs {
- class CommandSystem;
- }
- namespace lumacs {
- /// @brief Represents the base key (without modifiers).
- enum class BaseKey : uint16_t {
- Unknown = 0,
- A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
- D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, // Digits
- F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, // Function keys
- Space, Return, Tab, Escape, Backspace, Delete,
- ArrowUp, ArrowDown, ArrowLeft, ArrowRight,
- Home, End, PageUp, PageDown, Insert,
- Semicolon, Equal, Comma, Minus, Period, Slash, Backtick,
- LeftBracket, Backslash, RightBracket, Quote,
- NumLock, ScrollLock, PrintScreen, Pause,
- // Add more as needed
- };
- /// @brief Represents key modifiers as a bitmask.
- enum class Modifier : uint16_t {
- None = 0,
- Control = 1 << 0,
- Meta = 1 << 1, // Alt key, Option key
- Shift = 1 << 2,
- };
- /// @brief Represents a single key in a key sequence.
- struct Key {
- BaseKey base_key = BaseKey::Unknown;
- Modifier modifiers = Modifier::None;
-
- Key() = default;
- explicit Key(BaseKey bk, Modifier mods = Modifier::None) : base_key(bk), modifiers(mods) {}
- explicit Key(const std::string& key_name); // To be implemented in .cpp
-
- /// @brief Parse a key string like "C-x" or "M-S-a" into a Key structure.
- static Key parse(const std::string& key_str); // To be implemented in .cpp
- /// @brief Convert Key back to canonical string representation.
- std::string to_string() const; // To be implemented in .cpp
-
- bool operator==(const Key& other) const;
- bool operator<(const Key& other) const;
- };
- /// @brief Represents a sequence of keys (e.g., "C-x C-f").
- class KeySequence {
- public:
- KeySequence() = default;
- explicit KeySequence(const std::vector<Key>& keys);
- explicit KeySequence(const std::string& key_sequence_str);
-
- /// @brief Add a key to the sequence.
- void add_key(const Key& key);
- void add_key(const std::string& key_str);
-
- /// @brief Get the keys in this sequence.
- const std::vector<Key>& keys() const { return keys_; }
-
- /// @brief Check if this sequence is empty.
- bool empty() const { return keys_.empty(); }
-
- /// @brief Get the length of the sequence.
- size_t length() const { return keys_.size(); }
-
- /// @brief Check if this sequence is a prefix of another sequence.
- bool is_prefix_of(const KeySequence& other) const;
-
- /// @brief Check if this sequence has the given sequence as a prefix.
- bool has_prefix(const KeySequence& prefix) const;
-
- /// @brief Get string representation like "C-x 2".
- std::string to_string() const;
-
- /// @brief Clear the sequence.
- void clear();
-
- /// @brief Get a subsequence starting from index.
- KeySequence subsequence(size_t start_index) const;
-
- bool operator==(const KeySequence& other) const;
- bool operator<(const KeySequence& other) const;
- private:
- std::vector<Key> keys_;
- };
- /// @brief Represents a key binding with its associated function.
- struct KeyBinding {
- KeySequence sequence; ///< The key sequence that triggers this binding.
- std::string command_name; ///< The name of the command to execute.
- std::string description; ///< Human-readable description.
-
- KeyBinding() = default;
- KeyBinding(const KeySequence& seq, std::string cmd_name, std::string desc = "");
- KeyBinding(const std::string& key_str, std::string cmd_name, const std::string& description = "");
- };
- /// @brief Represents the result of processing a key in the binding manager.
- enum class KeyResult {
- Unbound, ///< No binding found, key not handled.
- Executed, ///< Binding found and executed successfully.
- Failed, ///< Binding found but execution failed.
- Partial, ///< Key is part of a multi-key sequence, waiting for more keys.
- Timeout ///< Partial sequence timed out.
- };
- /// @brief Detailed result of a key processing operation.
- struct KeyProcessingResult {
- KeyResult type;
- std::optional<CommandResult> command_result; // Relevant if type is Executed or Failed
- };
- /// @brief Central manager for all key bindings.
- ///
- /// Handles:
- /// - Registration of global key bindings.
- /// - Processing of key input (single and multi-key sequences).
- /// - Prefix key logic (e.g., C-x waiting for next key).
- class KeyBindingManager {
- public:
- KeyBindingManager(CommandSystem* command_system);
- ~KeyBindingManager() = default;
-
- /// @brief Bind a key sequence to a function.
- void bind(const KeySequence& sequence, std::string cmd_name, const std::string& description = "");
- void bind(const std::string& key_str, std::string cmd_name, const std::string& description = "");
-
- /// @brief Unbind a key sequence.
- void unbind(const KeySequence& sequence);
- void unbind(const std::string& key_str);
-
- /// @brief Process a single key press.
- /// @return Result indicating if key was bound, partial, etc.
- KeyProcessingResult process_key(const Key& key);
- KeyProcessingResult process_key(const std::string& key_str);
-
- /// @brief Check if a sequence has any bindings (exact or partial).
- bool has_binding(const KeySequence& sequence) const;
-
- /// @brief Check if a sequence has an exact binding.
- bool has_exact_binding(const KeySequence& sequence) const;
-
- /// @brief Check if a sequence is a prefix for other bindings.
- bool has_prefix_bindings(const KeySequence& sequence) const;
-
- /// @brief Clear current partial sequence (e.g., on timeout or escape).
- void clear_partial_sequence();
-
- /// @brief Get current partial sequence for display purposes.
- const KeySequence& current_partial_sequence() const { return current_sequence_; }
-
- /// @brief Check if we're currently building a multi-key sequence.
- bool is_building_sequence() const;
-
- /// @brief Get string representation of current sequence for display.
- std::string current_sequence_display() const;
-
- /// @brief Get all registered bindings (for debugging/help).
- std::vector<KeyBinding> get_all_bindings() const;
-
- /// @brief Set timeout for multi-key sequences.
- void set_sequence_timeout(std::chrono::milliseconds timeout);
- /// @brief Get timeout for multi-key sequences.
- [[nodiscard]] std::chrono::milliseconds get_sequence_timeout() const { return sequence_timeout_; }
- /// @brief Check if current partial sequence has timed out.
- bool has_sequence_timed_out() const;
- private:
- // Trie node structure
- struct TrieNode {
- std::optional<KeyBinding> binding; // Stores binding if this node represents the end of a sequence
- std::map<Key, std::unique_ptr<TrieNode>> children;
- int ref_count = 0; // Number of bindings passing through this node
- TrieNode() = default;
- // Prevent copying, allow moving
- TrieNode(const TrieNode&) = delete;
- TrieNode& operator=(const TrieNode&) = delete;
- TrieNode(TrieNode&&) noexcept = default;
- TrieNode& operator=(TrieNode&&) noexcept = default;
- };
-
- std::unique_ptr<TrieNode> root_; // Root of the trie
- KeySequence current_sequence_;
- std::chrono::steady_clock::time_point sequence_start_time_;
- std::chrono::milliseconds sequence_timeout_;
- CommandSystem* command_system_ = nullptr; // Dependency on CommandSystem
-
- // Helper function to find a node in the trie
- TrieNode* find_node(const KeySequence& sequence) const;
-
- // Helper to traverse trie and collect all bindings
- void collect_bindings(TrieNode* node, KeySequence current_prefix, std::vector<KeyBinding>& result) const;
- };
- } // namespace lumacs
|