ハクソク

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

ハマースプーン

概要

  • 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でタイル型ウィンドウマネージャーを偽装して、特定のコーナーやサイズに合わせてリサイズしてるよ: -- 比率に基づいてリサイズする関数 ```lua 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だけ使ってるけど、これだけでも全然価値があるよ。ウィンドウのサイズや位置を数学で指定するんだ。狂ってるよね。 ```lua 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 ```
Moomは本当に最高だね。
miroウィンドウマネージャープラグイン、めっちゃ好き!: https://github.com/miromannino/miro-windows-manager いろんなケースに合わせて半分や三分の一の設定を試せるのがいいよね。
https://github.com/peterklijn/hammerspoon-shiftit ShiftIt(素晴らしいプロジェクトだけど、もう終わってる)をHammerspoonで再実装して使ってるよ。すごく充実してる。
Zoomの画面共有コントロールを隠すために使ってる。 Escを押しても戻ってこないようにするために: -- Zoomの「共有」ウィンドウを隠す ```lua local zoomWindow = nil local originalFrame = nil hs.hotkey.bind({"cmd", "ctrl", "alt"}, "H", function() print("> Zoomを隠そうとしてる") if not zoomWindow then print("> ウィンドウを探してる") zoomWindow = hs.window.find("zoom share statusbar window") end if zoomWindow then print("> ウィンドウを見つけた") if originalFrame then print("> 復元中") zoomWindow:setFrame(originalFrame) originalFrame = nil zoomWindow = nil else print("> 隠してる") originalFrame = zoomWindow:frame() local screen = zoomWindow:screen() local frame = zoomWindow:frame() frame.x = screen:frame().w + 99000 frame.y = screen:frame().h + 99000 zoomWindow:setFrame(frame) end else print("> ウィンドウが見つからない") end end) ```
まじで、これだけのためにインストールする価値ありすぎ!
特定のUSBハブにMacBookを接続/切断するときにWi-Fiをオン/オフするために使ってる: ```lua local usbWatcher = hs.usb.watcher.new(function(device) if device.productName == "EMEET SmartCam C960" then if device.eventType == "added" then hs.execute("networksetup -setairportpower en0 off") hs.notify.new({title="Wi-Fi", informativeText="無効化(USBデバイス接続中)"}):send() elseif device.eventType == "removed" then hs.execute("networksetup -setairportpower en0 on") hs.notify.new({title="Wi-Fi", informativeText="再有効化(USBデバイス取り外し)"}):send() end end end) usbWatcher:start() ```
Ethernetアダプタが優先度高ければ、そんなことは必要ないはずだよ。とはいえ、他の理由があるかもね。 https://support.apple.com/en-ca/guide/mac-help/mchlp2711/mac
macOS用のウィンドウ管理ツールを探してたんだけど、RectangleやMagnetを試して、他にもいろいろ試したよ。そしたらHammerspoonがあることに気づいて、ウィンドウを自分好みに再現できるんだ。もう1年使ってるけど、99%完璧だよ。特定のアプリ(くっ、Firefox)でたまに変な状態になることもあるけど、それは我慢できる。アクティブなWi-Fiとモニターの設定を組み合わせて、家にいるのか、仕事中なのか、家で仕事してるのかを検出して、特定のレイアウトに一発でウィンドウを並べられるのもいいね。
Moomはめっちゃ使いやすいよ。
ちょっと宣伝させてね - https://github.com/agzam/spacehammer "Spacemacs|DoomにインスパイアされたHammerspoonモーダルツールキット" これなしではMacで作業できないよ。例えば「alt+spc a b」(アプリ -> ブラウザ)や「alt+spc m j/k」(メディア -> 音量アップ/ダウン)とか、どんなアプリのテキストもエディタ(今はEmacs)で編集できるんだ。スペルチェックやシソーラス、翻訳、LLMなど、いろんなツールが使えるよ。お気に入りのWM(今はYabai使ってる)に接続して、他にも面白いことがたくさんできる。Fennelで書かれてるから、接続されたREPLでフィードバックループを使って開発できるんだ。例えば、ClaudeにSlackアプリやFirefoxの中を見てもらったり、面白い自動化を作ったりできる。エディタから離れずにね。
> 「alt+cmd m j/k」(メディア -> 音量アップ/ダウン)キーボードに音量調整のボタンが付いてたらなぁ…あ、待って。タッチバーのMacを使ってるなら、そりゃ理解できるけどね。
Hammerspoonで作ったもの、使ってみて! - macOSのどこでもVimモード: https://github.com/dbalatero/VimMode.spoon - 修飾キー+クリック/ドラッグでウィンドウをリサイズまたは移動: https://github.com/dbalatero/SkyRocket.spoon - 修飾キーを押し続けると、すべてのキーバインドのオーバーレイヘルパーを表示: https://github.com/dbalatero/HyperKey.spoon あと、私のランダムなスクリプトや設定の山: https://github.com/dbalatero/nixpkgs/tree/main/home/modules/...
Hammerspoonのメンテナーだよ - みんなのコメントを読んで楽しんでるし、今は主にv2に取り組んでるから、みんながイライラしないことを願ってる。LuaからJavaScriptに切り替えるんだ:D
> v2 ATMがLuaからJavaScriptに切り替わるみたいだね :D たぶん、[カレンダーをチェック] 18日後にリリースされるのかな?
この切り替えは開発者の使いやすさのためなのか、それとも言語の人気のためなのか、ちょっと気になるな。
HammerspoonはLuaを書く唯一の理由なんだ。実はこの言語がすごく好きなんだよね。JavaScriptの方が実用的な選択だとは思うけど、それでもちょっと悲しいな。
これで数年前にJavaScriptを追加したAppleScriptとの相乗効果が生まれるかな?
Appleが何年も放置してきたことをやってくれて本当にありがとう!AppleScript/JXAを放置してたのは犯罪だよ。