yqrashawn / GokuRakuJoudo

config karabiner with ease
GNU General Public License v3.0
1.13k stars 122 forks source link

Create Karabiner JSON -> Goku converter #34

Open nikitavoloboev opened 5 years ago

nikitavoloboev commented 5 years ago

Would be useful for people trying to switch over from painstakingly writing Karabiner JSON to Goku.

Not a huge issue but can be helpful and there was a person in Telegram Karabiner group asking for something like it.

classicrob commented 4 years ago

I would still be very interested in this!

llity commented 4 years ago

I need this feature.

misha-tgshv commented 4 years ago

I need this feature ๐Ÿ‘

yqrashawn commented 4 years ago

The original intention of this project is to build a DSL to ease the frustration of jumping between multiple large blocks of JSON code while tweaking my karabiner config. A JSON->goku converter will indeed ease the onboarding process users still need to learn the syntax to really get the benefits from it. And it's really hard to convert the raw JSON config to goku syntax edn code.

We need to guess the user's intention from all rules in JSON let alone there will be rules that just contain a typo or get overwritten by other rules.

If you just want to import your JSON config into the edn file. You can find some json->edn converter and put all your rules in edn file like this.

I think a gui configuration tool like the tmk keymap editor is a better onboarding solution. But I don't think I'll really use it if there's one. It's really easy to manipulate texts in an editor than open a webpage and click on it.

I don't plan to implement this feature. I'll add a help wanted label here. If there's anyone interested in contributing or just write something up like walking through of all those logics in converting JSON to goku. I'm happy to discuss it here and implement it in goku.

tigger04 commented 3 years ago

The tool looks really cool, I'm interested to have a go at this, but I' m one of those people who hand-cranked a json file over many painstaking hours over the years, there's just too much in it for me to switch in one move, since i would have to set aside a considerable amount of time to write it once i have go tto grips with the syntax, and then there is the inevitable quirks of things breaking and needing to be tweaked/fixed. I have enough problems getting my work done without getting sidetracked with new ideas for hacking my mac without adding in a wholesale migration project for ... unknown benefits, but on the face of it, exactly the same as what i have now. Same goes for drawing it up in a UI ( i'll take the JSON thanks)

The problem I have with the GokuRaku tool is - the first thing it wants tto do is overwrite my karabiner.json and change my keys. That's fine if you are starting from a blank slate but i cannot be the only one who is not. Why not allow them to be generated as complex modifications so that i can import them in to my existing config, and i can switch incrementally over time

yqrashawn commented 3 years ago

The problem I have with the GokuRaku tool is - the first thing it wants tto do is overwrite my karabiner.json and change my keys. That's fine if you are starting from a blank slate but i cannot be the only one who is not. Why not allow them to be generated as complex modifications so that i can import them in to my existing config, and i can switch incrementally over time

Goku only changes the specified profile. You can specify a separate profile and migrate to it gradually. Also you can use the --dry-run option to test before goku really changes your karainer.json file.

pragmat1c1 commented 3 years ago

I use 4 complex modifications in karabiner, and I am totally lost in trying to migrate them into an EDN version of this.

This is the list of the complex modifications I use:

Does anyone know a project that deals with migrating the "complex modifications" to edn format?

yqrashawn commented 3 years ago

@pragmat1c1 commented on Feb 15, 2021, 2:02 AM GMT+8:

I use 4 complex modifications in karabiner, and I am totally lost in trying to migrate them into an EDN version of this.

This is the list of the complex modifications I use:

  • Change fn-key to command+control+option+shift.
  • Post left_ctrl when return_or_enter is hod.
  • Post escape if caps is pressed alone, left_ctrl otherwise
  • Emacs key bindings [control+keys] (rev 10)

Does anyone know a project that deals with migrating the "complex modifications" to edn format?

