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

François Beaufort
François Beaufort

Browser Support

  • Chrome: 109.
  • Edge: 109.
  • Firefox: not supported.
  • Safari: not supported.

Source

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

ブラウザ サポート

Conditional Focus は 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 });

Promise が解決される前に setFocusBehavior() を任意の回数呼び出すことができます。また、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() が返したストリームの動画トラックが "ライブ" でない場合。
  • getDisplayMedia() が返した Promise が解決された後、ユーザーがタブまたはウィンドウではなく画面を共有した場合。

サンプル

デモを実行して、Conditional Focus を試すことができます。

機能検出

CaptureController.setFocusBehavior() がサポートされているかどうかを確認するには、次のようにします。

if (
  "CaptureController" in window &&
  "setFocusBehavior" in CaptureController.prototype
) {
  // CaptureController.setFocusBehavior() is supported.
}

フィードバック

Chrome チームとウェブ標準コミュニティは、Conditional Focus の使用感についてご意見をお待ちしています。

デザインについて教えてください

Conditional Focus が想定どおりに動作しない場合はありますか?アイデアを実装するために必要なメソッドやプロパティが不足していますか?セキュリティ モデルについてご質問やご意見はありますか?

  • GitHub リポジトリで仕様に関する問題を提出するか、既存の問題にご意見を追加してください。

実装に問題がありますか?

Chrome の実装にバグが見つかりましたか?実装が仕様と異なる場合はありますか?

  • https://new.crbug.com でバグを報告してください。できるだけ詳細な情報と、再現手順を含めてください。

サポートを表示

Conditional Focus を使用する予定はありますか?公開サポートは、Chrome チームが機能の優先順位を決定するのに役立ち、他のブラウザ ベンダーにサポートの重要性を示すことができます。

@ChromiumDev にツイートして、どこでどのように使用しているかをお知らせください。

謝辞

このドキュメントのレビューにご協力いただいた Rachel Andrew に感謝いたします。