Files
FWS-ISO/configs/releng/airootfs/usr/local/bin/fws-hypr-keys
T
nocode d6212deaa9 feat(fws-hypr-keys): add optional style support and adjust wofi dimensions
- Import os module to check for style file existence
- Add _STYLE constant pointing to wofi-keys.css stylesheet
- Increase wofi window dimensions from 780x560 to 820x600
- Conditionally apply custom style if the stylesheet exists
- Refactor wofi command construction for better readability
2026-07-04 00:25:45 +02:00

102 lines
3.0 KiB
Python
Executable File

#!/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 os
import subprocess
import sys
_STYLE = "/usr/local/share/fws/wofi-keys.css"
# 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.
cmd = ["wofi", "--dmenu", "--prompt", "Raccourcis clavier — taper pour filtrer",
"--width", "820", "--height", "600", "--insensitive",
"--cache-file", "/dev/null"]
if os.path.exists(_STYLE):
# Style dédié : monospace (colonnes alignées) + palette FWS.
cmd += ["--style", _STYLE]
subprocess.run(cmd, input="\n".join(lines), text=True, check=False)
return 0
if __name__ == "__main__":
sys.exit(main())