Cocoa の仕組みに従って Mac のキーバインディングをカスタマイズする

# はじめに

macOS Sierra になって致命的だと感じているのは Karabiner が使えなくなってしまったことです。現在 Sierra に対応すべく暫定的に Karabiner-Elements が提供されていますが、以前のようなカスタマイズは行えないので、正直かなり困っています。

この記事のネタではそのような問題を解決することはできませんが、少しだけなら解決に向かえるかもしれません。

# 標準で備わっている emacs 風キーバインディング

macOS (Mac OS X, OS X) の Cocoa アプリではテキスト操作において emacs 風のキーバインディングを「一部」サポートしています。例えば以下のようなキー操作が標準で使えます。

|キー|内容|
|:--|:--|
|⌃A|カーソル操作／行頭に移動|
|⌃E|カーソル操作／行末に移動|
|⌃N|カーソル操作／1行下に移動|
|⌃P|カーソル操作／1行上に移動|
|⌃F|カーソル操作／1文字次に移動|
|⌃B|カーソル操作／1文字前に移動|
|⌃H|Backspace ⌫|
|⌃D|Forward Delete ⌦|
|⌃T|前後2文字の入れ替え|
|⌃L|カーソル行を画面中央に表示|
|⌃K|段落末尾までを削除／削除内容を Kill buffer にコピー|
|⌃Y|Yank／Kill buffer の内容をペースト|
|⌃V|Page Down|

vim vs. emacs の宗教戦争は抜きにして、おなじみのカーソル操作も使えるので、ホームポジションから手を外さずに快適なテキスト編集を行うことができます。

Kill buffer は macOS のペーストボードとは独立した領域なので、Mac では実質的に2種類のペーストボードを利用することができます。これほどウマい話はなかなかないでしょう。

これらキー操作は macOS ネイティブのキー操作とも組み合わせることができます。
例えば `shift ⇧` を押しながら上記のカーソル操作を入力すると、移動だけでなく選択範囲を拡張します。`option ⌥` を押しながらだと単語単位の移動になるので、さらに `shift ⇧` を押しながらやると単語単位で選択範囲を拡張します。

macOS では伝統的に `command ⌘` でのカーソル移動が備わっていますが、これと組み合わせることで、行の先頭・末尾、あるいは文書の先頭・末尾にまで一気に飛ぶことも可能です。

US 配列キーボードでは `control ⌃` が左下に配置されていて辛いので、私は `caps lock ⇪` を `control ⌃` にリマップして解決しています。修飾キーのリマップはシステム環境設定から簡単に行うことができます。

<img width="780" alt="スクリーンショット 2016-12-09 15.53.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/3603/d6ec3991-afa4-124e-648d-08ab1ae7dbcd.png">

この操作方法を知っていると知らないとでは Mac の操作体験がだいぶ異なるので、ぜひとも使っていただきたいものです。慣れるとカーソルキーを使わなくなります。

# StandardKeyBinding.dict

では一体これら emacs 風のキーバインディングをどこの誰が定義しているのでしょう？

実はこれらのキーバインディングは Cocoa のとあるフレームワークの奥底にある plist ファイルで全て定義されています。

> /System/Library/Frameworks/AppKit.framework/Versions/C/Resources/StandardKeyBinding.dict

AppKit は macOS の UIKit にあたるもので、キー操作の類もこいつが担っているということですね。

このファイルはバイナリ形式の plist なので直接テキストエディタで開くことは難しいのですが、拡張子を `plist` に変更すれば Xcode などでも開くことができます。ただし、キーを表す文字が文字化けしてしまうので編集するのは一苦労でしょう。

