条件付きフォーカスによる画面共有の改善

François Beaufort
François Beaufort

対応ブラウザ

  • Chrome: 109.
  • Edge: 109。
  • Firefox: サポートされていません。
  • Safari: サポートされていません。

ソース

Screen Capture API を使用すると、ユーザーはタブ、ウィンドウ、画面を選択してメディア ストリームとしてキャプチャできます。このストリームは録画したり、ネットワークを介して他のユーザーと共有したりできます。このドキュメントでは、条件付きフォーカスについて説明します。条件付きフォーカスは、キャプチャの開始時にキャプチャしたタブやウィンドウにフォーカスするか、キャプチャ ページにフォーカスしたままにするかをウェブアプリが制御するためのメカニズムです。

ブラウザ サポート

条件付きフォーカスは Chrome 109 から利用できます。

背景

ウェブアプリがタブまたはウィンドウのキャプチャを開始すると、ブラウザはキャプチャされたサーフェスをフォアグラウンドに移動するか、キャプチャ ページにフォーカスを維持するかを決定する必要があります。答えは、getDisplayMedia() を呼び出す理由と、ユーザーが最終的に選択するサーフェスによって異なります。

架空のビデオ会議ウェブアプリについて考えてみましょう。ビデオ会議ウェブアプリは、track.getSettings().displaySurface を読み取り、必要に応じてキャプチャ ハンドルを調べることで、ユーザーが共有することを選択した内容を把握できます。以下の手順を行います。

  • キャプチャしたタブやウィンドウをリモート制御できる場合は、ビデオ会議にフォーカスを合わせたままにします。
  • それ以外の場合は、キャプチャしたタブまたはウィンドウにフォーカスします。

上記の例では、スライド デッキを共有する場合、ビデオ会議ウェブアプリはフォーカスを保持し、ユーザーはリモートでスライドをめくることができます。ただし、ユーザーがテキスト エディタを共有する場合、ビデオ会議ウェブアプリはキャプチャされたタブまたはウィンドウにフォーカスをすぐに切り替えます。

Conditional Focus API の使用

CaptureController をインスタンス化して getDisplayMedia() に渡します。返された getDiplayMedia() の Promise が解決された直後に 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() を呼び出しても、何も処理されません。

つまり、次の 2 つのスニペットはどちらも失敗します。

// 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() によって返されたストリームの動画トラックが「ライブ」ではない。
  • 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 に感謝します。