;; 1 
;; this one may not work
;; found this at https://github.com/pqrs-org/KE-complex_modifications/issues/149#issuecomment-337031035
{:des   "fn to hyper"
 :rules [[:##fn :!CSOleft_control nil {:alone :fn}]]}
;; 2
{:des   "return_or_enter to control when pressed with other keys"
              :rules [[:##return_or_enter :left_control nil {:alone :return_or_enter}]]}
;; 3
{:des   "caps_lock"
              :rules [[:##caps_lock :left_control nil {:alone :escape}]]}

4 You can check the emacs one I use here. Don't forget to define the :emacs-mode-disable-app and Emacs applications. See here and here

pragmat1c1 commented 3 years ago

@pragmat1c1 commented on Feb 15, 2021, 2:02 AM GMT+8:

I use 4 complex modifications in karabiner, and I am totally lost in trying to migrate them into an EDN version of this. This is the list of the complex modifications I use:

  • Change fn-key to command+control+option+shift.
  • Post left_ctrl when return_or_enter is hod.
  • Post escape if caps is pressed alone, left_ctrl otherwise
  • Emacs key bindings [control+keys] (rev 10)

Does anyone know a project that deals with migrating the "complex modifications" to edn format?

;; 1 
;; this one may not work
;; found this at https://github.com/pqrs-org/KE-complex_modifications/issues/149#issuecomment-337031035
{:des   "fn to hyper"
 :rules [[:##fn :!CSOleft_control nil {:alone :fn}]]}
;; 2
{:des   "return_or_enter to control when pressed with other keys"
              :rules [[:##return_or_enter :left_control nil {:alone :return_or_enter}]]}
;; 3
{:des   "caps_lock"
              :rules [[:##caps_lock :left_control nil {:alone :escape}]]}

4 You can check the emacs one I use here. Don't forget to define the :emacs-mode-disable-app and Emacs applications. See here and here

Wow! Thank you very much! This is very helpful. Now I finally can migrate to Goku/edn files. :)

andmis commented 2 years ago

This only partially works. It doesn't handle variables or applications, for example. And you will definitely have to edit the result it produces. For example, the result is not formatted/indented in any way. But if you know how to program and have a long karabiner.json, this might be useful to produce a good starting point, since anyway you only have to migrate JSON โ†’ EDN one time.

#!/usr/bin/env python3

# Usage: json_to_edn.py
# Expects to find ~/.config/karabiner/karabiner.json
# Prints its results to STDOUT

import json
import os

# Apple seems to use โŒƒโŒฅโ‡งโŒ˜ as the order.
# https://support.apple.com/en-ca/HT201236
SORTED_MODS = [
    'control',
    'left_control',
    'right_control',
    'option',
    'left_option',
    'right_option',
    'alt',
    'left_alt',
    'right_alt',
    'shift',
    'left_shift',
    'right_shift',
    'command',
    'left_command',
    'right_command',
]

LONG_TO_SHORT_MOD = {
    'control':       'T',
    'left_control':  'T',
    'right_control': 'W',
    'option':        'O',
    'left_option':   'O',
    'right_option':  'E',
    'alt':           'O',
    'left_alt':      'O',
    'right_alt':     'E',
    'shift':         'S',
    'left_shift':    'S',
    'right_shift':   'R',
    'command':       'C',
    'left_command':  'C',
    'right_command': 'Q',
}

def short_mods(mods):
    """Return canonically-in-order mods, converted to short form.

    Args:
        mods: "left_command", etc.
    """
    if 'any' in mods:
        return '#'
    key = {mod: index for index, mod in enumerate(SORTED_MODS)}
    for mod in mods:
        if mod not in SORTED_MODS:
            raise ValueError(f'mod {mod} not found in SORTED_MODS')
    return ''.join(LONG_TO_SHORT_MOD[m] for m in sorted(mods, key=lambda m: key[m]))

def get_key_description(f):
    result = ':'
    if 'modifiers' in f and f['modifiers']:
        if 'mandatory' in f['modifiers'] and f['modifiers']['mandatory']:
            result = f'{result}!{short_mods(f["modifiers"]["mandatory"])}'
        if 'optional' in f['modifiers'] and f['modifiers']['optional']:
            result = f'{result}#{short_mods(f["modifiers"]["optional"])}'
        if type(f['modifiers']) is list:
            result = f'{result}!{short_mods(f["modifiers"])}'
    result = f'{result}{f["key_code"]}'
    return result

def get_to_description(t):
    if 'key_code' in t:
        return get_key_description(t)
    elif 'set_variable' in t:
        sv = t['set_variable']
        return f'["{sv["name"]}" {sv["value"]}]'
    else:
        raise NotImplementedError

def print_root(blob):
    print('{')
    print_applications(blob)
    print_main(blob)
    print('}')

def print_applications(blob):
    print(':applications')
    print('{')
    print('}')

def print_main(blob):
    print(':main')
    print('[')
    for d in blob['profiles'][0]['complex_modifications']['rules']:
        print_main_block(d)
    print(']')

def print_main_block(d):
    print('{')
    print(':des')
    print(f'"{d["description"]}"')
    print(':rules')
    print('[')
    for manipulator in d['manipulators']:
        print_rule(manipulator)
    print(']')
    print('}')

def print_rule(d):
    print('[')
    print(get_key_description(d['from']))
    if len(d['to']) == 1:
        print(get_to_description(d['to'][0]))
    else:
        print('[')
        for t in d['to']:
            print(get_to_description(t))
        print(']')
    print(']')

with open(str(os.getenv('HOME')) + '/.config/karabiner/karabiner.json') as f:
    print_root(json.load(f))