ラベル Karabiner の投稿を表示しています。 すべての投稿を表示
ラベル Karabiner の投稿を表示しています。 すべての投稿を表示

2017/04/06

【余談】Hammerspoon に移行

手元の Mac の OSをアップデートしたら Karabiner が利用できなくなってしまった。
どうも  macOS Sierra に非対応のとのこと。Karabiner はカーネルにモジュール(KEXT)を読み込ませ、カーネル内部のキーイベントを操作することでキーバインドの変更を実現している模様だが、そのためカーネルの変更に弱い面がある。

一方の Apple はセキュリティ面やOSの安定稼働の面から、KEXT による拡張を抑制する方向にある。Microsoft も 64bit 移行やOSのアップグレードの機会を通じて電子署名されていないデバイスドライバはロードできないようにしているし、iOS のようなモバイルデバイスのOSでは、もはやカーネルにモジュールを追加することすら不可能になっている。

幸い、Karabiner では Karabiner Elements という新しいキーリマップソフトウェアを開発、そこから従来の Karabiner の機能を追加していく形で刷新するようで、これは期待が持たれる。とはいえ、一からの作り直しなのでしばらくは Karabiner なしの生活に耐えなければならないようだ。

私が Karabiner を使ってる理由は、実のところ「Microsoft Office で Emacs キーバインド(のサブセット)が使いたい」 につきる。Karabiner Elements では現在のところアプリケーションごとのキーマップというのは実装されてないので、これは対応できないことになる。

いい加減 面倒になってきたので色々探して試した結果、Hammerspoon を利用することに落ち着いた。Hammerspoon はキー入力などのイベントを Lua という言語を使ってカスタマイズするもので、単なるキーリマップ以上の操作もできるようだ。
また、Accessibility API を通じてキーイベントを取得、操作を行う。公式のAPI を通しているため、OSのアップデートによる影響も(KEXTを使うのに比べると)低い訳だ。

Hammerspoon は ~/.hammerspoon/init.lua というスクリプトを読み、これに応じて処理をおこなう。私のスクリプトは以下の通りだ。

詳細は、この gist のコメントを見てほしい。

2015/08/04

【余談】Karabiner でのカスタムセッティング

Karabiner のおかげで Office アプリでも Emacs Keybinding が使えるようになった。

しかし、Karabiner を入れると、Office アプリ以外でもキーバインドノリマップが発生してしまい、Karabiner があるときとないときで挙動が変わってしまう。

例えば、OmniGraffle でテキストフィールドを選択、テキストを範囲選択した状態で「Ctrl-A」を押したときの挙動が、Karabiner なしだとそのテキストフィールド内での先頭位置になるが、Karabiner を有効にしていると別の(一つ前の)テキストフィールドに移動してしまう。

私がやりたいのは MS-Office (PowerPoint, Excel, Word, Outlook, OneNote) のみで Emacs Keybinding を効かせたいだけなので、他のアプリには影響を及ぼしたくない。

ざっと XML の仕様を読んだが、replacement(要は定数定義)を上書きして、挙動させないアプリを増やすことは簡単にできそうだ。だが、私のやりたい「特定のアプリだけに設定を効かせたい」の場合、定数の書き換えだけではうまくいかない、ちょっとまじめに項目(item)を増やすしかなさそうだ。

少し早く起きてしまったし、ちょっと試してみた。
---
<?xml version="1.0"?>
<root>
  <replacementdef>
    <replacementname>XML_INC</replacementname>
    <replacementvalue>/Applications/Karabiner.app/Contents/Resources/include/checkbox</replacementvalue>
  </replacementdef>

  <appdef>
    <appname>ONENOTE</appname>
    <equal>com.microsoft.onenote.mac</equal>
  </appdef> 
  <item> 
    <name>Private Settings</name>
    <item>
        <name>Emacs Keybinding for MS Office</name>
        <identifier>private.emacs_mode_for_msoffice</identifier>
        <only> EXCEL, POWERPOINT, WORD, EXCEL, ONENOTE </only>
        <include path="{{XML_INC }}/snippets/emacsmode_controlPNBF_ex.xml" />
    </item>
  </item>
</root>
---

