J'ai une longue liste de modifications complexes de Karabiner et il est difficile de les suivre toutes, y compris les conflits, les applications exclues, etc. D'après ce que je peux comprendre, l'utilisateur est censé modifier ~/.config/karabiner/karabiner.json
manuellement. Cependant, cela n'est pas du tout pratique, car chaque définition de modification finit par être assez verbeuse et je ne peux voir que 1 à 2 à l'écran. Existe-t-il une méthode plus efficace que j'ignore ? Ou devrais-je simplement écrire mon propre programme pour générer le fichier karabiner.json
?
Réponses
Trop de publicités?Il y a un éditeur web simple ces jours-ci grâce à @genesy: https://genesy.github.io/karabiner-complex-rules-generator/
J'ai trouvé Goku (voir réponse de furins) et quelques autres outils mais aucun ne semblait plus facile que de modifier le JSON. Au final, j'ai écrit mes propres scripts que je partagerai ici.
Il y a deux fichiers Python :
decompose.py
prend un JSON karabiner et le divise en plusieurs fichiers et répertoires, de sorte que vous puissiez éditer une règle à la fois.compose.py
prend ces répertoires et les regroupe dans un seul JSON que karabiner acceptera.
Je garde à la fois le JSON unique et les répertoires décomposés (ainsi que le script) dans mon repo de dotfiles. Lorsque je veux modifier un raccourci, je crée un répertoire pour cela (la méthode la plus simple est de copier un existant et de le modifier) puis je fais un encodage/décodage en aller-retour. Ex. : python compose.py; python decompose.py; python compose.py
.
Après cela, ma première étape est de vérifier git diff
pour voir si ma nouvelle règle comporte une erreur qui a tout cassé. Si c'est le cas, j'ai de nombreuses options pour revenir en arrière via git
et réessayer. Une fois terminé, je teste le raccourci avec Karabiner-EventViewer et son cas d'utilisation prévu, puis je commit.
Les scripts sont évidemment limités et bricolés, car ils sont destinés à un usage personnel (et je pense que la "solution" appropriée à cela serait simplement de ne pas utiliser de Mac, har har). Je suggère de commencer avec un JSON connu fonctionnant tel que raccourcis de style PC pour voir comment les règles existantes fonctionnent. Ils fonctionnent raisonnablement bien, mais quelques inconvénients :
- Chaque règle va dans un répertoire. Le nom du répertoire est construit à partir d'un chiffre (pour éviter que les règles ne changent d'ordre et ne perturbent git) et du nom de la règle. Évidemment les noms de règles peuvent avoir des caractères spéciaux, mais les répertoires non, donc j'ai dû faire une normalisation un peu spéciale avec ça. Cela peut être un peu fragile si vous faites des choses sophistiquées avec le nom de la règle.
- J'utilise PyCharm qui a son propre intercepteur de raccourcis clavier. En raison de cela, toutes les règles sont mises sur liste noire de PyCharm à l'étape de composition/décomposition.
compose.py :
import json
from pathlib import Path
p_decomposed = Path('decomposed/')
# Load scaffold
p_scaffold = p_decomposed / 'scaffold.json'
with p_scaffold.open() as f:
scaffold = json.load(f)
# Load rules
p_rules = p_decomposed / 'rules'
for p_rule in sorted(p_rules.iterdir()):
if p_rule.stem.startswith('.'):
continue
print(p_rule)
p_rule_json = p_rule / 'rule.json'
with p_rule_json.open() as f:
rule = json.load(f)
p_manipulators = p_rule / 'manipulators'
for p_manipulator in sorted(p_manipulators.iterdir()):
with p_manipulator.open() as f:
j = json.load(f)
rule['manipulators'].append(j)
profiles = scaffold['profiles']
first_prof = profiles[0]
complex_mods = first_prof['complex_modifications']
rules = complex_mods['rules']
rules.append(rule)
p_composed = Path('karabiner.json')
with p_composed.open('w') as f:
json.dump(scaffold, f, indent=4)
decompose.py :
import json
from pathlib import Path
with open('karabiner.json') as f:
j = json.load(f)
profiles = j['profiles']
first_prof = profiles[0]
complex_mods = first_prof['complex_modifications']
rules = complex_mods['rules']
# Dump everything except the rules into a "scaffold file"
complex_mods['rules'] = []
with open('decomposed/scaffold.json', 'w') as f:
json.dump(j, f, indent=4)
def normalize_rule_name(raw_name):
"""
Normalize rule name by removing special characters, to make it suitable
for use as a file name.
"""
lowered = raw_name.lower()
filtered = ''
for c in lowered:
if c.isalnum():
filtered += c
else:
filtered += '-'
while '--' in filtered:
filtered = filtered.replace('--', '-')
if filtered.endswith('-'):
filtered = filtered[:-1]
return filtered
def blacklist_pycharm(manipulator):
pattern = "^com\\.jetbrains\\."
if 'conditions' not in manipulator:
return
for c in manipulator['conditions']:
if c.get('type', '') != 'frontmost_application_unless':
continue
if pattern not in c['bundle_identifiers']:
c['bundle_identifiers'].append(pattern)
def process_manipulator(manipulator):
"""
Gets applied to every manipulator before dumping it to a file.
"""
result = dict(manipulator)
blacklist_pycharm(result)
return result
# Dump each rule to a separate file
for n, rule in enumerate(rules):
# Normalize name
desc = rule['description']
desc_norm = normalize_rule_name(desc)
# Pull out manipulators and save the rest
manipulators = rule['manipulators']
rule['manipulators'] = []
p_rule = Path('decomposed/rules') / f'{n:03d}_{desc_norm}' / 'rule.json'
p_rule.parent.mkdir(exist_ok=True)
with p_rule.open('w') as f:
json.dump(rule, f, indent=4)
# Dump each manipulator
p_manipulators = p_rule.parent / 'manipulators'
p_manipulators.mkdir(exist_ok=True)
for i, manipulator in enumerate(manipulators):
p_m = p_manipulators / f'{i+1}.json'
with p_m.open('w') as f:
json.dump(process_manipulator(manipulator), f, indent=4)