Screen Capture API を使用すると、ユーザーはタブ、ウィンドウ、画面を選択して、メディア ストリームとしてキャプチャできます。その後、このストリームを録画したり、ネットワーク経由で他のユーザーと共有したりできます。このドキュメントでは条件付きフォーカスについて説明します。条件付きフォーカスは、キャプチャの開始時にキャプチャしたタブまたはウィンドウをフォーカスするかどうか、キャプチャ ページをフォーカスしたままにするかどうかをウェブアプリで制御するためのメカニズムです。
ブラウザ サポート
条件付きフォーカスは Chrome 109 から利用可能になりました。
背景
ウェブアプリがタブやウィンドウのキャプチャを開始すると、ブラウザは決定を下します。キャプチャしたサーフェスを最前面に配置するか、キャプチャ ページのフォーカスを維持すべきか、などです。その答えは、getDisplayMedia()
を呼び出した理由と、ユーザーが最終的に選択するサーフェスによって異なります。
架空のビデオ会議ウェブアプリについて考えてみましょう。ビデオ会議ウェブアプリは、track.getSettings().displaySurface
を読み取り、場合によってはハンドルのキャプチャを調べることで、ユーザーが共有することを選択したものを把握できます。以下の手順を行います。
- キャプチャしたタブまたはウィンドウをリモートで操作できる場合は、ビデオ会議にフォーカスを合わせたままにします。
- それ以外の場合は、キャプチャされたタブまたはウィンドウをフォーカスします。
上記の例では、ビデオ会議ウェブアプリはスライド資料を共有している場合にフォーカスを保持し、ユーザーがリモートでスライドを次々と切り替えることができます。ただし、ユーザーがテキスト エディタの共有を選択した場合、ビデオ会議ウェブアプリのフォーカスはキャプチャされたタブまたはウィンドウに直ちに切り替わります。
Conditional Focus API を使用する
CaptureController
をインスタンス化して getDisplayMedia()
に渡します。返された getDiplayMedia()
が解決した直後に setFocusBehavior()
を呼び出すことで、キャプチャされたタブまたはウィンドウにフォーカスするかどうかを制御できます。この操作は、ユーザーがタブまたはウィンドウを共有した場合にのみ行えます。
const controller = new CaptureController();
// Prompt the user to share a tab, a window or a screen.
const stream =
await navigator.mediaDevices.getDisplayMedia({ controller });
const [track] = stream.getVideoTracks();
const displaySurface = track.getSettings().displaySurface;
if (displaySurface == "browser") {
// Focus the captured tab.
controller.setFocusBehavior("focus-captured-surface");
} else if (displaySurface == "window") {
// Do not move focus to the captured window.
// Keep the capturing page focused.
controller.setFocusBehavior("focus-capturing-application");
}
フォーカスするかどうかを決定する際に、キャプチャ ハンドルを考慮できます。
// Retain focus if capturing a tab dialed to example.com.
// Focus anything else.
const origin = track.getCaptureHandle().origin;
if (displaySurface == "browser" && origin == "https://example.com") {
controller.setFocusBehavior("focus-capturing-application");
} else if (displaySurface != "monitor") {
controller.setFocusBehavior("focus-captured-surface");
}
getDisplayMedia()
を呼び出す前に、フォーカスするかどうかを決定することもできます。
// Focus the captured tab or window when capture starts.
const controller = new CaptureController();
controller.setFocusBehavior("focus-captured-surface");
// Prompt the user to share their screen.
const stream =
await navigator.mediaDevices.getDisplayMedia({ controller });
setFocusBehavior()
は、Promise が解決される前に何度でも呼び出すことができます。または、Promise が解決された直後に 1 回だけ呼び出すことができます。最後の呼び出しは、以前のすべての呼び出しをオーバーライドします。
より正確に言うと、- 返された getDisplayMedia()
Promise はマイクロタスクで解決されます。そのマイクロタスクの完了後に setFocusBehavior()
を呼び出すと、エラーがスローされます。- キャプチャの開始後 1 秒を超えて setFocusBehavior()
を呼び出すと何も実行されない。
つまり、次のスニペットは両方とも失敗します。
// Prompt the user to share their screen.
const stream =
await navigator.mediaDevices.getDisplayMedia({ controller });
// Too late, because it follows the completion of the task
// on which the getDisplayMedia() promise resolved.
// This will throw.
setTimeout(() => {
controller.setFocusBehavior("focus-captured-surface");
});
// Prompt the user to share their screen.
const stream =
await navigator.mediaDevices.getDisplayMedia({ controller });
const start = new Date();
while (new Date() - start <= 1000) {
// Idle for ≈1s.
}
// Because too much time has elapsed, the browser will have
// already decided whether to focus.
// This fails silently.
controller.setFocusBehavior("focus-captured-surface");
setFocusBehavior()
を呼び出すと、次の場合もスローされます。
getDisplayMedia()
から返されたストリームの動画トラックが "live" ではない。getDisplayMedia()
が返された Promise が解決された後、ユーザーが(タブやウィンドウではなく)画面を共有した場合。
サンプル
Glitch でデモを実行すると、条件付きフォーカスをお試しいただけます。必ずソースコードを確認してください。
特徴検出
CaptureController.setFocusBehavior()
がサポートされているかどうかを確認するには、次のコマンドを使用します。
if (
"CaptureController" in window &&
"setFocusBehavior" in CaptureController.prototype
) {
// CaptureController.setFocusBehavior() is supported.
}
フィードバック
Chrome チームとウェブ標準コミュニティでは、条件付きフォーカスのフィードバックをお待ちしています。
デザインについてお聞かせください
条件付きフォーカスについて、想定どおりに機能しない点はありますか。あるいは、アイデアを実装するために必要なメソッドやプロパティが不足しているか?セキュリティ モデルについてご質問やご意見がある場合
- GitHub リポジトリで仕様の問題を提出するか、既存の問題に意見を追加します。
実装に問題がある場合
Chrome の実装にバグが見つかりましたか?あるいは、実装が仕様と異なるのでしょうか?
- https://new.crbug.com でバグを報告します。できるだけ詳しい情報と、再現するための簡単な手順を記載してください。Glitch はコードの共有に適しています。
サポートを示す
条件付きフォーカスを使用する予定はありますか?公開サポートによって、Chrome チームは機能の優先順位付けを行うことができ、サポートがいかに重要であるかを他のブラウザ ベンダーに示すことができます。
@ChromiumDev 宛てのツイートで、この機能をどこでどのように使っているかを教えてください。
関連情報
謝辞
ヒーロー画像: Elena Taranenko
この記事をレビューしてくれた Rachel Andrew に感謝します。