ui: modifier chord support in the keybind registry
This commit is contained in:
parent
8642f6fe12
commit
66c42a571c
2 changed files with 66 additions and 9 deletions
|
|
@ -57,7 +57,9 @@ std::string VirtualKeyToString(VirtualKey vk);
|
|||
* binding is visible in the settings overlay and persisted to config.
|
||||
*
|
||||
* @param name CVAR name for this bind (e.g. "bind_console").
|
||||
* @param default_key Default key name (e.g. "Backtick", "F3").
|
||||
* @param default_key Default key spec: a key name (e.g. "Backtick", "F3")
|
||||
* or a modifier chord "Mod+...+Key" (e.g. "Ctrl+Shift+B";
|
||||
* modifiers are Ctrl/Control, Shift, Alt, Super/Win).
|
||||
* @param description Human-readable description for the settings UI.
|
||||
* @param callback Function to invoke when the bound key is pressed.
|
||||
*/
|
||||
|
|
@ -73,9 +75,11 @@ void UnregisterBind(std::string_view name);
|
|||
/**
|
||||
* Process a key-down event against all registered binds.
|
||||
*
|
||||
* Looks up each bind's current key from its CVAR, parses it, and compares
|
||||
* against the event's virtual key. If a match is found, the bind's callback
|
||||
* is invoked and the event is marked as handled.
|
||||
* Looks up each bind's current key spec from its CVAR, parses it, and
|
||||
* compares against the event's virtual key. Chord specs ("Ctrl+Shift+B")
|
||||
* additionally require the event's modifier state to match exactly; plain
|
||||
* single-key specs fire regardless of held modifiers. If a match is found,
|
||||
* the bind's callback is invoked and the event is marked as handled.
|
||||
*
|
||||
* @param e The key event to process.
|
||||
* @return True if a bind matched and the event was consumed.
|
||||
|
|
|
|||
|
|
@ -163,6 +163,49 @@ std::string VirtualKeyToString(VirtualKey vk) {
|
|||
return {};
|
||||
}
|
||||
|
||||
/* ---- Chord parsing ---- */
|
||||
|
||||
/* A key spec is either a single key name ("Home", "F3") or a chord of
|
||||
modifier names joined to a final key with '+' ("Ctrl+Shift+B",
|
||||
"Alt+NumpadPlus"). The last token is always the main key; every earlier
|
||||
token must be a modifier name (Ctrl/Control, Shift, Alt, Super/Win). */
|
||||
struct KeyChord {
|
||||
VirtualKey key = VirtualKey::kNone;
|
||||
bool shift = false;
|
||||
bool ctrl = false;
|
||||
bool alt = false;
|
||||
bool super_key = false;
|
||||
bool has_modifiers() const { return shift || ctrl || alt || super_key; }
|
||||
};
|
||||
|
||||
static KeyChord ParseKeyChord(std::string_view spec) {
|
||||
KeyChord chord;
|
||||
size_t pos = 0;
|
||||
while (true) {
|
||||
const size_t plus = spec.find('+', pos);
|
||||
if (plus == std::string_view::npos) {
|
||||
chord.key = ParseVirtualKey(spec.substr(pos));
|
||||
return chord;
|
||||
}
|
||||
const std::string_view token = spec.substr(pos, plus - pos);
|
||||
if (token == "Ctrl" || token == "Control") {
|
||||
chord.ctrl = true;
|
||||
} else if (token == "Shift") {
|
||||
chord.shift = true;
|
||||
} else if (token == "Alt") {
|
||||
chord.alt = true;
|
||||
} else if (token == "Super" || token == "Win") {
|
||||
chord.super_key = true;
|
||||
} else {
|
||||
/* Unknown modifier name: treat the whole spec as invalid rather than
|
||||
silently binding the trailing key. */
|
||||
chord.key = VirtualKey::kNone;
|
||||
return chord;
|
||||
}
|
||||
pos = plus + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- Bind registry ---- */
|
||||
|
||||
struct BindEntry {
|
||||
|
|
@ -219,13 +262,23 @@ bool ProcessKeyEvent(KeyEvent& e) {
|
|||
for (auto& entry : g_binds) {
|
||||
if (!entry.callback)
|
||||
continue;
|
||||
VirtualKey vk = ParseVirtualKey(entry.current_key);
|
||||
if (vk != VirtualKey::kNone && e.virtual_key() == vk) {
|
||||
const KeyChord chord = ParseKeyChord(entry.current_key);
|
||||
if (chord.key == VirtualKey::kNone || e.virtual_key() != chord.key)
|
||||
continue;
|
||||
/* Chord binds require the exact modifier set. Plain binds keep firing
|
||||
regardless of held modifiers, so a bind like "End" still works while
|
||||
Shift/Ctrl are held for another purpose. */
|
||||
if (chord.has_modifiers() &&
|
||||
(e.is_shift_pressed() != chord.shift ||
|
||||
e.is_ctrl_pressed() != chord.ctrl ||
|
||||
e.is_alt_pressed() != chord.alt ||
|
||||
e.is_super_pressed() != chord.super_key)) {
|
||||
continue;
|
||||
}
|
||||
entry.callback();
|
||||
e.set_handled(true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue