keybinding.hpp 5.8 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. /// @brief Represents a single key in a key sequence.
  11. struct Key {
  12. std::string name; ///< Key name (e.g., "a", "Return", "F1").
  13. bool ctrl = false; ///< Ctrl modifier active.
  14. bool meta = false; ///< Meta/Alt modifier active.
  15. bool shift = false; ///< Shift modifier active.
  16. Key() = default;
  17. explicit Key(const std::string& key_name);
  18. /// @brief Parse a key string like "C-x" or "M-S-a" into a Key structure.
  19. static Key parse(const std::string& key_str);
  20. /// @brief Convert Key back to canonical string representation.
  21. std::string to_string() const;
  22. bool operator==(const Key& other) const;
  23. bool operator<(const Key& other) const;
  24. };
  25. /// @brief Represents a sequence of keys (e.g., "C-x C-f").
  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. /// @brief Add a key to the sequence.
  32. void add_key(const Key& key);
  33. void add_key(const std::string& key_str);
  34. /// @brief Get the keys in this sequence.
  35. const std::vector<Key>& keys() const { return keys_; }
  36. /// @brief Check if this sequence is empty.
  37. bool empty() const { return keys_.empty(); }
  38. /// @brief Get the length of the sequence.
  39. size_t length() const { return keys_.size(); }
  40. /// @brief Check if this sequence is a prefix of another sequence.
  41. bool is_prefix_of(const KeySequence& other) const;
  42. /// @brief Check if this sequence has the given sequence as a prefix.
  43. bool has_prefix(const KeySequence& prefix) const;
  44. /// @brief Get string representation like "C-x 2".
  45. std::string to_string() const;
  46. /// @brief Clear the sequence.
  47. void clear();
  48. /// @brief 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. /// @brief Function type for key binding callbacks.
  56. using KeyBindingFunction = std::function<bool()>;
  57. /// @brief Represents a key binding with its associated function.
  58. struct KeyBinding {
  59. KeySequence sequence; ///< The key sequence that triggers this binding.
  60. KeyBindingFunction function;///< The function to execute.
  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. /// @brief 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. /// @brief Central manager for all key bindings.
  75. ///
  76. /// Handles:
  77. /// - Registration of global key bindings.
  78. /// - Processing of key input (single and multi-key sequences).
  79. /// - Prefix key logic (e.g., C-x waiting for next key).
  80. class KeyBindingManager {
  81. public:
  82. KeyBindingManager();
  83. ~KeyBindingManager() = default;
  84. /// @brief Bind a key sequence to a function.
  85. void bind(const KeySequence& sequence, KeyBindingFunction function, const std::string& description = "");
  86. void bind(const std::string& key_str, KeyBindingFunction function, const std::string& description = "");
  87. /// @brief Unbind a key sequence.
  88. void unbind(const KeySequence& sequence);
  89. void unbind(const std::string& key_str);
  90. /// @brief Process a single key press.
  91. /// @return Result indicating if key was bound, partial, etc.
  92. KeyResult process_key(const Key& key);
  93. KeyResult process_key(const std::string& key_str);
  94. /// @brief Check if a sequence has any bindings (exact or partial).
  95. bool has_binding(const KeySequence& sequence) const;
  96. /// @brief Check if a sequence has an exact binding.
  97. bool has_exact_binding(const KeySequence& sequence) const;
  98. /// @brief Check if a sequence is a prefix for other bindings.
  99. bool has_prefix_bindings(const KeySequence& sequence) const;
  100. /// @brief Clear current partial sequence (e.g., on timeout or escape).
  101. void clear_partial_sequence();
  102. /// @brief Get current partial sequence for display purposes.
  103. const KeySequence& current_partial_sequence() const { return current_sequence_; }
  104. /// @brief Check if we're currently building a multi-key sequence.
  105. bool is_building_sequence() const;
  106. /// @brief Get string representation of current sequence for display.
  107. std::string current_sequence_display() const;
  108. /// @brief Get all registered bindings (for debugging/help).
  109. std::vector<KeyBinding> get_all_bindings() const;
  110. /// @brief Set timeout for multi-key sequences.
  111. void set_sequence_timeout(std::chrono::milliseconds timeout);
  112. /// @brief Check if current partial sequence has timed out.
  113. bool has_sequence_timed_out() const;
  114. private:
  115. std::map<KeySequence, KeyBinding> bindings_;
  116. KeySequence current_sequence_;
  117. std::chrono::steady_clock::time_point sequence_start_time_;
  118. std::chrono::milliseconds sequence_timeout_;
  119. std::optional<KeyBinding> find_exact_binding(const KeySequence& sequence) const;
  120. bool has_prefix_bindings_impl(const KeySequence& sequence) const;
  121. };
  122. } // namespace lumacs