デュアルディスプレイの「見えない画面」問題、Stream Deckで解決した話

💻 デュアルディスプレイの「見えない画面」問題、Stream Deckで解決した話

10分で読めます

こんにちは。あでぃです。

「見えない画面」という地味なストレス

デュアルディスプレイって便利ですよね。作業効率は上がるし、情報はたくさん表示できる。
でもこんな状況、心当たりありませんか?

  • メインディスプレイをゲーム機に切り替えたら、一部のウィンドウが行方不明になる
  • macOS側はまだ「そこ」に画面があると思っているから、Discordのウィンドウが消えていく
  • ゲーム中にDiscordで通話したいのに、操作不能。Alfredもメインディスプレイにでるので見えない。

ゲーム中だってDiscordは繋ぎっぱなしだし、攻略サイトも見たいじゃないですか。
良いディスプレイを2枚揃えるのは予算的にもスペース的にもしんどいので、僕はメインディスプレイとゲーム機を共用しつつ、サブにモバイルモニターを使っています。

で、これを解決するには「ミラーリング」に切り替えればいいんですが、ゲームのたびに毎回システム設定を開くの、流石に面倒すぎませんか?

というわけで、Stream Deckのボタン一発で切り替えられるようにしてみました。快適。

僕の環境

参考までに、僕の環境はこんな感じです。

  • メインディスプレイ(28インチ)
    • HDMI1: Macmini
    • HDMI2: ゲーム機(キャプチャーボードのパススルー)
  • サブディスプレイ(13インチ モバイルモニター)
    • HDMI: Macmini

普段の作業時は、当然「拡張ディスプレイ」として広々と使っています。
コードを書きながらブラウザを見たり、Discordで通話しながら作業したり。快適ですね。

しかし、ゲームを始める時にメインディスプレイの入力をHDMI2に切り替えると

  1. メインディスプレイにはゲーム画面が映る
  2. でもmacOSはまだメインディスプレイに出力し続けている
  3. 結果、見えない幽霊画面が存在する状態になる

といった具合になり。そして、Discordのウィンドウがそこに行くと操作不能。ブラウザのウィンドウも見えない画面に消える。マウスカーソルすら行方不明になる。
これが地味に、でも確実にストレスを積み上げてくるわけです。

解決策:ミラーリングモードの活用

解決策自体はシンプルです。ゲーム開始時にサブディスプレイを「ミラーリングモード」に切り替える。これだけ。
そうすればmacOSの画面は全てサブディスプレイに集約されるので、操作不能になることはありません。
ゲーム終了後は拡張ディスプレイに戻せば、作業時の快適な環境が戻ってきます。

でも、この切り替え自体もシステム環境設定を開いて...ディスプレイ設定を選んで...ってやるの、正直面倒ですよね。「今すぐ変えたい」が実現できないし。
今回は、これをStream Deckのボタン1つで自動化する方法を紹介します。

環境

  • macOS Sonoma

必要なツール

1. displayplacer

macOSのディスプレイ設定をコマンドラインから制御できるツールです。これが今回の主役ですね。

brew tap jakehilborn/jakehilborn
brew install displayplacer
2. Automator(macOS標準)

作成したシェルスクリプトをアプリケーション化するために使用します。
「え、直接スクリプト叩けばよくない?」と思うじゃないですか。僕もそう思ったんですが、これがないとStream Deckの標準機能ではうまく動かないんですよね(後述)。
スクリプトを実行するための有料プラグインも存在するみたいですが、標準機能でできることは標準機能でやりたい派です。

実装手順

Step 1: 現在のディスプレイ設定を取得

まずは現状把握からですね。以下のコマンドで構成を確認します。

displayplacer list

すると、接続されているディスプレイの詳細情報がズラーっと出てきます。
めちゃくちゃ長いので、ひるまずに見てください。

Persistent screen id: [モニター1ID]
Type: 28 inch external screen
Resolution: 2560x1440
Origin: (0,0) - main display
...

Persistent screen id: [モニター2ID]
Type: 13 inch external screen
Resolution: 1920x1080
Origin: (-1920,154)
...

大事なのは以下の3つ。

  • Persistent screen id: ディスプレイの固有ID
  • Resolution: 解像度
  • Origin: 配置座標(どの位置に置かれているか)

そして一番重要なのが、出力の最後に表示されるコマンドです。

Execute the command below to set your screens to the current arrangement.

displayplacer "id:[モニター1のID] res:2560x1440 ..." "id:[モニター2のID] res:1920x1080 ..."

これ、ミラーリングから拡張に戻すときに死ぬほど重要な情報になります。
適当にミラーリングを実行してみちゃう前に必ず控えてくださいね。僕は控え忘れて、元の設定(配置とか解像度とか)が失われてショックを受けました。

Step 2: displayplacerのフルパスを確認

後でAutomatorから実行する際に必要になります。

which displayplacer

僕の環境(Apple Silicon Mac)では /opt/homebrew/bin/displayplacer が返ってきました。
Intel Macの場合は /usr/local/bin/displayplacer になったりするようですね。なので、自分の環境に合わせてメモしておいてください。

Step 3: スクリプトを作成

取得した情報をもとに、2つのスクリプトを作成します。

