diff --git a/configs/releng/airootfs/usr/local/bin/fws-hypr-keys b/configs/releng/airootfs/usr/local/bin/fws-hypr-keys new file mode 100755 index 0000000..e8c5453 --- /dev/null +++ b/configs/releng/airootfs/usr/local/bin/fws-hypr-keys @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 +# FWS — affiche les raccourcis clavier RÉELS de Hyprland. +# +# Source de vérité : « hyprctl binds -j » = les binds effectivement CHARGÉS +# par le compositeur (ceux de ~/.config/hypr/hyprland.conf, y compris ceux +# ajoutés par l'utilisateur après l'installation). Les descriptions viennent +# des « bindd » de la config ; un bind sans description affiche son action +# brute (dispatcher + argument). Affichage : wofi en mode dmenu (recherche +# incrémentale intégrée) — déclenché par le bouton ⌨ de la waybar ou SUPER+K. +# +# python3 et wofi sont déjà sur le système (image FWS + paquets Hyprland) : +# aucune dépendance supplémentaire. + +import json +import subprocess +import sys + +# Bits de modmask (masques X11) dans l'ordre d'affichage voulu. +_MODS = [ + (64, "SUPER"), + (4, "CTRL"), + (8, "ALT"), + (1, "SHIFT"), +] + +# Libellés humains pour les « touches » spéciales. +_KEY_LABELS = { + "mouse:272": "clic gauche", + "mouse:273": "clic droit", + "mouse:274": "clic molette", + "mouse_down": "molette bas", + "mouse_up": "molette haut", + "return": "Entrée", + "space": "Espace", + "escape": "Échap", + "tab": "Tab", + "left": "←", + "right": "→", + "up": "↑", + "down": "↓", +} + + +def _mods(mask): + return [name for bit, name in _MODS if mask & bit] + + +def _combo(bind): + parts = _mods(bind.get("modmask", 0)) + key = bind.get("key") or "" + if not key and bind.get("keycode"): + key = f"code {bind['keycode']}" + parts.append(_KEY_LABELS.get(key.lower(), key)) + return " + ".join(p for p in parts if p) + + +def _action(bind): + desc = (bind.get("description") or "").strip() + if desc: + return desc + arg = (bind.get("arg") or "").strip() + return f"{bind.get('dispatcher', '?')} {arg}".strip() + + +def main(): + try: + raw = subprocess.check_output(["hyprctl", "binds", "-j"], text=True) + binds = json.loads(raw) + except (OSError, subprocess.CalledProcessError, ValueError) as exc: + subprocess.run(["notify-send", "Raccourcis FWS", + f"hyprctl binds a échoué : {exc}"], check=False) + return 1 + + lines = [] + seen = set() + for bind in binds: + combo = _combo(bind) + if not combo or combo in seen: # binde répétés (resize) : une ligne + continue + seen.add(combo) + lines.append(f"{combo:<24} {_action(bind)}") + + if not lines: + lines = ["(aucun raccourci déclaré)"] + + # dmenu = liste + filtre incrémental ; la sélection n'a pas d'effet. + subprocess.run( + ["wofi", "--dmenu", "--prompt", "Raccourcis clavier — taper pour filtrer", + "--width", "780", "--height", "560", "--insensitive", "--cache-file", "/dev/null"], + input="\n".join(lines), text=True, check=False) + return 0 + + +if __name__ == "__main__": + sys.exit(main())