Hammerspoonは、macOSでキー入力やウィンドウ操作をLuaスクリプティングでカスタマイズできる便利なアプリです。
特にキーマッピングを変更するhs.hotkey.bind
は便利なAPIですが、デフォルトの処理も行われなくなるのでたまに困る場面があります。
例えば、escapeキーを押した時に、普通のエスケープ処理に加えてIMEを英数モードにするみたいなことをしたいときにはhs.hotkey.bind
は使えません。
正確には、一時的にbindを解除しておいてデフォルト処理のためのイベントを発火して、タイマーで再度bindを有効化するみたいな処理を書けば使えなくはないのですが、これはあまり良い設定方法ではありません。
こういう場面ではhs.eventtap.new
を使ってキーが押されたときに処理を差し込むことで綺麗に設定できます。
switchToEisuOnEscape = hs.eventtap.new({hs.eventtap.event.types.keyDown}, function(e) if hs.keycodes.map[e:getKeyCode()] == 'escape' then hs.eventtap.keyStroke({}, 'eisu', 0) end end):start()
switchToEisuOnEscape
はグローバル変数で参照されていませんが、こうしておかないとGCが走ってeventtap
が動かなくなるので、こういうものをグローバル変数に入れておくのはHammerspoonの設定あるあるです (参考)。
ここからが本題ですが、皆さんはコロンとセミコロンを入れ替えていますか?
この記事に辿り着いた皆さんはVimを使う英字キーボードユーザーだと思うのですが、当然なんらかの方法でコロンとセミコロンは入れ替えていますよね?
そういう場面でもhs.hotkey.bind
よりもhs.eventtap.new
を使う方が良いでしょう。
swapColonAndSemicolon = hs.eventtap.new({hs.eventtap.event.types.keyDown}, function(e) if hs.keycodes.map[e:getKeyCode()] == ';' then remappingColonAndSemicolon = not remappingColonAndSemicolon if remappingColonAndSemicolon then hs.eventtap.event.newKeyEvent(hs.keycodes.map.shift, not e:getFlags().shift):post() hs.eventtap.event.newKeyEvent(';', true):post() return true end end end):start()
コロンまたはセミコロンが押されたときにシフトキーの状態をトグルして、再度セミコロンキーをkey-downするイベントを発火します (hs.eventtap.event.newKeyEvent
の第二引数がkey-downかkey-upかを表すbooleanです)。
ここで発火したイベントに対してもeventtap
が反応してしまうので、booleanのグローバル変数で処理が無限再帰してしまわないようにしています。
true
を返してイベントの伝搬を止めているのも重要なポイントです。
この設定ならキーリピート時にもきちんと動作してとても便利です。
私は最近までhs.hotkey.bind
を使ってコロンとセミコロンを入れ替えていたのですが、いつの間にかリマップの処理に時間がかかるようになってしまい (:q
と押したつもりがq:
になるなど)、またキーリピート時にも思うように動作しなくなってしまいました。
コロンを打ったあとは気持ち少し待つみたいにしてしばらくは頑張っていたのですが、設定をちゃんと見直したところhs.eventtap.new
を使う方が良いということがわかりました。
Hammerspoonを使っていて困っている方にお役に立てると幸いです。