世界を動かす技術を、日本語で。

ハマースプーン

2026年3月14日原文(github.com)

概要

  • Hammerspoon は、 OS X の高度な自動化ツール
  • Luaスクリプト でシステム機能を制御可能
  • 拡張機能 により多様な操作が可能
  • インストール方法 は手動またはHomebrew
  • 設定ファイル 作成が利用開始の第一歩

Hammerspoonとは何か

  • Hammerspoon は、 OS X の強力な自動化ツール
  • コア部分は オペレーティングシステムLuaスクリプトエンジン の橋渡し役
  • 拡張機能 (Extensions)がシステムの特定機能をユーザーに公開
  • Luaスクリプト を使い、多様なOS X環境の制御が可能

インストール方法

  • 手動インストール
    • 最新リリースをダウンロード
    • Hammerspoon.app をダウンロードフォルダから Applications へドラッグ
  • Homebrew利用
    • コマンド: brew install hammerspoon --cask

初期設定とリソース

  • デフォルト状態では 何も動作しない 仕様
  • 利用開始には ~/.hammerspoon/init.lua を作成し、スクリプトを記述
  • 参考リソース
    • Getting Started Guide (導入ガイド)
    • APIドキュメント
    • FAQ
    • ユーザーによるサンプル設定
    • Contribution Guide (開発者向けガイド)
    • IRCチャンネル (#hammerspoon on Libera)
    • Google Group (サポート用)

プロジェクトの歴史

  • HammerspoonMjolnir からのフォーク
  • Mjolnir は最小限のアプリを目指し、拡張機能を外部で管理
  • Hammerspoon はより統合された体験を提供

プロジェクトの今後

  • 拡張機能 によるシステムAPIのカバー範囲拡大
  • 拡張機能同士の 連携強化
  • ユーザー体験 の向上

Hackerたちの意見

これが俺の設定全部だよ。 hs.hotkey.bind({"ctrl"}, "D", function() hs.grid.show() end) 他のいろんなウィンドウマネージャーも試したけど、俺にとっては使いやすさが一番だね。 (1) Ctrl-Dでグリッドを表示、 (2) ウィンドウの左上のコーナーにしたい場所の文字を入力、 (3) 右下のコーナーにしたい場所の文字を入力でウィンドウがリサイズされる。

EOFを挿入することはあんまりないけど、ターミナルでCTRL+Dと競合しないの?

これすごい! 俺はもう少し複雑な設定をしてて、Appleが最近追加したような感じで、片側からリサイズできるようにしてるんだけど、もっと柔軟性があるんだ。 でもこれはめっちゃ面白いね、シェアしてくれてありがとう!

いい感じだけど、設定を同期させたり、複数のマシンを調和させる必要が出てくると、HammerspoonとLuaでドットファイルの頭痛が増える。 ウィンドウルールやアプリ固有の動作、モニターの変更を扱うような複雑なロジックを追加すると、そのホットキーのシンプルさが失われて、延々と調整が続くことになる。 それでも、マウスを使わずに済む数少ない柔軟な選択肢の一つだから、macOSでは古臭さを感じない。 どこにでもトレードオフがあるけど、他には本当にこのコントロール感に匹敵するものはないね。

わぁ…それは…すごいね。Hammerspoonをずっと使ってるけど、そんな機能があるなんて知らなかった。いじってたら、hs.grid.setGrid('4x4')でグリッドサイズを拡張できることに気づいたし、さらにhs.grid.ui.textSize = 30でテキストサイズを縮小することもできる。あと、代替キーボードレイアウト(例えばColemak)を使ってるなら、hs.grid.HINTSでそれを使うように設定できるよ。この機能、ほんとにすべてを考慮してるね。

Hammerspoonは俺のMacを支えてる重要な存在。 このアプリでやってることのスタートリストを少し紹介するね:

  • 開いてるSafariのタブをObsidianドキュメントにダンプ
  • 新しいウィンドウを開くための「hyper」(Ctrl-Opt-Cmd)キーを追加:
    • Safari
    • Finder
    • Terminal / Ghostty
    • VS Code
    • Notes
  • Hammerspoon/AeroSpace/Sketchybarの設定を編集
  • Hammerspoonの設定をリロード
  • Sketchybarをリロード
  • Finder以外のDockアプリを全部終了
  • スクリーンロック
  • システムスリープ
  • VS Codeで前面のFinderフォルダを開く
  • Archive.todayで前面のSafari URLを開く
  • 前面のSafariウィンドウのタブ数を表示
  • 前面のアプリのバンドルIDを表示
  • 現在の音楽トラックについて通知を投稿
  • Logi Litraライトをコントロール(色温度や明るさを調整)
  • クライアント作業タイマーをスタート/ストップ
  • AeroSpaceに連携して:
    • ウィンドウを別のモニターに移動
    • 2つのウィンドウレイアウトを実行
    • その2つのウィンドウを入れ替え
    • 他のワークスペースのウィンドウを全部閉じる
    • すべてのウィンドウを最初のワークスペースに集める
    • クラッシュした場合にバックグラウンドアプリを維持
    • ゴミ箱に入れたディスクイメージをアンマウントするように促す
  • Skimにバインドして、特定のセクションにジャンプするためのMarkdown URLを使う。

キーボード関連はKarabiner Elementsでやるのがいいよ。

  • 開いてるSafariのタブをObsidianドキュメントにダンプするの、私もやってみたい!どうやってるのか教えてくれない?それとも簡単すぎて説明する価値ない感じ?(HSについてはまだ深く見てないんだ。)

最近はほとんどこれを2つ(関連する)ことにしか使ってないんだ。 - 開いてるTeamsウィンドウのリストをチェックして、もし標準じゃないのがあったら、会議中だと思ってHomeAssistantにウェブフックして会議用ライトの「アクティブ」[2]プリセットを選ぶ。 - 自分の仕事のiCal[1]をダウンロードして、もし会議が近づいてたら(<~15分)、ウェブフック-HASSで会議用ライトの「保留」プリセットを使う。 [0] ただのWS2812Bの短いストリップをESP32に接続してWLEDを動かしてるだけ。 [1] 元々はoutlook.comの共有リンクにHTTPでアクセスしてたけど、認証が必要になっちゃった(共有リンクに認証が必要なんて、ほんとにクソだよね)。Azure SDKを見てみたけど、あれはもう訳がわからなかった。結局、仕事のiCalをAppleカレンダーにインポートして、そのリンクをHammerspoonで使うことになった。ああ、笑ったよ。特に「自分のカレンダー」には実際の会議の約40%しか入ってないことに気づいたときはね。なぜか「自分のカレンダー」は4つか5つの痛みの混合物で、「自分のカレンダー」のiCalはそのうちの一つだけ。しかも、役に立たないやつ。 [2] いろいろあって、「カメラ」は「カメラをオンにしなきゃいけない会議」、「アクティブ」は「多分話さなきゃいけない」、「パッシブ」は「話さないつもり」、「サイレント」は会社のプレゼンみたいに、Teamsで退屈なパワーポイントを見るだけの時に使ってる。

Hammerspoonでタイル型ウィンドウマネージャーを偽装して、特定のコーナーやサイズに合わせてリサイズしてるよ: -- 比率に基づいてリサイズする関数

function ratioResize(xr, yr, wr, hr)
  return function ()
    local win = hs.window.focusedWindow()
    win:moveToUnit({x=xr,y=yr,w=wr,h=hr})
  end
end

-- 4つのコーナー、異なるサイズ hs.hotkey.bind({"cmd", "ctrl"}, "w", ratioResize(0, 0, 2/5, 2/3)) hs.hotkey.bind({"cmd", "ctrl"}, "e", ratioResize(2/5, 0, 3/5, 2/3)) hs.hotkey.bind({"cmd", "ctrl"}, "s", ratioResize(0, 2/3, 2/5, 1/3)) hs.hotkey.bind({"cmd", "ctrl"}, "d", ratioResize(2/5, 2/3, 3/5, 1/3)) ウィンドウを他のモニターに移動するために: -- 次のスクリーンに送る hs.hotkey.bind({"cmd", "ctrl"}, ";", function() local win = hs.window.focusedWindow() local screen = win:screen() local next_screen = screen:next() win:moveToScreen(next_screen) end)

Aerospaceはめっちゃおすすめだよ!いくつかのアプローチを試したけど、セキュリティを妥協したくなかったから、i3から来た人にはすごく合うと思う。 https://github.com/nikitabobko/AeroSpace

俺も似たような使い方してるけど、サイドバイサイドや左、中、右のスポットも追加してる。これにはHammerspoonだけ使ってるけど、これだけでも全然価値があるよ。ウィンドウのサイズや位置を数学で指定するんだ。狂ってるよね。

local mode = hs.screen.primaryScreen():currentMode()
local mods = {"ctrl", "alt", "cmd"} -- そのキーを押しまくる --
local w = 1094 -- GitHubやHNではクリップなし
local h = 1122 -- 高め
local x_1 = 0 -- 左端
local x_2 = math.max(0, (mode.w - w - w) / 2) -- 左中
local x_3 = (mode.w - w) / 2 -- 中央
local x_4 = math.min(mode.w - w, x_2 + w + 1) -- 右中
local x_5 = mode.w - w -- 右端
local y = 23 -- メニューバーの下の画面上部

hs.hotkey.bind(mods, "2", function() move_win(0, y, mode.w, mode.h) end) -- 最大化
hs.hotkey.bind(mods, "3", function() move_win(x_1, y, w, h) end)
hs.hotkey.bind(mods, "4", function() move_win(x_2, y, w, h) end)
hs.hotkey.bind(mods, "5", function() move_win(x_3, y, w, h) end)
hs.hotkey.bind(mods, "6", function() move_win(x_4, y, w, h) end)
hs.hotkey.bind(mods, "7", function() move_win(x_5, y, w, h) end)

end

function move_win(x, y, w, h)
    hs.window.focusedWindow():setFrame(hs.geometry.rect(x, y, w, h))
end
Hacker Newsで議論の続きを見る