root タグでくくられた範囲が設定として使用される。カスタムXMLはどうもデフォルトのXML群より先に読まれるっぽいので、ここで設定したエントリがGUIでは一番上にくるようだ。

replacement は要するに定数定義。後で出てくるが、今回 アプリの中に用意されている XMLの定義を流用したかったので、そこまでのパスを「XML_INC」という定数にしてしまった。
これぐらい組み込みの定義でありそうな気もするのだが、探すの面倒だった次第だ。

appdef はアプリケーションの名称を設定している。Mac のアプリケーションは CFBundleIdentifier と呼ばれるそのアプリ独自の名称を持っているが、CFBundleIdentifier は逆DNS記法で長ったらしいので分かりやすい名前をつけている次第だ。

様々なアプリケーションがKarabiner 内の appdef.xml であらかじめ定義されており、たとえば MS-Office の場合、EXCEL, WORD, POWERPINT, OUTLOOK などはすでに定義済みだ。
しかし、今回から増えた OneNote については定義がなかったので、ここで com.microsoft.onenote.mac という CFBundleIdentifier を持つアプリを ONENOTE と定義している。なお、CFBundleIdentifier については、そのアプリ内の Info.plist に記載されているが、Karabiner 付属の EventViewer でも確認ができる。


さて、item タグからが本来の設定だ。

item タグはGUI城で現れる各設定項目を示す。入れ子にすることも可能で、入れ子にすると親の name でのグループが作成される。Karabiner 標準では「General」などのグループがあるが、これは item タグの入れ子でできている。

別にグループを作る必要性はないが、ただ見た目的に、チェックボックスがいきなり現れているのはちょっとかっこわるかったので Private Settings というグループを作成した。

その中の item タグの Emacs Keybinding for MS Office が今回やりたかった設定項目だ。identifier はこの項目固有の名称、name は表示される項目名になる。
appendix タグでテキストを書いておくと説明書きを追加できるらしいが、今回は省いた。

only タグはその設定を有効にするアプリ名を記載する。このなかでは , を使うことで複数のアプリを指定できる。MS-Office に所属する主立ったアプリをここで指定している訳だ。

autogen タグによってどういったキーをリマップしていくかを記載するが、EmacsKeybinding の、特にカーソル移動の部分だけ場合、アプリの中にそれだけの定義を抜き出した XMLが存在する。

ここでは、include タグでその XMLを読み込むことで個別の定義を回避している。

なお、ここで先ほどの XML_INC の定数を参照している。(別にフルパスを書いてもいいのだが...。)
相対パスにした場合はどうもそのXMLファイルの位置からの相対になるようだ(未確認)。

この定義を private.xml に作成、保存した後にリロードすることで、設定が現れる。


後はチェックを入れるだけだ。軽く試した限りは、これでちゃんと動作しているようだ。



個人的に気になったのは、item にて挙動の定義と画面に表示されるデータが混在されていることにある。

ActiveDirectory のGPOの管理テンプレートでもあった失敗だが、挙動と表示を混ぜた定義を作ってしまうと I18Nのとき、名称や説明を現地の言葉にする場合にハマってしまう。

GPOの管理テンプレートの場合、それ以外の問題(例えば構文が独自だったのをXMLに更新したかったなど)もあり、動作を定義した ADMX ファイルと、言語ごとの表示内容を抜き出した ADML ファイルに分ける羽目になった。

管理テンプレートの例を出さずとも、OS X の Cocoa アプリのローカライズも、.lproj というフォルダを作成し、nib/xib といった表示されるオブジェクトの定義や strings といったメッセージを各言語ごと別に作る事でなされている。


Karabiner の場合も、item には identifier があるので、言語ごとのメッセージファイルを作成、identifier でローカライズされたメッセージと item を紐付ければいい、用に見えるが、ここで先の「item は入れ子にできる」が引っかかってくる。

そう、グループを作る親の item はname タグしかもっておらず、個別の identifier を持たない。つまり、各設定項目ごとは identifier で紐付けして別のファイルからメッセージを持ってこれるが、「General」などのグループ名に対するローカライズされたメッセージを紐付ける手段がない。


