keybinding.hpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. #pragma once
  2. #include <string>
  3. #include <vector>
  4. #include <map>
  5. #include <memory>
  6. #include <functional>
  7. #include <chrono>
  8. #include <optional>
  9. namespace lumacs {
  10. /// Represents a single key in a key sequence
  11. struct Key {
  12. std::string name; // Key name like "C-x", "M-f", "a", "Return"
  13. bool ctrl = false; // Ctrl modifier
  14. bool meta = false; // Meta/Alt modifier
  15. bool shift = false; // Shift modifier
  16. Key() = default;
  17. explicit Key(const std::string& key_name);
  18. /// Parse a key string like "C-x" into Key structure
  19. static Key parse(const std::string& key_str);
  20. /// Convert Key back to string representation
  21. std::string to_string() const;
  22. bool operator==(const Key& other) const;
  23. bool operator<(const Key& other) const;
  24. };
  25. /// Represents a sequence of keys like ["C-x", "2"] for "C-x 2"
  26. class KeySequence {
  27. public:
  28. KeySequence() = default;
  29. explicit KeySequence(const std::vector<Key>& keys);
  30. explicit KeySequence(const std::string& key_sequence_str);
  31. /// Add a key to the sequence
  32. void add_key(const Key& key);
  33. void add_key(const std::string& key_str);
  34. /// Get the keys in this sequence
  35. const std::vector<Key>& keys() const { return keys_; }
  36. /// Check if this sequence is empty
  37. bool empty() const { return keys_.empty(); }
  38. /// Get the length of the sequence
  39. size_t length() const { return keys_.size(); }
  40. /// Check if this sequence is a prefix of another sequence
  41. bool is_prefix_of(const KeySequence& other) const;
  42. /// Check if this sequence has the given sequence as a prefix
  43. bool has_prefix(const KeySequence& prefix) const;
  44. /// Get string representation like "C-x 2"
  45. std::string to_string() const;
  46. /// Clear the sequence
  47. void clear();
  48. /// Get a subsequence starting from index
  49. KeySequence subsequence(size_t start_index) const;
  50. bool operator==(const KeySequence& other) const;
  51. bool operator<(const KeySequence& other) const;
  52. private:
  53. std::vector<Key> keys_;
  54. };
  55. /// Function type for key binding callbacks
  56. using KeyBindingFunction = std::function<bool()>;
  57. /// Represents a key binding with its associated function
  58. struct KeyBinding {
  59. KeySequence sequence;
  60. KeyBindingFunction function;
  61. std::string description; // Human-readable description
  62. KeyBinding() = default;
  63. KeyBinding(const KeySequence& seq, KeyBindingFunction func, std::string desc = "");
  64. KeyBinding(const std::string& key_str, KeyBindingFunction func, std::string desc = "");
  65. };
  66. /// Result of processing a key in the binding manager
  67. enum class KeyResult {
  68. Unbound, // No binding found, key not handled
  69. Executed, // Binding found and executed successfully
  70. Failed, // Binding found but execution failed
  71. Partial, // Key is part of a multi-key sequence, waiting for more keys
  72. Timeout // Partial sequence timed out
  73. };
  74. /// Central manager for all key bindings
  75. class KeyBindingManager {
  76. public:
  77. KeyBindingManager();
  78. ~KeyBindingManager() = default;
  79. /// Bind a key sequence to a function
  80. void bind(const KeySequence& sequence, KeyBindingFunction function, const std::string& description = "");
  81. void bind(const std::string& key_str, KeyBindingFunction function, const std::string& description = "");
  82. /// Unbind a key sequence
  83. void unbind(const KeySequence& sequence);
  84. void unbind(const std::string& key_str);
  85. /// Process a single key press
  86. KeyResult process_key(const Key& key);
  87. KeyResult process_key(const std::string& key_str);
  88. /// Check if a sequence has any bindings (exact or partial)
  89. bool has_binding(const KeySequence& sequence) const;
  90. bool has_exact_binding(const KeySequence& sequence) const;
  91. bool has_prefix_bindings(const KeySequence& sequence) const;
  92. /// Clear current partial sequence (e.g., on timeout or escape)
  93. void clear_partial_sequence();
  94. /// Get current partial sequence for display purposes
  95. const KeySequence& current_partial_sequence() const { return current_sequence_; }
  96. /// Check if we're currently building a multi-key sequence
  97. bool is_building_sequence() const;
  98. /// Get string representation of current sequence for display
  99. std::string current_sequence_display() const;
  100. /// Get all registered bindings (for debugging/help)
  101. std::vector<KeyBinding> get_all_bindings() const;
  102. /// Set timeout for multi-key sequences (in milliseconds)
  103. void set_sequence_timeout(std::chrono::milliseconds timeout);
  104. /// Check if current partial sequence has timed out
  105. bool has_sequence_timed_out() const;
  106. private:
  107. /// Map from key sequences to their bindings
  108. std::map<KeySequence, KeyBinding> bindings_;
  109. /// Current partial key sequence being built
  110. KeySequence current_sequence_;
  111. /// Timestamp of when current sequence started
  112. std::chrono::steady_clock::time_point sequence_start_time_;
  113. /// Timeout for partial sequences
  114. std::chrono::milliseconds sequence_timeout_;
  115. /// Find exact binding for a sequence
  116. std::optional<KeyBinding> find_exact_binding(const KeySequence& sequence) const;
  117. /// Check if sequence has any prefix bindings
  118. bool has_prefix_bindings_impl(const KeySequence& sequence) const;
  119. };
  120. } // namespace lumacs