macOS Sierra で Karabiner が使えない問題にどう対処したか


# 先に結論

- 「かな」周りのキーバインディング設定は Karabiner Elements を使う。「かな」キーに F13 を割り当て、そこを入力ソースのトグルにした
- キーリピート設定は同じく Karabiner Elements
- iTerm2 のメタキーの設定は、iTerm2 自身の設定を使って対処
- <del>Cocoa アプリケーションの最低限のキーバインドは DefaultKeybindings.dict に定義してお茶を濁す</del><ins>Hammerspoon を使う方法に移行した http://qiita.com/naoya@github/items/81027083aeb70b309c14</ins>
- keyhac は利用を検討したが、見送った

# やりたかったこと

- 新しい MacBook Pro を購入したことで macOS Sierra を使うことになった。これまでは Karabiner が動かないことを懸念して Sierra へのアップグレードは行っていなかった
- Karabiner で設定していたあれやこれを Sierra でどう実現するか
- なお、キーボードは日本語配列

# やったこと

## 「かな」を入力ソースのトグルに割り当てる

「かな」を押したら日本語入力に、もう一度おしたら英語に･･･というトグル設定になるようにしてたのをどうするか。ここでは Karabiner の基本部分の Sierra 版として開発が進められている Karabiner Elements を使う。

Karabiner Elements ですべて事足りれば何ひとつ苦労はなかったのだが、2016年11月22日現在の Karabiner Elements では「`Ctrl + /` に Undo を割り当てる」みたいな修飾キーつきのキー割り当ての機能がないなど Karabiner の各種機能がまだ実現されていない。

もとい、「かな」の設定である。

