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

François Beaufort
François Beaufort

Browser Support

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

Source

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() を任意の回数呼び出すことができ、プロミスが解決した直後には最大で 1 回呼び出すことができます。最後の呼び出しは、以前のすべての呼び出しをオーバーライドします。

具体的には、次のようになります。 - getDisplayMedia() が返した Promise はマイクロタスクで解決されます。そのマイクロタスクの完了後に setFocusBehavior() を呼び出すと、エラーがスローされます。- キャプチャ開始から 1 秒以上経過してから setFocusBehavior() を呼び出しても、何の処理も行われません(no-op)。

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

// 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 が解決された後、ユーザーが画面(タブやウィンドウではない)を共有した場合。

サンプル

デモを実行して、条件付きフォーカスを試すことができます。

特徴検出

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

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

フィードバック

Chrome チームとウェブ標準コミュニティは、条件付きフォーカスに関する皆様のご意見をお待ちしています。

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

条件付きフォーカスについて、期待どおりに動作しない点がありましたらご記入ください。アイデアを実装するために必要なメソッドやプロパティが不足している場合はどうすればよいですか?セキュリティ モデルについて質問やコメントがある場合

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

実装に関する問題ですか?

Chrome の実装にバグが見つかりましたか?それとも、実装が仕様と異なるのでしょうか?

サポートを表示

条件付きフォーカスを使用する予定はありますか?皆様からの公開サポートは、Chrome チームが機能の優先順位を決定するうえで役立ち、他のブラウザ ベンダーにサポートの重要性を示すことにもつながります。

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

謝辞

ヒーロー画像: Elena Taranenko

この記事をレビューしてくれた Rachel Andrew に感謝します。