まあ、private.xml の説明が英語でしかなかったり、そもそもアプリの GUI も英語UIしかないので、そうした表示面でのローカライズについてはこれを行わない、というのがおそらく作者のポリシーなのだろう。Karabiner のアプリの立ち位置を考えると、別にそれは悪いことでもない。

2015/08/03

【余談】Karabiner でのキーリピート速度

これまで、ちょっとしたテキストやメモの共有には、OS X/iOS標準の「メモ」(Notes)を使っていた。

「メモ」(Notes)はバックエンドがIMAPなどメールサーバになっており、Gmail なりの適当なメールサーバさえ確保できれば簡単にドキュメントが同期できることと、Apple 系のデバイス間だけではなく、限定的にだが ExchangeServer を経由して Windows とも連携が可能なのが便利だったためだ。

そもそも、何故 IMAPをメモに...っていうのも理由があり、ExchangeServer がメールや予定等々を統一的なアクセス方法で扱えるようにしており、その中に「メモ」があったのが理由と思われる。( 古い Macユーザなら、Exchange サポートの入った前後の Mail.app に「メモ」がひっついてたのを覚えているだろうか? 要するにそういうことだ )

ところが、ExchangeServer 側がメモのサポートをやめようとしている。一応機能としては残っているが obsolete 扱いで、現在の Exchange 2013 + Outlook 2013 では、表示フォントの変更ができないなど以前にあった機能が欠落を始めている。


そんなこともあり、ちょっとしたテキストやメモの共有に OneNote を使い始めた。OneNote はフリーで使え、iOS でもアプリがある。仕事でも OneNote を使い始めたこともあって、移行先としては悪くないと思った次第だ。

多少の癖はあるが Mac 版の OneNote もそこそこできがいい。(IMAPやExchangeではなく) OneDrive を通じて同期し、人との共有も可能。賛否は分かれるがページ以外にもタブという概念があり、一次元ではなく二次元にメモを整理できる。また、オンラインアクセスできるのも悪くない。(iPhone でアクセスするときわめて使いにくく、PC/タブレット用と割り切る必要はあるが。)


さて、便利に使い始めた OneNote だが、Emacsキーバインドが使えないのだけが厄介であった。指がそっちに慣れているため、つい Ctrl-P を押してしまう、Ctrl-F, Ctrl-B でカーソルを動かそうとしてしまう、のでどうしてもストレスがたまる訳だ。

同じ事が Excel や PowerPoint でも起こっており、そろそろ年貢の納め時か、とあきらめ Karabiner を導入した。以前は KeyRemap4MacBook と呼ばれていたアプリで、 KEXT (カーネル拡張)を突っ込んでキーボードからの入力をいじってしまうというもの。トラブったときがやっかいなのでこの手合いのデバイスドライバはなるたけ避けていたのだが、背に腹はかえられぬ。実際、導入したら便利であった。

ただ、Karabiner を導入するとキーリピート速度の速度がなにやら遅い。見ると Karabina がリピートまでの認識時間とリピート速度を上書きしている、とある。

直したいのだが Karabiner ではミリ秒単位で値を設定するもので、さて Mac側の設定でどれが何ミリ秒になっているかわからないと設定しようがない。

仕方がないので、少し調べた。
Mac 側の設定は「defaults read -g | grep Repeat」あたりで検出できる。InitialKeyRepeat の値が「リピート認識までの時間」、KeyRepeat の値が「キーのリピート」での値だ。

しかし、この値はミリ秒ではない。出てきた値に 15をかけるとミリ秒になる。

図示すると、こんな感じだ。



値としては、以下の通りだ。

キーのリピート 遅い           早い
1800
1350
900
450
180
90
30

リピート入力認識までの時間 長い         短い
1800 
1470
1020
525
375
225

この値をかき込めば、Mac のときと同じになる。

ただ、微妙に妙な動作がでてしまう。例えば OmniGraffle でテキストフィールドで範囲選択中に Ctrl-A を押したときの挙動が、Karabiner の有無で異なる。

Notifier を使って Office アプリだけを有効にしたいのだが...、これは、XMLでの設定を書くことでできそうなのでまた試すとする。

--
8/4 タイトルのスペル間違えてたので修正。