8 / 22

2015

RubyのDSLでKarabinerのかゆい所に手を届かせる

Macを使い始めてキーボードで困ったこと

昨年からメインマシンにiMacを使い始めて、キーボードショートカットに戸惑った。

WindowsだとControlキー(Ctrl)との組合せで使うショートカットの多くが、コマンドキー(⌘)との組合せになっているのがその要因。さらにやっかいなのはターミナル上で走らせたプログラム(簡易サーバーなど)を停止する際のキーバインドはCtrl-Cだったりすること。

Mac OSXでは設定でControlキーとコマンドキーを入れ替えることはできるが、それだと前述のようなキーバインドも入れ替わってしまい、嫌だった。

Karabiner(旧・KeyRemap4Macbook)という無料ソフトがあり、これを使えばかなり豊富なキーバインドの変更が可能なため、そちらを使うようにした。

ところが、Karabinerで変更したキーバインドが特定のアプリケーションのキーバインドと競合してしまう場合がある。

僕の場合はコピー・カット・ペースト・アンドゥのショートカットをWindowsと同じControl + という組合せに変えているのだけど、MacVimを使っているとVimの矩形ビジュアルモードへ移行するコマンド C-V とかち合ってしまい、矩形選択をするつもりで意図せずに文字列が貼り付けられてしまう。ターミナルでVimを使うときは問題ないのだけど。

Karabinerでは元から入っているキーバインド設定の他にもユーザーが独自に追加できるようになっている。しかしその設定はXMLで書かねばならず、単純なものならともかく、上に挙げたような衝突を回避する設定はどう書けばいいのかわからず、使いづらいと思いつつそのまま使っていた。

Karabinerの設定をRubyのDSLで書けるgem

つい今週、たまたまのぞいたブログでKarabinerの設定ファイルをRubyの文法で書けるDSL(ドメイン特化言語)を作っていたのを知り、さっそく試してみた。

Karabinerの設定を楽に書けるやつ作った - k0kubun's blog

このライブラリkarabiner-dslはgemで配布されている(gem名はkarabiner)。

k0kubun/karabiner-dsl

使い方は上記のブログに書いてあるとおり、gem install しておいて、~/.karabiner にRubyで設定ファイルを書き、 シェルで karabiner dsl を実行するだけ。

自分は最低限の設定ができればよかったので次のように書いてみた。

appdef "MacVim", equal: "org.vim.MacVim" do
end

item "PC Style Copy/Paste (Except for TERMINAL, MacVim)", not: "TERMINAL,MacVim" do
  remap "C-C", to: "Cmd-C"
  remap "C-V", to: "Cmd-V"
  remap "C-X", to: "Cmd-X"
end

item "PC Style Undo (Except for TERMINAL, MacVim)", not: "TERMINAL,MacVim" do
  remap "C-Z", to: "Cmd-Z"
end

そうすると次のようなXMLを生成してくれた。

<?xml version="1.0"?>
<root>
  <appdef>
    <appname>MacVim</appname>
    <equal>org.vim.MacVim</equal>
  </appdef>

  <item>
    <name>PC Style Copy/Paste (Except for TERMINAL, MacVim)</name>
    <identifier>remap.pc_style_copy_paste__except_for_terminal__macvim_</identifier>
    <not>TERMINAL,MacVim</not>
    <autogen>__KeyToKey__ KeyCode::C, VK_CONTROL, KeyCode::C, VK_COMMAND</autogen>
    <autogen>__KeyToKey__ KeyCode::V, VK_CONTROL, KeyCode::V, VK_COMMAND</autogen>
    <autogen>__KeyToKey__ KeyCode::X, VK_CONTROL, KeyCode::X, VK_COMMAND</autogen>
  </item>

  <item>
    <name>PC Style Undo (Except for TERMINAL, MacVim)</name>
    <identifier>remap.pc_style_undo__except_for_terminal__macvim_</identifier>
    <not>TERMINAL,MacVim</not>
    <autogen>__KeyToKey__ KeyCode::Z, VK_CONTROL, KeyCode::Z, VK_COMMAND</autogen>
  </item>
</root>

これでずっとモヤモヤしていたキーバインドの衝突が解消された。しかも生のXMLを書くよりもずっと直感的で書きやすいし読みやすい。gemの作者@k0kubunさんに感謝。

注意点

以上のようにとても簡単に独自設定が書けてしまうのだけど、いくつか自分がハマった箇所があるので挙げておく。

  1. DSLで設定を書くときにオプションの指定が間違っているとエラー吐いて正常に設定が書き込まれない。正しく書かれていれば既存のprivate.xmlに追加で書き込まれるはずが、上書きされてしまうので要注意。

  2. 特定のアプリケーションのみで動作させたい、あるいはさせたくないというような設定をしたい場合、onlyオプションやnotオプションで指定してやる。この時、TERMINALやEMACSのような一部のアプリケーションについてはデフォルトでアプリケーション名が認識されるが、今回のようにMacVimといったその他のアプリケーションを指定する場合は先にappdef要素で定義する必要があった。equal要素のアプリケーションの識別名の調べ方は下記ブログ参照。

Karabiner の private.xml 設定方法 - Qiita

おまけ

メタプログラミングRubyの第2版の翻訳本がついに10月に出るみたいですね。原書の第2版は原書でも読みましたが、第1版の翻訳はとても良かったので楽しみにしています。


メタプログラミングRuby 第2版

メタプログラミングRuby 第2版/Paolo Perrotta 角 征典/訳 本・コミック : オンライン書店e-hon

※ 2015/09/19 Amazonリンクを追記、語句修正