Hammerspoon と Karabiner-Elements でアプリケーションごとにキーマッピングを変更する

Sierra より前の OSX で動作していた Karabiner はアプリケーションごとにキーマッピングを変更できたが、Sierra で動作する Karabiner-Elements ではその機能がなくなってしまった。Hammerspoon と Karabiner-Elements を組み合わせて Sierra でもそれを実現する。

# 背景

Sierra より前の OSX ではキーマッピングを以下のように設定していた（US 配列のキーボードを利用）。

- `Caps lock` を `Command` に変更: Mac のシステム環境設定で設定
- ターミナルでは左の `Command` を `Control` に変更: ↑で設定したものを更に iTerm2 で設定
- MacVim でも左の `Command` を `Control` に変更: Karabiner でアプリケーションごとに設定を変更して対応

しかし冒頭に書いた理由で MacVim の設定が実現できなくなり、とても困っていた。

# 手順

- Karabiner-Elements に複数のプロファイルを用意
- Hammerspoon でアプリケーションごとにプロファイルを変更

（[こちら](https://medium.com/@jphenow/sierra-broke-my-keyboard-modifier-keys-and-i-refused-to-wait-for-a-fix-46a548ace044)の記事でキーボードごとに設定変更していたので、それをアプリケーションごとに変更できるようにした）

## Karabiner-Elements に複数のプロファイルを用意

Karabiner-Elements の `Profiles` から作成する。今回は名前を `MacVim` とした。

<img width="798" alt="K-1.png" src="https://qiita-image-store.s3.amazonaws.com/0/57291/4a2b66cb-e786-298e-b3b4-c081989bb67e.png">

作成したプロファイルを [Select] してから `Simple Modifications` でキーマッピングを追加する。

<img width="798" alt="K-2.png" src="https://qiita-image-store.s3.amazonaws.com/0/57291/380a3580-2f88-1338-7996-371177c48721.png">

Karabiner-Elements は `~/.config/karabiner/karabiner.json` に設定を保存している。`profiles` 以下はこのようになっているはず。

```json:~/.config/karabiner/karabiner.json（抜粋）
{
  "profiles": [
    {
      "name": "Default",
      "selected": true,
      "simple_modifications": {}
    },
    {
      "name": "MacVim",
      "selected": false,
      "simple_modifications": {
        "caps_lock": "left_control"
      }
    }
  ]
}
```

## Hammerspoon でアプリケーションごとにプロファイルを変更

Hammerspoon で利用中のアプリケーションを取得して、プロファイル変更スクリプトを実行する。

```lua:~/.hammerspoon/init.lua
local home = os.getenv("HOME")

local function handleGlobalEvent(name, event, app)
    if event == hs.application.watcher.activated then
        -- hs.alert.show(name)
        if name == "MacVim" then
            hs.execute(home .. '/.hammerspoon/karabiner-switcher 1')
        else
            hs.execute(home .. '/.hammerspoon/karabiner-switcher 0')
        end
    end
end

watcher = hs.application.watcher.new(handleGlobalEvent)
watcher:start()
```

プロファイル変更スクリプト（実行権を付与すること）:

```ruby:~/.hammerspoon/karabiner-switcher
#!/usr/bin/env ruby

require 'json'

select = ARGV[0].to_i

filename = "#{ENV["HOME"]}/.config/karabiner/karabiner.json"
file = File.open(filename)
data = JSON.parse(file.read)
file.close

data["profiles"][0]["selected"] = select == 0
data["profiles"][1]["selected"] = select == 1

json = JSON.generate(data)

file = File.new(filename, "w")
file.write(json)
file.close
```

これで通常時は `profiles[0] # Default` が、MacVim 利用時には `profiles[1] # MacVim` が有効になる。
`Misc` で `Show profile name in menu bar` をONにすると動作確認ができて便利。

<img width="855" alt="h1.png" src="https://qiita-image-store.s3.amazonaws.com/0/57291/bc766e17-05f6-61b6-998d-79be2a0bfde7.png">
<img width="855" alt="h2.png" src="https://qiita-image-store.s3.amazonaws.com/0/57291/8552c925-1448-8d19-3264-3d1a264b7ddf.png">

## その他

僕の場合は Karabiner-Element を入れると Mac のシステム環境設定で設定した修飾キー変更が効かなくなってしまったので、`Default` プロファイルに `caps_lock` を `left_command` にする設定を入れた。

# まとめ

最終的に以下のように設定することになった。

- `Caps lock` を `Command` に変更: Karabiner-Elements の `Default` プロファイル
- ターミナルでは左の `Command` を `Control` に変更: ↑で設定したものを更に iTerm2 で設定
- MacVim では左の `Caps lock` を `Control` に変更: Karabiner-Elements の `MacVim` プロファイル

# 参考にしたWebページ

- [Sierra broke my keyboard modifier keys and I refused to wait for a fix - Medium](https://medium.com/@jphenow/sierra-broke-my-keyboard-modifier-keys-and-i-refused-to-wait-for-a-fix-46a548ace044)
- [Karabiner 使えない対策: Hammerspoon で macOS の修飾キーつきホットキーのキーリマップを実現する - Qiita](http://qiita.com/naoya@github/items/81027083aeb70b309c14)
- [Karabiner-Elements Usage](https://github.com/tekezo/Karabiner-Elements/blob/master/usage/README.md)