morisolog

ソフトウェア関連の技術書まとめ:新卒3年目エンジニア

HammerspoonでAlacrittyにHotkeyを設定してみた。

最近メインで使うターミナルエミュレータをiTerm2からAlacrittyに移した。

iTerm2ではHotkeyを設定してCtrlキー2回押しで表示/非表示を切り替えていたが、 AlacrittyはHotkeyを標準搭載していないようだった。

AlacrittyでもHotkeyを使えないか調べていると、HammerspoonというMacの自動化ツールが使えそうだったので採用してみる。

なお、環境は macOS Monterey 12.2 です。

Hammerspoon

Hammerspoonは、macの自動化ツール。Luaというスクリプト言語を用いて、キーボードショートカットと一連のウィンドウ操作などのアクションを紐付けることができる。

他にも、Wifiの接続先が切り替わったタイミングで任意のコマンドを実行したり、バッテリーが一定以下になるとアラームを飛ばすなんてこともできるらしい。

まずはhomebrewでインストール。

brew install hammerspoon --cask

Hammerspoonはインストールしただけでは何もしてくれないので、~/.hammerspoon/init.luaLuaスクリプトを作成。

この中に設定を記述していく。

設定: ちょっと寄り道

公式の Getting Started のページ見たら、「とりあえずHelloWorldしてみなはれ」と言われたので、そうしてみた。

~/.hammerspoon/init.lua

hs.hotkey.bind({"cmd", "alt", "ctrl"}, "W", function()
  hs.alert.show("Hello World!")
end)

ファイルを保存して、macメニューバーのHammerspoonアイコンをクリック > Reload Configを選択する。

++ctrl+wを押すと、画面にHelloWorldが通知された!

Hello World 通知のようす(3回連打した)
Hello World 通知のようす(3回連打した)

これだけでもう、Hammerspoonで未来が開けそう感!

他にもかなりの数のチュートリアルが用意されているので、あさってみるだけでも楽しそう。

Hotkeyを設定する

キーイベントを検知して Alacrittyの起動 & 表示 / 非表示をやってくれるスクリプトを書く。

hs.hotkey.bind({ "cmd", "ctrl" }, "e", function()
  local appName = "Alacritty"
  local app = hs.application.get(appName)

  if app == nil or app:isHidden() then
    hs.application.launchOrFocus(appName)
  else
    app:hide()
  end
end)

アプリケーションは、Hammerspoon APIhs.application で操作できるようになっている。

これで、+ctrl+eを押すとiTerm2のHotkeyにかなり近い操作ができる。

ただし、ctrl 2回押し のキーイベントを検知してほしいので、もう一工夫必要になる。

Stack over flow によると、どうやら面倒なことやらないといけないらしい。

stackoverflow.com

hammerspoon double keyでググったら、ctrl 2回押し のキーイベントを検知して任意のfunctionを実行できるモジュールが公開されていた✌️

gist.github.com

これを、~/.hammerspoon/ctrlDoublePress.luaに保存して、init.luaから呼び出す。

init.lua

local double_press = require("ctrlDoublePress")

local open_alacritty = function()
  local appName = "Alacritty"
  local app = hs.application.get(appName)

  if app == nil or app:isHidden() then
    hs.application.launchOrFocus(appName)
  else
    app:hide()
  end
end

double_press.timeFrame = 0.5
double_press.action = open_alacritty

これでHotkeyの設定できた!

hotkey
hotkey

アクティブウィンドウ上でAlacrittyの表示 / 非表示ができるようにする

このままだと、アクティブなウィンドウが切り替わって使いにくい。どういうことかというと、

  1. まずデスクトップ 1 で Alacritty を開く
  2. その後デスクトップ 2 に移動して Chrome を起動
  3. その場でHotkeyすると、デスクトップ 2 に Alacritty を移してほしいが、実際にはデスクトップ 1 にフォーカスが移動して Alacritty が開く

これを解決するために、Hammerspoonの外部モジュールであるhs.spacesを使う。

github.com

インストール手順

$ cd ~/Downloads
$ git clone git@github.com:asmagill/hs._asm.spaces.git
$ cd hs._asm.spaces
$ make install

最後にmake installコマンドを実行することで、~/.hammerspoon配下にモジュールを作成してくれる。

最終的にはこのようなディレクトリ構成になった。 hs配下は全て、さっきのmakeコマンドで作ってくれたもの。

.hammerspoon
├── hs
│   ├── libspaces.dylib.dSYM
│   │   └── Contents
│   │       ├── Resources
│   │       │   └── DWARF
│   │       │       └── libspaces.dylib
│   │       └── Info.plist
│   ├── libspaces_watcher.dylib.dSYM
│   │   └── Contents
│   │       ├── Resources
│   │       │   └── DWARF
│   │       │       └── libspaces_watcher.dylib
│   │       └── Info.plist
│   ├── libspaces.dylib
│   ├── libspaces_watcher.dylib
│   ├── spaces.docs.json
│   └── spaces.lua
├── ctrlDoublePress.lua
└── init.lua

init.lua の中身はこう。

local application = require("hs.application")
local spaces = require("hs.spaces")

local double_press = require("ctrlDoublePress")

local open_alacritty = function()
  local appName = "Alacritty"
  local app = application.get(appName)

  if app == nil then
    application.launchOrFocus(appName)
  elseif app:isFrontmost() then
    app:hide()
  else
    local active_space = spaces.focusedSpace()
    local alacritty_win = app:focusedWindow()
    spaces.moveWindowToSpace(alacritty_win, active_space)
    app:setFrontmost()
  end
end

double_press.timeFrame = 0.5
double_press.action = open_alacritty

appNameを変えれば、Python製ターミナルエミュレータkittyとかにもHotkeyが設定できる。

僕のdotfilesはこちら

github.com