キャプチャしたタブをスクロールしてズームする

François Beaufort
François Beaufort

タブ、ウィンドウ、画面の共有は、ウェブ プラットフォームで Screen Capture API を使用してすでに可能です。ウェブアプリが getDisplayMedia() を呼び出すと、Chrome はタブ、ウィンドウ、または画面を MediaStreamTrack 動画としてウェブアプリと共有するようユーザーに求めるメッセージを表示します。

getDisplayMedia() を使用する多くのウェブアプリでは、キャプチャされたサーフェスの動画プレビューがユーザーに表示されます。たとえば、ビデオ会議アプリでは、この動画をリモート ユーザーにストリーミングするとともに、ローカルの HTMLVideoElement にレンダリングして、ローカル ユーザーが共有している内容のプレビューを常に表示します。

このドキュメントでは、Chrome の新しい Captured Surface Control API について説明します。この API を使用すると、ウェブアプリでキャプチャされたタブをスクロールしたり、キャプチャされたタブのズームレベルを読み書きしたりできます。

ユーザーがキャプチャしたタブをスクロールしてズームする(デモ)。

キャプチャされたサーフェス コントロールを使用する理由

どのビデオ会議アプリにも同じ欠点があります。キャプチャされたタブまたはウィンドウを操作するには、そのサーフェスに切り替えて、ビデオ会議アプリから離れる必要があります。これにはいくつかの課題があります。

  • ユーザーは、ピクチャー イン ピクチャーを使用するか、ビデオ会議タブと共有タブに別々の並列ウィンドウを使用する場合を除き、キャプチャされたアプリとリモート ユーザーのビデオフィードを同時に表示することはできません。小さな画面では、この操作が難しい場合があります。
  • ビデオ会議アプリとキャプチャされたサーフェスを切り替える必要があるため、ユーザーの負担が増大します。
  • ユーザーがビデオ会議アプリから離れている間、ビデオ会議アプリによって公開されているコントロール(埋め込みチャット アプリ、絵文字のリアクション、通話への参加をリクエストするユーザーに関する通知、マルチメディアとレイアウトのコントロール、その他の便利なビデオ会議機能など)にアクセスできなくなります。
  • プレゼンターは、リモート参加者に操作を委任できません。そのため、リモート ユーザーがプレゼンターにスライドの変更、上下のスクロール、ズームレベルの調整を依頼する、というよくあるシナリオが発生します。

Captured Surface Control API は、これらの問題に対処します。

キャプチャされたサーフェス コントロールを使用するにはどうすればよいですか?

キャプチャされたサーフェス コントロールを正常に使用するには、ブラウザタブを明示的にキャプチャし、キャプチャしたタブをスクロールおよびズームする前にユーザーから権限を取得するなど、いくつかの手順が必要です。

ブラウザタブをキャプチャする

まず、getDisplayMedia() を使用して共有するサーフェスを選択するようユーザーにプロンプトを表示します。このプロセスで、キャプチャ セッションに CaptureController オブジェクトを関連付けます。まもなく、このオブジェクトを使用してキャプチャされたサーフェスを制御する予定です。

const controller = new CaptureController();
const stream = await navigator.mediaDevices.getDisplayMedia({ controller });

次に、キャプチャされたサーフェスのローカル プレビューを <video> 要素の形式で生成します。

const previewTile = document.querySelector('video');
previewTile.srcObject = stream;

お客様がウィンドウまたは画面の共有を選択した場合は、現時点ではサポート範囲外ですが、タブの共有を選択した場合は、サポートを進めることができます。

const [track] = stream.getVideoTracks();

if (track.getSettings().displaySurface !== 'browser') {
  // Bail out early if the user didn't pick a tab.
  return;
}

権限プロンプト

特定の CaptureController オブジェクトで forwardWheel()increaseZoomLevel()decreaseZoomLevel()、または resetZoomLevel() を初めて呼び出すと、権限プロンプトが表示されます。ユーザーが権限を付与すると、これらのメソッドの呼び出しが許可されます。

ユーザーに権限プロンプトを表示するにはユーザー ジェスチャーが必要です。そのため、アプリは、権限をすでに持っている場合、またはウェブアプリの関連するボタンの click などのユーザー ジェスチャーに応答する場合にのみ、前述のメソッドを呼び出す必要があります。

スクロール

キャプチャ アプリは forwardWheel() を使用して、キャプチャ アプリ自体内のソース要素からキャプチャされたタブのビューポートにホイールイベントを転送できます。これらのイベントは、キャプチャされたアプリにとって、ユーザーの直接的な操作と区別できません。

キャプチャ アプリが "previewTile" という <video> 要素を使用していると仮定すると、次のコードは、キャプチャされたタブにホイール イベントをリレー送信する方法を示しています。

const previewTile = document.querySelector('video');
try {
  // Relay the user's action to the captured tab.
  await controller.forwardWheel(previewTile);
} catch (error) {
  // Inspect the error.
  // ...
}

メソッド forwardWheel() は、次のいずれかの単一の入力を受け取ります。

  • ホイール イベントがキャプチャされたタブに転送される HTML 要素。
  • null: 転送を停止する必要があることを示します。

forwardWheel() の呼び出しが成功すると、以前の呼び出しがオーバーライドされます。

forwardWheel() によって返される Promise は、次の場合に拒否されることがあります。

  • キャプチャ セッションがまだ開始されていないか、すでに停止している場合。
  • ユーザーが関連する権限を付与していない場合。

ズーム

キャプチャされたタブのズームレベルを操作するには、次の CaptureController API サーフェスを使用します。

