Every bind in keybinds.lua now goes through a small wrapper that substitutes the chord from a stored override. Only the chord is taken from settings; the action is always the Lua value written in that file, so an override can move a shortcut but can never make one do something else. That is the property that makes reading them from a file the user can edit safe, and it is why the alternative -- storing dispatchers -- was not considered. Overrides are keyed by the shipped chord rather than the description. Keying by description moved every bind that shared one: rebinding SUPER+C also moved the XF86Calculator hardware key onto the same chord, silently costing it. Chords are unique; descriptions are not. Applying needs hyprctl reload rather than a live hl.bind. Hyprland reports Lua-defined binds with dispatcher "__lua" and a bytecode offset, so the action cannot be reconstructed from outside to re-bind it; reload re-runs the config, which re-reads the settings file. The capture control ignores modifier-only presses, because every chord passes through them and holding Super would otherwise be captured the moment the modifier went down. It refuses a bare letter, which would swallow ordinary typing, and refuses a key with no keysym name rather than storing something that would fail to bind. Rebinding onto a chord already in use is refused rather than shadowing the existing shortcut. The refactor was verified by snapshotting all 113 binds before and after: the keymap is byte-identical, and identical again after applying an override and resetting it. Claude-Session: https://claude.ai/code/session_01BRvzt4H8XXLPVH5MyYdk9L
51 lines
1.6 KiB
QML
51 lines
1.6 KiB
QML
import Quickshell
|
|
import Quickshell.Io
|
|
import QtQuick
|
|
|
|
import qs.config
|
|
import qs.services
|
|
|
|
ShellRoot {
|
|
IpcHandler {
|
|
target: "keybinds-test"
|
|
|
|
function rebind(current: string, next: string): bool {
|
|
return Keybinds.rebind(current, next);
|
|
}
|
|
|
|
function resetBind(current: string): void { Keybinds.resetBind(current); }
|
|
function resetAll(): void { Keybinds.resetAll(); }
|
|
|
|
function chordFor(description: string): string {
|
|
const found = Keybinds.binds.find(bind => bind.description === description);
|
|
return found ? found.luaChord : "";
|
|
}
|
|
|
|
function overrideState(): string {
|
|
return JSON.stringify({
|
|
overrides: Keybinds.overrides,
|
|
count: Object.keys(Keybinds.overrides).length
|
|
});
|
|
}
|
|
|
|
function status(): string {
|
|
const grouped = Keybinds.grouped();
|
|
let groupedCount = 0;
|
|
for (const group of grouped)
|
|
groupedCount += group.binds.length;
|
|
|
|
const superT = Keybinds.binds.find(bind => bind.description === "Terminal");
|
|
|
|
return JSON.stringify({
|
|
loaded: Keybinds.loaded,
|
|
count: Keybinds.binds.length,
|
|
groupedCount: groupedCount,
|
|
groups: grouped.map(group => group.name),
|
|
sample: superT ? superT.chord : "",
|
|
emptyDescriptions: Keybinds.binds.filter(bind => !bind.description).length,
|
|
lastError: Keybinds.lastError
|
|
});
|
|
}
|
|
}
|
|
}
|