![](https://qiita-image-store.s3.amazonaws.com/0/3603/c9b04e37-0435-e682-60da-833b71a4b863.png)

つらいですね。

その辺り詳しく検証した記事がこちらにありますので、参考になるかと思います。
> [テキスト編集のキー操作を自在にコントロールする](http://d.hatena.ne.jp/zariganitosh/20101026/text_key_binding)

でも結局編集はどうすりゃいいのよ、というところだと思うので、ここでとても便利なアプリをご紹介します。

# KeyBindingsEditor.app

KeyBindingsEditor.app というアプリを使うと、このキーバインディングを定義したファイルを GUI で編集することができるようになります。

> ![](http://www.cocoabits.com/KeyBindingsEditor/KeyBindingsEditorIcon.png)
> KeyBindingsEditor
> http://www.cocoabits.com/KeyBindingsEditor/

さて、StandardKeyBinding.dict はシステムフォルダの奥底にあるため、基本的には編集することができないファイルです。アクセス権を変更して無理にデフォルトの定義を書き換えることも可能ですが、ここは macOS のシステムの仕組みに従い、~/Library/ 以下に独自の定義ファイルを新規に作成してインストールしましょう。

macOS では主に3種類の Library が存在します。

1. /System/Library
2. /Library
3. ~/Library

ユーザーが自由に書き換えられるのは2と3のみで、1は滅多に触ることはありません。2はユーザー全体、3はユーザー専用です。

KeyBindingsEditor.app では自動的に `~/Library/KeyBindings` に新規の定義ファイル `DefaultKeyBinding.dict` を作成してくれます。
![](https://qiita-image-store.s3.amazonaws.com/0/3603/16ba3af9-6206-328c-2503-e0b19c6e4b60.png)

# DefaultKeyBinding.dict で独自のキーバインディングを定義

このファイルに独自のキーバインディングを追加できますが、用意されているアクション以外のことは行えません。ここが Karabiner とは異なるところで、結局のところ Karabiner がなければ実現できないキー操作もあります。

ちなみに私はこのようにしてみました。
![](https://qiita-image-store.s3.amazonaws.com/0/3603/516b6901-26dc-6900-5c7a-ab20098a4f13.png)

`option ⌥` を使ったキーを入力すると高確率で謎の不可視文字が入力されてビルドエラーが頻発しているので、単語単位移動系ではなるべく `option ⌥` を使わないよう別のキー操作を定義しました。⌃Oとか⌃Vが空いてそうだったのでそこをオーバーライドしています。⌃Cや⌃Zは Terminal の操作で使うからか元から欠番になっています。

その他、`setMark` `selectToMark` を追加しました。これはマークを入れた位置（目には見えない）から指定位置までの範囲を選択するというアクションで、マウスを使わずに一気に範囲選択するのにとても便利です。

また、MacBook Pro with Touch Bar の `esc ⎋` が感触がなさすぎて支障が出ているために、解決策として `cancelOperation` のアクションを ⌃↩︎ に割り当ててみました。ただやはり `esc ⎋` としての役割がアプリごとに独自に実装してしまっているので、アプリによっては `esc ⎋` として認識してくれない場合があります。リマップではないためここはどうしても解決は無理でした。

ちなみに Xcode のコード補完は `esc ⎋` によって行いますが、こちらに関しては Xcode のキーバインディングを変更することで解決できています。⌃↩︎ は以前よりも便利かもしれません。
![](https://qiita-image-store.s3.amazonaws.com/0/3603/02ebb292-6d35-c51d-383d-89619cc44a2f.png)

# StandardKeyBinding.dict のアクションは何者なのか

ところで、ここで用意されているアクションは何者なのでしょうか。説明がないので意味がわからないものもあります。

![](https://qiita-image-store.s3.amazonaws.com/0/3603/f4bb5611-5046-c26f-9dbe-426f695eec35.png)

実はこれらは NSResponder という AppKit においてイベント処理を取り扱う Objective-C クラスのメソッド名になっていて、イベント処理のメソッド名が直接アクション名として plist に書き込まれているということになります。面白い仕組みですね。

なので、NSResponder のクラスリファレンスを参照すれば、アクションの意味も理解することができます。以下のページでアクション名と全く同じメソッド名が見つかるはずです。

> https://developer.apple.com/reference/appkit/nsresponder

# むすび

macOS の Cocoa で定義されているキーバインディングとその仕組みの概要、およびカスタマイズの方法を説明しました。

Sierra になって Karabiner が現在使えないのはなかなか厳しい情勢ではありますが、Cocoa のキーバインディングをカスタマイズすることでいくらかはマシにはなるかもしれません。

快適な Mac ライフを。