Vim
Mac
Sierra
Hammerspoon

MacOS Sierra で入力ソースの切り替えのキーバインドを設定する(HammerSpoon)

More than 1 year has passed since last update.

はじめに

MacOS Sierra ではキーバインド変更アプリのKarabinerが利用できない。(Karabiner-Elementsのみ)
よってこれまでKarabinerで実現していた以下の機能を実現するアプリとしてHammerSpoon( http://www.hammerspoon.org/ )を利用する。

  • SHIFT+SPACEによる日本語入力切替
  • ESC押下に英数押下のアクション追加(vimのエディットモードをESCで抜ける際に日本語入力を解除するため)

Sierraにアップデートする前に「El Capitan」での動作確認を行なっているためこのバージョン以降であれば動作する。

環境情報

OS: 10.12.6 (MacOS Sierra)
HammerSpoon: 0.9.55

HammerSpoon設定

設定作成/反映

メニューバーのアイコンを押下し、「Open Config」を選択すると設定ファイルのinit.luaがエディタで開かれる。

init.luaにluaで設定(コード)を記述し、再度メニューバーのアイコンから「Reload Config」を選択し設定を反映させる。

メニュバーから「Console」選択すると、設定読み込みの様子やエラーの確認ができるコンソールが開く。
コンソールの下部にはプロンプトも用意されているので、コードの断片のデバッグなどに利用できる。

なおメニューバーの「Preference」を選択し表示される設定画面下部の「Accessibility」が「Disable」だと利用できる機能に制限が発生する。(例:hs.eventtap.event.types.keyDown/keyUp)
特に理由がなければ「Enable」にする。そして「Enable」にした後、必ずHammerSpoonを再起動すること。

init.lua

「hs」で始まる変数でHammerSpoonのAPIが利用できる。
APIの詳細はここから

init.lua
-----------------------------------------------------------------------------------
-- define const vars
-----------------------------------------------------------------------------------
---------------------
-- modifire keys
---------------------
--local MOD_COMMAND        =  55 --hs.keycodes.map['cmd']
--local MOD_SHIFT          =  56 --hs.keycodes.map['shift']
--local MOD_ALT            =  58 --hs.keycodes.map['alt']
--local MOD_CTRL           =  59 --hs.keycodes.map['ctrl']
---------------------
-- general keys
---------------------
local SPACE              =  49 --hs.keycodes.map['space']
local ESCAPE             =  53 --hs.keycodes.map['escape']
local KEY_CODE_JIS_EISUU = 102
--local KEY_CODE_JIS_KANA  = 104
---------------------
-- application names
---------------------
--local VIM_BINDING_APPS = {
--  "ターミナル", "iTerm2", "Boostnote"
--}

-----------------------------------------------------------------------------------
-- define functions
-----------------------------------------------------------------------------------
--------------------------------------------------------
-- constract function of  executing multiple functions.
--------------------------------------------------------
local function multiFunc(functions)
   return function()
      for i, func in ipairs(functions) do
         func()
      end
   end
end

--------------------------------------------------------
-- constract tap (press and release) key function. 
--------------------------------------------------------
local function tapKey(mods, key)
   mods = mods or {}
   return function()
      hs.eventtap.event.newKeyEvent(mods, key, true):post()
      hs.timer.usleep(1000)
      hs.eventtap.event.newKeyEvent(mods, key , false):post()      
   end
end

--------------------------------------------------------
-- set hotkey. (remap)
--------------------------------------------------------
local function remapKey(mods, key, tapKeyFunc)
   hs.hotkey.bind(mods, key, tapKeyFunc, nil, tapKeyFunc)
end

--------------------------------------------------------
-- handle key action event.
--------------------------------------------------------
local function keyactionEventHandler(e)
   local keycode = e:getKeyCode()
   --hs.alert(keycode)          
   if keycode == ESCAPE then
     hs.eventtap.event.newKeyEvent({}, KEY_CODE_JIS_EISUU, true):post()
   end
end

-----------------------------------------------------------------------------------
-- remap keys
-----------------------------------------------------------------------------------
--global
remapKey({'shift'}, SPACE, tapKey({'cmd'}, SPACE))

--for vim editor.  
--remapKey({}, ESCAPE, multiFunc({
--    tapKey({}, ESCAPE),
--    tapKey({}, KEY_CODE_JIS_EISUU)
--}))

-----------------------------------------------------------------------------------
-- listen event
-----------------------------------------------------------------------------------
local keyactionEventListener = hs.eventtap.new({
                          hs.eventtap.event.types.flagsChanged,
                          hs.eventtap.event.types.keyDown,
                          hs.eventtap.event.types.keyUp
                      }, keyactionEventHandler)
keyactionEventListener:start()

設定概要

日本語入力切り替えはホットキーで、ESC押下時の動作はイベントハンドリングにより実現。
(現状は利用していない設定や関数も含んでいるが、今後のためにある程度事前に用意。)

ESC押下時の動作をホットキーで実現すると、ESC押下してから反応するまでに1秒程度のタイムラグが発生するため不採用。
(複数のアクションを実行する参考例としてコメントアウト。)

--for vim editor.  
--remapKey({}, ESCAPE, multiFunc({
--    tapKey({}, ESCAPE),
--    tapKey({}, KEY_CODE_JIS_EISUU)
--}))

ホットキーの設定はremapKey関数で行う。remapKey関数の第1、第2引数で指定したホットキー押下時に、第3引数で指定した関数を実行する。
第3引数で利用しているtapKey関数は指定したキーの「押す」「離す」を1[msec]間隔で行う関数を返却する。

multiFunc関数を利用すれば、複数のアクションを1つのホットキーに割り当てることができる。(現状は利用していない)

キーに関するイベントの監視はkeyactionEventListenerで行なう。
hs.eventtap.event.typesの後に続くものが定義されたイベント。

  • 修飾キーのイベント: flagsChanged
  • 一般キーのイベント: keyDown/keyUp

修飾キー(modifires)のイベントはkeyDown/keyUpでは取得できない為、注意が必要。

参考

http://qiita.com/naoya@github/items/81027083aeb70b309c14
http://mizoguche.info/2017/01/hammerspoon_for_sierra/
http://kitak.hatenablog.jp/entry/2016/11/28/104038
http://rochefort.hatenablog.com/entry/2017/02/25/070000
http://virtnote.blogspot.jp/2017/04/hammerspoon.html