getSupportedZoomLevels()

このメソッドは、キャプチャされるサーフェス タイプでブラウザがサポートするズームレベルのリストを返します。このリストの値は、「デフォルトのズームレベル」(100% と定義)に対する割合として表されます。リストは単調に増加し、値 100 が含まれています。

このメソッドは、サポートされているディスプレイ サーフェス タイプでのみ呼び出すことができます。現時点では、タブでのみ呼び出せます。

controller.getSupportedZoomLevels() は、次の条件が満たされている場合に呼び出されます。

  • controller はアクティブなキャプチャに関連付けられています。
  • キャプチャはタブです。

そうでない場合は、エラーが発生します。

このメソッドの呼び出しに "captured-surface-control" 権限は不要です。

zoomLevel

この読み取り専用属性には、キャプチャされたタブの現在のズームレベルが保持されます。null を指定できる属性で、キャプチャされたサーフェス タイプに有意なズームレベルの定義がない場合は null を保持します。現時点では、ズームレベルはタブに対してのみ定義され、ウィンドウや画面に対しては定義されません。

キャプチャが終了すると、この属性には最後のズームレベルの値が保持されます。

この属性の読み取りには "captured-surface-control" 権限は不要です。

onzoomlevelchange

このイベント ハンドラを使用すると、キャプチャされたタブのズームレベルの変更を簡単にリッスンできます。これらのエラーは、次のいずれかの場合に発生します。

  • ユーザーがブラウザを操作して、キャプチャしたタブのズームレベルを手動で変更した場合。
  • キャプチャ アプリがズーム設定メソッド(後述)を呼び出したとき。

この属性の読み取りには "captured-surface-control" 権限は不要です。

increaseZoomLevel()decreaseZoomLevel()resetZoomLevel()

これらのメソッドを使用すると、キャプチャしたタブのズームレベルを操作できます。

increaseZoomLevel()decreaseZoomLevel() は、getSupportedZoomLevels() によって返された順序に従って、ズームレベルをそれぞれ次のズームレベルまたは前のズームレベルに変更します。resetZoomLevel() は値を 100 に設定します。

これらのメソッドを呼び出すには、"captured-surface-control" 権限が必要です。キャプチャ アプリにこの権限がない場合は、権限を付与または拒否するようユーザーに求めるメッセージが表示されます。

これらのメソッドはすべて、呼び出しが成功した場合は解決され、それ以外の場合は拒否される Promise を返します。拒否の理由として、次のようなものが考えられます。

  • 権限がありません。
  • キャプチャの開始前に呼び出されます。
  • キャプチャの終了後に呼び出されます。
  • サポートされていないディスプレイ サーフェス タイプのキャプチャに関連付けられた controller で呼び出されます。(タブ キャプチャ以外)。
  • 最大値または最小値を超える増減を試行します。

特に、controller.zoomLevel == controller.getSupportedZoomLevels().at(0) の場合は decreaseZoomLevel() を呼び出さず、.at(-1) と同様に increaseZoomLevel() への呼び出しをガードすることをおすすめします。

次の例は、キャプチャ アプリから直接、キャプチャしたタブのズームレベルをユーザーが拡大できるようにする方法を示しています。

const zoomIncreaseButton = document.getElementById('zoomInButton');
zoomIncreaseButton.addEventListener('click', async (event) => {
  if (controller.zoomLevel >= controller.getSupportedZoomLevels().at(-1)) {
    return;
  }
  try {
    await controller.increaseZoomLevel();
  } catch (error) {
    // Inspect the error.
    // ...
  }
});

次の例は、キャプチャしたタブのズームレベルの変化に応答する方法を示しています。

controller.addEventListener('zoomlevelchange', (event) => {
  const zoomLevelLabel = document.querySelector('#zoomLevelLabel');
  zoomLevelLabel.textContent = `${controller.zoomLevel}%`;
});

特徴検出

Captured Surface Control API がサポートされているかどうかを確認するには、次のコマンドを使用します。

if (!!window.CaptureController?.prototype.forwardWheel) {
  // CaptureController forwardWheel() is supported.
}

increaseZoomLeveldecreaseZoomLevel など、他の Captured Surface Control API サーフェスを使用することも、それらをすべて確認することもできます。

ブラウザ サポート

キャプチャされたサーフェス コントロールは、パソコン版 Chrome 136 以降でのみご利用いただけます。

セキュリティとプライバシー

"captured-surface-control" 権限ポリシーを使用すると、キャプチャ アプリと埋め込まれたサードパーティの iframe がキャプチャされたサーフェス コントロールにアクセスする方法が管理できます。セキュリティのトレードオフについて詳しくは、キャプチャされたサーフェス コントロールの説明のプライバシーとセキュリティに関する考慮事項をご覧ください。

デモ

Captured Surface Control を試すには、Glitch でデモを実行します。ソースコードを確認してください。

フィードバック

Chrome チームとウェブ標準コミュニティは、Captured Surface Control に関するご意見をお待ちしています。

デザインについて

キャプチャされたサーフェス キャプチャが想定どおりに動作しない点はありますか?または、アイデアを実装するために必要なメソッドやプロパティが不足している場合は、セキュリティ モデルについてご質問やご意見がございましたら、GitHub リポジトリで仕様に関する問題を報告するか、既存の問題にコメントを追加してください。

実装に関する問題

Chrome の実装にバグが見つかりましたか?それとも、実装が仕様と異なるのでしょうか?https://new.crbug.com でバグを報告します。できるだけ詳細な情報と、再現手順を記載してください。Glitch は、再現可能なバグを共有するのに適しています。