Help us understand the problem. What is going on with this article?

Karabiner 使えない対策: Hammerspoon で macOS の修飾キーつきホットキーのキーリマップを実現する

More than 3 years have passed since last update.

背景

http://qiita.com/naoya@github/items/56a34be85710f4ed5531 でも書いたとおり Karabiner が使えない現状、修飾キーつきのホットキーのカスタマイズをどうするかという問題がある。記事を書いた時点では macOS の DefaultKeybidings.dict でショートカットを定義していたが、Hammerspoon を使うことでやりたいことが実現できたので、こちらの方法に移行した。

課題に感じてたこと

こちらのコメントに書いたとおり、DefaultKeyBiding.dict では特定のキーイベントを別のキーイベントに変換するという指定はできない。おかげで Karabiner のときにカスタマイズしていた挙動を再現できなかった。

それ Hammerspoon でできるよ

Hammerspoon は macOS の挙動を自動化するためのツール。自動化の処理を Lua で書けるフレームワークみたいなもの。キーリマップだけが目的のソフトウエアではないが、それにも使える代物。

Hammerspoon で、やっと Karabiner と同じ挙動を再現できた。keyhac のときのように iTerm2 のキーリマップ機能とコンフリクトを起こしたりといった不具合も今のところ起きていない。

init.lua

試行錯誤の末、~/.hammerspoon/init.lua を以下のように書いた。

local function keyCode(key, modifiers)
   modifiers = modifiers or {}
   return function()
      hs.eventtap.event.newKeyEvent(modifiers, string.lower(key), true):post()
      hs.timer.usleep(1000)
      hs.eventtap.event.newKeyEvent(modifiers, string.lower(key), false):post()      
   end
end

local function remapKey(modifiers, key, keyCode)
   hs.hotkey.bind(modifiers, key, keyCode, nil, keyCode)
end

local function disableAllHotkeys()
   for k, v in pairs(hs.hotkey.getHotkeys()) do
      v['_hk']:disable()
   end
end

local function enableAllHotkeys()
   for k, v in pairs(hs.hotkey.getHotkeys()) do
      v['_hk']:enable()
   end
end

local function handleGlobalAppEvent(name, event, app)
   if event == hs.application.watcher.activated then
      -- hs.alert.show(name)
      if name ~= "iTerm2" then
         enableAllHotkeys()
      else
         disableAllHotkeys()
      end
   end
end

appsWatcher = hs.application.watcher.new(handleGlobalAppEvent)
appsWatcher:start()

-- カーソル移動
remapKey({'ctrl'}, 'f', keyCode('right'))
remapKey({'ctrl'}, 'b', keyCode('left'))
remapKey({'ctrl'}, 'n', keyCode('down'))
remapKey({'ctrl'}, 'p', keyCode('up'))

-- テキスト編集
remapKey({'ctrl'}, 'w', keyCode('x', {'cmd'}))
remapKey({'ctrl'}, 'y', keyCode('v', {'cmd'}))

-- コマンド
remapKey({'ctrl'}, 's', keyCode('f', {'cmd'}))
remapKey({'ctrl'}, '/', keyCode('z', {'cmd'}))
remapKey({'ctrl'}, 'g', keyCode('escape'))

-- ページスクロール
remapKey({'ctrl'}, 'v', keyCode('pagedown'))
remapKey({'alt'}, 'v', keyCode('pageup'))
remapKey({'cmd', 'shift'}, ',', keyCode('home'))
remapKey({'cmd', 'shift'}, '.', keyCode('end'))
  • キーリマップ
  • アプリの切り替えを監視して、対象が iTerm2 だったらキーリマップを無効にする

という二点をやっている。後者を入れないと iTerm2 上でもキーリマップが作用してシェルや Emacs を使ってるときに不都合がありまくったので、こうした。

参考情報

Hammerspoon のバージョン

Version 0.9.50

スクリーンショット 2016-11-23 12.09.36.png

ikyu
「こころに贅沢を」をコンセプトに一休.com、一休レストランなどのサービスを提供しています。
https://www.ikyu.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away