Carpe Diem

備忘録

yabaiを使ってホットキーのみでアプリを各仮想デスクトップに移動する方法

概要

自席では複数の外部ディスプレイを使っているため、

  • ターミナルは内蔵ディスプレイ
  • ブラウザは外部ディスプレイ1
  • Slackは外部ディスプレイ2

のように配置することが多い自分です。

また外部ディスプレイを使わない場合は、内蔵ディスプレイで

  • ターミナルは仮想デスクトップ1
  • ブラウザは仮想デスクトップ2
  • Slackは仮想デスクトップ4

のように配置しています。

問題はミーティングなどで外部ディスプレイを付けたり外したりする度に、上記のアプリの配置を手動で都度直さないといけない点です。

ただ残念ながら、よくあるウィンドウマネージャー・タイルマネージャーは仮想デスクトップ(Spaces)の操作まではできないため、この問題を解決することができませんでした。

しかしyabaiというツールは、SIPの一部をdisableにすることで上記を解決する事が可能です。

環境

  • macOS 15.1.1
  • yabai v7.1.5
  • skhd v0.3.9

対応方法

yabai は macOS 用のウィンドウマネージャで、非公開のAPIを利用して Spaces を含めた詳細なウィンドウ操作を行うことが可能です。

※加えてSIP(System Integrity Protection)の部分的な無効化を必要とする等、セキュリティリスクやmacOSのアップデートで動かなくなる可能性があります。

SIPの一部無効化

以下の手順をとることでSIPを部分的に無効化します。

  1. 電源を落とす
  2. リカバリモードで起動
    1. Loading startup optionsが出るまで電源ボタンを押す
  3. オプション > 自分のユーザでログイン > ユーティリティ > ターミナル
  4. csrutil enable --without fs --without debug --without nvramを入力
  5. 再起動し、通常モードへ
  6. ターミナルでsudo nvram boot-args=-arm64e_preview_abiを実行
  7. 再起動

ref: Disabling System Integrity Protection · koekeishiya/yabai Wiki · GitHub

yabai

次にyabai の設定です。

インストール

以下のコマンドでインストールします。

$ brew install koekeishiya/formulae/yabai
$ yabai --start-service

上記の中でアクセシビリティの許可などが必要になります。

rootユーザ許可

yabaiはmacOS Mach APIを使ってDock.appにコードを注入します。これにはroot権限が必要なため以下の設定をします。

echo "$(whoami) ALL=(root) NOPASSWD: sha256:$(shasum -a 256 $(which yabai) | cut -d " " -f 1) $(which yabai) --load-sa" | sudo tee /private/etc/sudoers.d/yabai

ref: https://github.com/koekeishiya/yabai/wiki/Installing-yabai-%28latest-release%29#configure-scripting-addition

設定ファイル

.config/yabai/yabaircというファイルを作成し、以下を記述します。

#!/usr/bin/env sh

#
# for this to work you must configure sudo such that
# it will be able to run the command without password
#
# see this wiki page for information:
#  - https://github.com/koekeishiya/yabai/wiki/Installing-yabai-(latest-release)#configure-scripting-addition
#
yabai -m signal --add event=dock_did_restart action="sudo yabai --load-sa"
sudo yabai --load-sa

yabaiのconfigは以下の順に読み込まれるので、$HOME/.yabaircでも大丈夫です。

  • $XDG_CONFIG_HOME/yabai/yabairc
  • $HOME/.config/yabai/yabairc
  • $HOME/.yabairc

設定ファイルを用意したらyabaiを再起動します。

$ yabai --restart-service

アプリを各Spacesへ送るスクリプトの用意

次にアプリを各Spacesへ送るスクリプトを用意します。

僕の環境では以下の様な状態で話を進めます。

ディスプレイ 仮想デスクトップ(Spaces)
内蔵ディスプレイ デスクトップ1〜5
外部ディスプレイ1 デスクトップ6〜7
外部ディスプレイ2 デスクトップ8

外部ディスプレイあり用

``.config/yabai/display2.sh

#!/usr/bin/env bash

# 1. すべてのウィンドウ情報をまとめて取得し、変数に格納
WINDOWS_JSON=$(yabai -m query --windows)

# 2. jq で Google Chrome のウィンドウ ID を取り出し
CHROME_ID=$(echo "$WINDOWS_JSON" \
  | jq '.[] | select(.app == "Google Chrome") | .id' \
  | head -n1)

# 3. jq で Slack のウィンドウ ID を取り出し
SLACK_ID=$(echo "$WINDOWS_JSON" \
  | jq '.[] | select(.app == "Slack") | .id' \
  | head -n1)

# 4. 取得できているかチェックしつつ操作
if [ -n "$CHROME_ID" ]; then
  yabai -m window "$CHROME_ID" --space 6
  yabai -m window "$CHROME_ID" --grid 1:1:0:0:1:1
else
  echo "Google Chrome のウィンドウが見つかりませんでした。"
fi

if [ -n "$SLACK_ID" ]; then
  yabai -m window "$SLACK_ID" --space 8
  yabai -m window "$SLACK_ID" --grid 1:1:0:0:1:1
else
  echo "Slack のウィンドウが見つかりませんでした。"
fi
  1. Google Chromeをデスクトップ6(外部ディスプレイ1)へ
  2. アプリを全画面表示に
  3. Slackをデスクトップ8(外部ディスプレイ2)へ
  4. アプリを全画面表示に

という設定です。

外部ディスプレイなし用

.config/yabai/default.sh

#!/usr/bin/env bash

WINDOWS_JSON=$(yabai -m query --windows)

CHROME_ID=$(echo "$WINDOWS_JSON" \
  | jq '.[] | select(.app == "Google Chrome") | .id' \
  | head -n1)

SLACK_ID=$(echo "$WINDOWS_JSON" \
  | jq '.[] | select(.app == "Slack") | .id' \
  | head -n1)

if [ -n "$CHROME_ID" ]; then
  yabai -m window "$CHROME_ID" --space 2
  yabai -m window "$CHROME_ID" --grid 1:1:0:0:1:1
else
  echo "Google Chrome のウィンドウが見つかりませんでした。"
fi

if [ -n "$SLACK_ID" ]; then
  yabai -m window "$SLACK_ID" --space 4
  yabai -m window "$SLACK_ID" --grid 1:1:0:0:1:1
else
  echo "Slack のウィンドウが見つかりませんでした。"
fi
  1. Google Chromeをデスクトップ2へ
  2. アプリを全画面表示に
  3. Slackをデスクトップ4へ
  4. アプリを全画面表示に

という設定です。

直接シェルスクリプトを実行してみて、期待する挙動になるか確認しておきます。

skhd

skhdはシンプルなホットキー設定ツールです。

一般的には各yabaiコマンドを色んなホットキーとして設定しますが、僕の場合は上記スクリプトを実行する設定のみします。

インストール

$ brew install koekeishiya/formulae/skhd
$ skhd --start-service

設定ファイル

.config/skhd/skhdrcというファイルを作り、以下を記述します。

shift + cmd - 1 : ~/.config/yabai/default.sh
shift + cmd - 2 : ~/.config/yabai/display2.sh

用意できたら設定をリロードします。

$ skhd --reload

動作確認

  • shift + cmd + 1を押したら外部ディスプレイなし用の配置に
  • shift + cmd + 2を押したら外部ディスプレイあり用の配置に

ということが確認できます。

まとめ

yabaiを使ってホットキーのみでアプリを各仮想デスクトップに移動する方法を説明しました。

同じような悩みを持っている人の参考になれば幸いです。

参考