| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- #pragma once
- #include <string>
- #include <vector>
- #include <map>
- #include <memory>
- #include <functional>
- #include <chrono>
- #include <optional>
- namespace lumacs {
- /// Represents a single key in a key sequence
- struct Key {
- std::string name; // Key name like "C-x", "M-f", "a", "Return"
- bool ctrl = false; // Ctrl modifier
- bool meta = false; // Meta/Alt modifier
- bool shift = false; // Shift modifier
-
- Key() = default;
- explicit Key(const std::string& key_name);
-
- /// Parse a key string like "C-x" into Key structure
- static Key parse(const std::string& key_str);
-
- /// Convert Key back to string representation
- std::string to_string() const;
-
- bool operator==(const Key& other) const;
- bool operator<(const Key& other) const;
- };
- /// Represents a sequence of keys like ["C-x", "2"] for "C-x 2"
- class KeySequence {
- public:
- KeySequence() = default;
- explicit KeySequence(const std::vector<Key>& keys);
- explicit KeySequence(const std::string& key_sequence_str);
-
- /// Add a key to the sequence
- void add_key(const Key& key);
- void add_key(const std::string& key_str);
-
- /// Get the keys in this sequence
- const std::vector<Key>& keys() const { return keys_; }
-
- /// Check if this sequence is empty
- bool empty() const { return keys_.empty(); }
-
- /// Get the length of the sequence
- size_t length() const { return keys_.size(); }
-
- /// Check if this sequence is a prefix of another sequence
- bool is_prefix_of(const KeySequence& other) const;
-
- /// Check if this sequence has the given sequence as a prefix
- bool has_prefix(const KeySequence& prefix) const;
-
- /// Get string representation like "C-x 2"
- std::string to_string() const;
-
- /// Clear the sequence
- void clear();
-
- /// 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_;
- };
- /// Function type for key binding callbacks
- using KeyBindingFunction = std::function<bool()>;
- /// Represents a key binding with its associated function
- struct KeyBinding {
- KeySequence sequence;
- KeyBindingFunction function;
- std::string description; // Human-readable description
-
- KeyBinding() = default;
- KeyBinding(const KeySequence& seq, KeyBindingFunction func, std::string desc = "");
- KeyBinding(const std::string& key_str, KeyBindingFunction func, std::string desc = "");
- };
- /// 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
- };
- /// Central manager for all key bindings
- class KeyBindingManager {
- public:
- KeyBindingManager();
- ~KeyBindingManager() = default;
-
- /// Bind a key sequence to a function
- void bind(const KeySequence& sequence, KeyBindingFunction function, const std::string& description = "");
- void bind(const std::string& key_str, KeyBindingFunction function, const std::string& description = "");
-
- /// Unbind a key sequence
- void unbind(const KeySequence& sequence);
- void unbind(const std::string& key_str);
-
- /// Process a single key press
- KeyResult process_key(const Key& key);
- KeyResult process_key(const std::string& key_str);
-
- /// Check if a sequence has any bindings (exact or partial)
- bool has_binding(const KeySequence& sequence) const;
- bool has_exact_binding(const KeySequence& sequence) const;
- bool has_prefix_bindings(const KeySequence& sequence) const;
-
- /// Clear current partial sequence (e.g., on timeout or escape)
- void clear_partial_sequence();
-
- /// Get current partial sequence for display purposes
- const KeySequence& current_partial_sequence() const { return current_sequence_; }
-
- /// Check if we're currently building a multi-key sequence
- bool is_building_sequence() const;
-
- /// Get string representation of current sequence for display
- std::string current_sequence_display() const;
-
- /// Get all registered bindings (for debugging/help)
- std::vector<KeyBinding> get_all_bindings() const;
-
- /// Set timeout for multi-key sequences (in milliseconds)
- void set_sequence_timeout(std::chrono::milliseconds timeout);
-
- /// Check if current partial sequence has timed out
- bool has_sequence_timed_out() const;
- private:
- /// Map from key sequences to their bindings
- std::map<KeySequence, KeyBinding> bindings_;
-
- /// Current partial key sequence being built
- KeySequence current_sequence_;
-
- /// Timestamp of when current sequence started
- std::chrono::steady_clock::time_point sequence_start_time_;
-
- /// Timeout for partial sequences
- std::chrono::milliseconds sequence_timeout_;
-
- /// Find exact binding for a sequence
- std::optional<KeyBinding> find_exact_binding(const KeySequence& sequence) const;
-
- /// Check if sequence has any prefix bindings
- bool has_prefix_bindings_impl(const KeySequence& sequence) const;
- };
- } // namespace lumacs
|