Karabiner-Elements と Hammerspoon を持って Sierra に行こう

完全に出遅れた感のある内容ですが、Karabiner を捨て、Karabiner-Elements と Hammerspoon をインストールし、Sierra に移行しました。

Karabiner
Karabiner-Elements
https://pqrs.org/osx/karabiner/

Hammerspoon
http://www.hammerspoon.org/

追記: Sierra の標準機能でキーリマップする方法があったので Hammerspoon だけ握りしめて Sierra に来ました。
http://qiita.com/hetima/items/b475997008dabd567da0

Karabiner で行っていたカスタマイズは単純なリマップと、「かな」キーをモデファイキーとして使い、空打ちした場合「かな」を出力するというものでした。試しに作ってみた程度で本格的には導入していませんでしたが。

とりあえず空打ち可能なモデファイキーを Hammerspoon で実現することにしました。どうせなら汎用的に使えるようなものにしようとライブラリを作りました。

hyperex
https://github.com/hetima/hammerspoon-hyperex

というわけでこの記事は実質的に hyperex の宣伝です。

僕の init.lua はこんな風になっています。

local KEY_EISU = 0x66; local KEY_KANA = 0x68;
local KEY_LBRA = 30; local KEY_RBRA = 42;
local KEY_ATMARK = 33; local KEY_COLON = 39;

local hyperex = require('hyperex')
local hx = hyperex.new('f18'):setInitialKey(KEY_EISU):setEmptyHitKey(KEY_KANA)
hx:bind(KEY_LBRA):to('8', {'shift'}) --(
hx:bind(KEY_RBRA):to('9', {'shift'}) --)
hx:bind(KEY_ATMARK):to('3', {'shift'}) --#
hx:bind(';'):to('2', {'shift'})
hx:bind(KEY_COLON):to('7', {'shift'})
hx:mod({'cmd'}):to('any')

冒頭でよく使うキーを定数化しています。

local hyperex = require('hyperex')
local hx = hyperex.new('f18')

hyperex.luainit.lua と同じ ~/.hammerspoon に配置して require() で読み込み、new()インスタンスを作ります。
コンストラクタにモデファイキーにしたいキーを渡します。かな キー(PC 用キーボードなので正確には変換キー)を Karabiner-Elements で F18 にリマップしているので、このインスタンスかな キーを押したときに作動します。リマップした理由は後述します。

hx:setInitialKey(KEY_EISU):setEmptyHitKey(KEY_KANA)

コンストラクタに続けてメソッドチェーンで設定をしています。setInitialKey() は基本キーが押されると同時に出力されるキーです。この例では かな を押すとただちに 英数 が出力されます。

setEmptyHitKey() は基本キーを押したけれど何もせずに離した場合に出力されるキーです。いわゆる空打ちです。この例では かな が出力されます。Hammerspoon では hotkey に使ったキーと同じキーを含むイベントを直後に送出できない仕様があります。ここで かな を出力するためには かな 以外のキーを基本キーにしないといけないのでリマップしているというわけです。

これらの設定はもちろん省略可能で、何も設定しなければプレーンなモデファイキーとして動作します。

hx:bind(';'):to('2', {'shift'})

初期設定が終わったらショートカットを登録していきます。例えばこれは基本キーを押しながら ; キーを押したら shift+2 を出力するという設定です。

hx:mod({'cmd'}):to('any')

そして最後のこれは、すべてのキーに cmd モデファイアを付け足して出力するという設定です。基本キー+a などと打ったら cmd+a が出力されます。基本キー+shift+a などと他のモデファイキーも押していたら cmd+shift+a となります。
hotkey に使ったキーと同じキーは使えないと書きましたが、hyperex で hotkey を使っているのは最初に押す基本キーだけで、他は eventtap を使っているのでこういうことが可能です。
対象キーが重複する場合は、先に設定した方を優先します。また、 mod() よりも bind() が常に優先されます。

mod() を活用すれば「矢印キーは cmd+opt+矢印、FKey は cmd+ctl+* その他は cmd+*」というような変則的なモデファイキーも作れます。

hx:mod({'cmd', 'alt'}):to('left', 'right', 'down', 'up')
hx:mod({'cmd', 'ctrl'}):to('fkeys')
hx:mod({'cmd'}):to('any')

追記:モデファイキーを hyperex の基本キーに設定できるようアップデートしました。左右のコマンドキーを空打ちするとそれぞれ 英数かな に変更する設定はわずか2行です。

local hxLCmd = hyperex.new('cmd'):setEmptyHitKey(0x66)
local hxRCmd = hyperex.new('rightcmd'):setEmptyHitKey(0x68)

これまで Lua には触れたことがなく多少の不安がありましたが、変態的で面白い言語ですね。

追記:ターミナル.app の「キーボード入力のセキュリティを保護」をオンにしていると、Hammerspoon の eventtap 監視機能が無効になるようです(keyStroke や hotkey は使えます)。hyperex はこの影響を受けます。保護オンにしたまま回避するのは難しいと思われます。