Karabiner-Elementsの設定が超絶楽になるDSL「Goku」

※使用環境: `Goku 0.2.5`, `Karabiner-Elements 12.4.0`, `Homebrew 2.1.4`, `macOS 10.13.6`

#はじめに
「Mac 三大神アプリ」の1つと言っても差し支えない「Karabiner-Elements」ですが、設定ファイルの編集が少し面倒ですよね。[__Goku__](https://github.com/yqrashawn/GokuRakuJoudo)という__Karabiner-Elements用のDSL__を使うと、めちゃくちゃ楽に設定ができるようになりますよ。


# どのくらい楽になるのか？

「`左Optionキー`の空打ちを、`Control+F2`に割り当てる[^1]」という設定を例に、Gokuを使わずに直接書いた場合と、Gokuを使って書いた場合とを比べてみます。

[^1]: Macの標準設定では、`Control+F2`はメニューバーへフォーカスが移動するショートカットです。

- Gokuを使わない場合

```json:karabiner.json(抜粋)
{
  "description": "左Option(空打ち) -> Ctrl+F2",
  "manipulators": [
    {
      "from": {
        "key_code": "left_option"
      },
      "to": [
        {
          "key_code": "left_option"
        }
      ],
      "to_if_alone": [
        {
          "key_code": "f2",
          "modifiers": [
            "left_control"
          ]
        }
      ],
      "type": "basic"
    }
  ]
}
```

- Gokuを使った場合

```clojure:karabiner.edn(抜粋)
{:des "左Option(空打ち) -> Ctrl+F2" :rules [[:left_option :left_option nil {:alone :!Tf2}]]}
```

いかがでしょうか？

1つだけだと、違いがもう一つ伝わらないかもしれませんので、さらに設定を2つ追加してみます。
Terminalアプリの場合にのみ、「`Cmd+S` -> `Ctrl+S`」「`Cmd+T` -> `Cmd+T`,`英数キー`」となる設定を追加した例が下記になります。

<details><summary> Gokuを使わない場合 (クリックで表示)</summary><div>

```json:karabiner.json(抜粋)
{
  "rules": [
    {
      "description": "左Option(空打ち) -> Ctrl+F2",
      "manipulators": [
        {
          "from": {
            "key_code": "left_option"
          },
          "to": [
            {
              "key_code": "left_option"
            }
          ],
          "to_if_alone": [
            {
              "key_code": "f2",
              "modifiers": [
                "left_control"
              ]
            }
          ],
          "type": "basic"
        }
      ]
    },
    {
      "description": "[Terminal]  Cmd+S -> Ctrl+S",
      "manipulators": [
        {
          "conditions": [
            {
              "bundle_identifiers": [
                "^com\\.googlecode\\.iterm2$",
                "^com\\.apple\\.Terminal$"
              ],
              "type": "frontmost_application_if"
            }
          ],
          "from": {
            "key_code": "s",
            "modifiers": {
              "mandatory": [
                "left_command"
              ]
            }
          },
          "to": [
            {
              "key_code": "s",
              "modifiers": [
                "left_control"
              ]
            }
          ],
          "type": "basic"
        }
      ]
    },
    {
      "description": "[Terminal]  Cmd+T -> Cmd+T, EISUU",
      "manipulators": [
        {
          "conditions": [
            {
              "bundle_identifiers": [
                "^com\\.googlecode\\.iterm2$",
                "^com\\.apple\\.Terminal$"
              ],
              "type": "frontmost_application_if"
            }
          ],
          "from": {
            "key_code": "t",
            "modifiers": {
              "mandatory": [
                "left_command"
              ]
            }
          },
          "to": [
            {
              "key_code": "t",
              "modifiers": [
                "left_command"
              ]
            },
            {
              "key_code": "japanese_eisuu"
            }
          ],
          "type": "basic"
        }
      ]
    }
  ]
}
```
</div></details>


- Gokuを使った場合

```clojure:karabiner.edn
{:main [{:des "左Option(空打ち) -> Ctrl+F2" :rules [[:left_option :left_option nil {:alone :!Tf2}]]}
        {:des "[Terminal]  Cmd+S -> Ctrl+S" :rules [[:!Cs :!Ts :terminal]]}
        {:des "[Terminal]  Cmd+T -> Cmd+T, EISUU" :rules [[:!Ct [:!Ct :japanese_eisuu] :terminal]]}]
 :applications {:terminal ["^com\\.googlecode\\.iterm2$" "^com\\.apple\\.Terminal$"]}}
```

いかがでしょうか？

__Gokuを使わない場合は70行以上の追加が必要ですが、Gokuを使った場合は3行の追加で済みます。__
このように、Gokuを使えば大半の設定は1~2行で書けるため、追加や見直しを躊躇する必要がなく、いつでも思いついたタイミングで新しい設定を試してみることが可能になります。


---
#導入手順
Gokuを試してみたい方は、まず最初に以下の3つのドキュメントを読むことをオススメします。インストール方法、記述方法、Karabiner-Elementsへの反映まで、必要なことが一通り網羅されています。
- [README.md](https://github.com/yqrashawn/GokuRakuJoudo/blob/master/README.md)
- [Tutorial](https://github.com/yqrashawn/GokuRakuJoudo/blob/master/tutorial.md)
- [Example](https://github.com/yqrashawn/GokuRakuJoudo/blob/master/examples.org)

## 1. Install
HomebrewでGithubのリポジトリをtapしてインストールします。

```sh
$ brew install yqrashawn/goku/goku
```

## 2. Profileの作成
__Karabiner-Elementsの設定画面の「Profiles」から、`Default`という名前のProfileを追加してください。__
GokuはProfileを指定する記述がない場合、`Default`という名前のProfileに設定を反映しようとします。

__[※注意事項]__
__もし、既に`Default`という名前でProfileを運用している場合、Gokuで記述されていないリマップルールは反映時に消えてしまいます__ので、リネームしておいてください。別の名前のProfileを使うように指定することも可能ですが、記述ミスなどによって`Default`という名前のProfileが使われることもありますので、慣れるまではリネームしておいたほうが安全です。

![karabiner-profile-gui.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32927/855e9264-d07b-9e62-2a90-5c2ff89f7d2b.jpeg)

## 3. karabiner.ednの作成
Gokuはデフォルトでは、`~/.config/karabiner.edn`を設定ファイルとして読み込みます。
他のディレクトリやファイル名を使う場合は、反映時に環境変数`GOKU_EDN_CONFIG_FILE`を使ってファイルパスを指定しておく必要があります。

はじめに紹介した「`左Optionキー`の空打ちを、`Ctrl+F2`に割り当てる」という設定のみを書いた`karabiner.edn`を作成します。

```sh
$ cd ~/.config
$ echo `{:main [{:des "左Option(空打ち) -> Ctrl+F2" :rules [[:left_option :left_option nil {:alone :!Tf2}]]}]}` > karabiner.edn
```

## 4. Karabiner-Elementsへの反映
`goku`コマンドを実行して、`karabiner.edn`に書いた設定を、Karabiner-Elementsへの反映します。

```sh
$ goku
```

`Done!`と表示されたら反映完了です。
Karabiner-ElementsからProfileを`Default`に変更すれば、設定が反映されていることが確認できます。

![complex_modifications_抜粋_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32927/9a959827-2339-a799-a07b-90e0853fb97e.jpeg)

デフォルトとは違うディレクトリやファイル名で設定ファイルを作成した場合は、以下のように`GOKU_EDN_CONFIG_FILE`という環境変数でパスを指定後、`goku`コマンドを実行してください。

```sh
$ GOKU_EDN_CONFIG_FILE=~/path/to/file.edn
$ goku
```

### 設定ファイルをウォッチする
`gokuw`コマンドを実行すると、設定ファイルをウォッチして、変更があれば自動で`goku`コマンドが実行されるようになります。

```sh
$ gokuw
```

また、`brew services start yqrashawn/goku/goku`を実行すると、`gokuw`コマンドと同様の処理がバックグラウンドサービスとして起動されます。

ただし、現状はいずれの場合もウォッチする設定ファイルのパスが固定で、環境変数は使われないようになっているため、デフォルト以外のファイルパスを使っている場合は、`gokuw`の中身を変更したり、別のスクリプトを書いて対応する必要があります。

```sh:/usr/local/bin/gokuw
#!/bin/sh
watchexec -r -w ~/.config/karabiner.edn /usr/local/opt/goku/bin/goku
```

### インポート用設定ファイルを使って反映する場合
`goku`コマンドを実行すると、`karabiner.json`が更新されますが、それを避けたい場合はインポート用の設定ファイルを作成するのがいいかと思います。方法は下記の記事を参照してください。
[【Karabiner-Elements+Goku】インポート用の設定ファイルを作成する](https://qiita.com/QuestionDriven/items/34ddbb69eba8a45e133b)


#参考資料
- Goku
    - [yqrashawn/GokuRakuJoudo](https://github.com/yqrashawn/GokuRakuJoudo)
    - [Karabiner God Mode](https://medium.com/@nikitavoloboev/karabiner-god-mode-7407a5ddc8f6)
    - [键位修改 & 快捷键设置 by gokw] (https://konfido.github.io/wiki/2018/12/%E9%94%AE%E4%BD%8D%E4%BF%AE%E6%94%B9%20&%20%E5%BF%AB%E6%8D%B7%E9%94%AE%E8%AE%BE%E7%BD%AE/)

- karabiner.edn
    - [yqrashawn's dotfile](https://github.com/yqrashawn/yqdotfiles/blob/master/.config/karabiner.edn)
    - [nikitavoloboev's dotfile](https://github.com/yqrashawn/yqdotfiles/blob/master/.config/karabiner.edn)

- edn
    - [Learn edn in Y Minutes](https://learnxinyminutes.com/docs/edn/)
    - [JSON <-> EDN](http://pschwarz.bicycle.io/json-to-edn/)