拡張ディスプレイにする
#!/bin/bash
# extend_display.sh
/opt/homebrew/bin/displayplacer \\
  "id:[モニター1のID] res:2560x1440 hz:60 color_depth:8 enabled:true scaling:on origin:(0,0) degree:0" \\
  "id:[モニター2のID] res:1920x1080 hz:60 color_depth:8 enabled:true scaling:off origin:(-1920,154) degree:0"

ポイントはここですね。

  • コマンド名はdisplayplacerではなくフルパスで指定した方が安定します(Automatorでcommand not foundって怒られるのを防げます)。
  • Step 1でコピーしたコマンドの内容をそのまま使います。

スクリプト自体は、管理しやすい適当な場所に保存しておいてください。

ミラーリング用(ゲームモード)
#!/bin/bash
# mirror_display.sh
/opt/homebrew/bin/displayplacer "id:[モニター1のID]+[モニター2のID] res:1920x1080 hz:60 color_depth:8 enabled:true scaling:on origin:(0,0) degree:0"

こっちのポイントは

  • IDを +(プラス記号)でつなぐこと。これでミラーリング指定になります。
  • 解像度は低い方に合わせるのが無難です。僕の場合、メインはWQHDですが、サブがFHDなので1920x1080に統一しました。
実行権限付与

忘れずに権限を付与しておきましょう。

chmod +x extend_display.sh
chmod +x mirror_display.sh

できたら、一度ターミナルから直接実行して動作確認をしてみるといいですよ。
この時点で画面がパチパチ切り替われば勝利は近いです。

Step 4: Automatorでアプリ化

ここがちょっとした罠なんですが、Stream Deckから直接シェルスクリプトを実行しようとすると、なぜか上手く動かないんですよね(環境によるかもですが)。
アプリケーションの実行ならスムーズにできるので、Automatorを使って.appにしちゃうのが確実です。

実行用アプリの作成
  1. Automator.appを開く
  2. 「新規書類」→「アプリケーション」を選択
  3. 左側のアクション一覧から「シェルスクリプトを実行」を検索してダブルクリック
  4. 右側のスクリプト欄に以下を入力(パスは自分の環境に合わせてください)
/path/to/extend_display.sh
  1. 「ファイル」→「保存」でExtendDisplay.appとかで保存
    • 保存場所は好きな場所でOKです。

同じ手順で、もうミラーリング用のアプリも作成しましょう。こちらはMirrorDisplay.appとかで。
作成したアプリをFinderでダブルクリックして、ディスプレイが切り替わればOKです。

Step 5: Stream Deckに設定

ここまで来れば、あとは設定だけ。

  1. Stream Deckアプリを開く
  2. 新しいボタンを追加 → **「System: Open」**を選択
  3. 拡張ディスプレイ用ボタン(作業モード)
    • App/File: 作成したExtendDisplay.appのフルパスを指定
  4. ミラーリング用ボタン(ゲームモード)
    • App/File: 作成したMirrorDisplay.appのフルパスを指定

これで完成です!
Stream Deckのボタンを押して、ディスプレイが切り替わる快感を味わってください。

実際の使い方

こんな感じで運用しています。

ゲーム開始時
  1. Stream Deckの「ゲームモード」ボタンを押す
    • → ディスプレイがミラーリングに切り替わる
    • → すべてのウィンドウがメインディスプレイに集約される(安心感!)
  2. メインディスプレイの入力をHDMI2に切り替え
    • → メインディスプレイにゲーム画面が映る
  3. ゲーム開始!
    • Discord、ブラウザ等はサブディスプレイ(ミラーリング)で操作可能
ゲーム終了時
  1. メインディスプレイの入力をHDMI1に戻す
  2. Stream Deckの「拡張モード」ボタンを押す
    • → 拡張ディスプレイに切り替わる
    • → 快適なデュアルディスプレイ環境に復帰

たったこれだけ。スムーズに作業↔ゲームを切り替えられます。

使ってみた感想

ボタンを押すと一瞬でディスプレイ設定が切り替わる。慣れると以下のフローが体に染み付きます。

  1. Stream Deckポチッ
  2. モニターの入力切替
  3. ゲーム開始
  4. (ゲーム終了後)モニターの入力切替
  5. Stream Deckポチッ

特に「急にDiscordで呼ばれた時」とか、さっと切り替えて即参戦できるのが最高ですね。
あと、配信準備でOBS等の配信ソフトが見えない画面に行かなくなるのも地味に助かってます。

余談:会議用途にも使える

今回はゲーマー向けに書きましたが、これ、リモートワーカーの会議用途にもそのまま使えるんですよね。

  • 普段は拡張ディスプレイで作業領域を広げる
  • 会議が始まる直前にミラーリングに切り替え
  • 画面共有で「ここを見てください」と言いながら別の画面が映っている...という事故を防げる

会議開始1分前に「あっ」と気づいても、ボタン一発で終わり。会議が終わったらまたボタン一発で拡張に戻す。
スマートじゃないですか?

まとめ

最初の設定は正直ちょっと面倒ですが(特にID調べるところとか)、一度作ってしまえばこっちのものです。
未来の自分が楽をするために、週末にでも試してみてはいかがでしょうか。

ぜひ試してみてください。