![スクリーンショット 2016-11-22 7.17.54.png](https://qiita-image-store.s3.amazonaws.com/0/1834/ccfe4e03-2446-af00-f8dd-270eba3c5da8.png "スクリーンショット 2016-11-22 7.17.54.png")

このように「かなキー」を f13 キーに割り当てる。

ちなみに Devices で JIS キーボードを明示的に選ばないとキー配列が英語配列になるみたいなことが自分の環境では起こったので以下も設定している。

![スクリーンショット 2016-11-22 7.18.42.png](https://qiita-image-store.s3.amazonaws.com/0/1834/710bb38a-0d97-ddd5-2482-4b7c3b32eaa9.png "スクリーンショット 2016-11-22 7.18.42.png")

次に Karabiner Elements から離れて、macOS のキーボードショートカット設定で先に割り当てた f13 を入力ソースのトグルに使うように設定する。

![スクリーンショット 2016-11-22 7.20.31.png](https://qiita-image-store.s3.amazonaws.com/0/1834/f90b271e-3712-a8fb-3880-ade3220671ec.png "スクリーンショット 2016-11-22 7.20.31.png")

これで完了。

## キーリピート設定

キーリピートを高速にしてカーソル移動その他を快適にしたい。これは Karabiner Elements で設定できた。

![スクリーンショット 2016-11-22 7.21.46.png](https://qiita-image-store.s3.amazonaws.com/0/1834/d891ebc8-1880-0643-636b-bb79ae02c685.png "スクリーンショット 2016-11-22 7.21.46.png")

## iTerm2 でメタキーを Command キーに変更する

この設定は以前は Karabiner でやってたが、できなくなったので iTerm2 本体の設定で対応する。

そもそもなんでそんなことをするかというと、これをやらないと iTerm2 内でのシェル操作や Emacs などのスクリーンエディタを使うにあたってメタキーが Alt になってしまって非常に押しづらいから、である。

![スクリーンショット 2016-11-22 7.23.02.png](https://qiita-image-store.s3.amazonaws.com/0/1834/774723a0-5bd7-16ce-2f30-6f413231dc47.png "スクリーンショット 2016-11-22 7.23.02.png")

ちょっと分かりづらいが「Remap Modifier Keys」のところで

- Left option を Left Command に変更
- Left Command を Left Option に変更

している。これで、iTerm2 では Alt と Command の役割が交換される。

この設定だけだと不都合があって Command + Tab でアプリケーションを切り替えるときに iTerm2 では Command + Tab が効かないってことになる。そこで、スクリーンショット右側の「Key Mappings」のところに

- Command+Tab は Do Not Remap Modifiers

を入れている。

これで Command + Tab のときは先にいれた Alt と Command の設定を変える設定が有効にならないので、結果、意図した通りに動く。

ほかにも Alt と Command を入れ替えたことで手に馴染まない動きをすることがあったらこの辺の設定をうまく駆使すれば良いと思う。

## Cocoa アプリケーションの Emacs キーバインドをどうするか

<ins>追記: Hammerspoonを使う方法に移行しました http://qiita.com/naoya@github/items/81027083aeb70b309c14</ins>

Karabiner には Cocoa アプリケーションを Emacs ライクなキーバインドで操作できるようにするオプションがついてた。もともと Cocoa は微妙に Emacs というか Readline といっていいのかわからないけど、テキスト入力時に `C-a` や `C-e` や `C-f` や `C-b` が効くなどそれっぽい動きをするのだが、Karabiner では `C-s` を検索に割り当てたり、`C-/` を Undo にしてくれたりとより Emacs に近いキーバインドに変更してくれるおもてなし機能があった。

これをどうするか。いろいろ試行錯誤をしたのだが、結局 DefaultKeyBiding.dict に主要なキーバインドを自分で定義してお茶を濁すことにした。

DefaultKeyBiding.dict は `~/Library/KeyBidings/DefaultKeyBiding.dict` というファイルに以下のようにキー定義を書くと Cocoa アプリケーションのキーバインドを変更できるという代物。

```
{
  "^/" = "undo:";
  "^y" = "paste:";
  "^v" = "scrollPageDown:";
  "~v" = "scrollPageUp:";
  "^g" = "_cancelKey:";
  "^l" = "centerSelectionInVisibleArea:";
  "^w" = "cut:";
}
```

`^/` は Ctrol + / のことで、`~v` は alt + v のこと。Command + a だったら `@a` と書く。

設定ファイルを書き換えたそばから OS には設定が反映される。ただし対象のアプリケーションは再起動が必要。

`undo:` や `paste:` などどういうアクションを割り当てることができるか、などは

- http://d.hatena.ne.jp/zariganitosh/20101026/text_key_binding

この記事が詳しい。ほかにも「DefaultKeybiding.dict emacs」とかでググれば一杯でてくると思う。

本当は `C-s` に検索機能 (Command + F) を割り当てたりしたかったのだけど、ものによってはそういうアクションがないようです。

あまりこのファイルを複雑に設定しすぎるのもほかとバッティングしたりいろいろ具合が良くなさそうだなと思ったので頻繁に使ってるキーバインドだけを定義して、その他は macOS 標準のキーバインドに慣れるようにした。

## おまけ: keyhac は利用を見送り

keyhac というツールがあって、keyhac なら修飾キーつきのキーバインドを柔軟にカスタマイズできる。`C-s` を `Cmd-f` に変更するなんてことも簡単だ。また、iTerm2 など特定のアプリケーションではそういうキーバインド変更を適用しない、みたいなこともやってみたらできた。

keyhac は設定を Python スクリプトで書く。前述の設定は以下のようになる。

```config.py
import sys
import os

from keyhac import *
import ckit

def configure(keymap):
    not_emacs_target = [
        "com.googlecode.iterm2",
        "com.apple.Terminal",
    ]

    class Fakeymacs:
        pass

    fakeymacs = Fakeymacs()
    fakeymacs.last_window = None

    def is_emacs_target(window):
        if window != fakeymacs.last_window:
            fakeymacs.last_window = window

        # print(ckit.getApplicationNameByPid(window.pid))

        if ckit.getApplicationNameByPid(window.pid) in not_emacs_target:
            return False

        return True    

    keymap_emacs = keymap.defineWindowKeymap(check_func=is_emacs_target)

    keymap_emacs[ "Ctrl-V" ]     = "PageDown" # Page down
    keymap_emacs[ "Alt-V" ]      = "PageUp"   # page up
    keymap_emacs[ "Ctrl-S" ]     = "Cmd-F"    # Search
    keymap_emacs[ "Ctrl-W" ]     = "Cmd-X"    # Cut
    keymap_emacs[ "Alt-W" ]      = "Cmd-C"    # Copy
    keymap_emacs[ "Ctrl-Y" ]     = "Cmd-V"    # Paste
    keymap_emacs[ "Ctrl-Slash" ] = "Cmd-Z"    # Undo
```

keyhac のソースを見ながらいろいろいじってたら、できた。なお、keyhac のソースは https://github.com/crftwr/keyhac こちらにある。keyhac はもともと Windows 版でお世話になってたツールだが後に macOS 用にもポートされた様子。macOS 版のソースは mac_port ブランチにある。

keyhac をやめたのは、どうも keyhac を起動すると先に紹介した iTerm2 のキーリマップ設定が効かなくなる。キーリマップ周りの仕組みがよくわかってないが、keyhac がリマップ周りの制御を先に奪ってしまって iTerm2 でそれが効かなくなるとかそんなところだろうか。とにかく、相性が悪かったので一旦利用を見送った。

# 所感

みんな Karabiner Elements の開発を応援しよう。自分も何かしらのかたちでコントリビュートしなきゃなあ、と思う次第です。