通过条件聚焦功能更好地共享屏幕

François Beaufort
François Beaufort

Browser Support

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

Source

借助屏幕捕获 API,用户可以选择要捕获的标签页、窗口或屏幕,并将其作为媒体流进行捕获。然后,您可以录制此视频流,也可以通过网络与他人分享。本文档介绍了条件聚焦,这是一种机制,可供 Web 应用控制在开始捕获时,是聚焦于捕获的标签页或窗口,还是聚焦于捕获页面。

浏览器支持

条件聚焦功能自 Chrome 109 起提供。

背景

当 Web 应用开始捕获标签页或窗口时,浏览器会面临一个选择:是将捕获的表面置于前台,还是让捕获页面保持焦点?答案取决于来电原因 getDisplayMedia() 以及用户最终选择的 Surface。

假设有一个视频会议 Web 应用。通过读取 track.getSettings().displaySurface 并可能检查 Capture Handle,视频会议 Web 应用可以了解用户选择共享的内容。然后,执行以下操作:

  • 如果捕获的标签页或窗口可以远程控制,请将视频会议保持在焦点位置。
  • 否则,聚焦于捕获的标签页或窗口。

在上述示例中,如果用户共享的是幻灯片演示,视频会议 Web 应用会保持焦点,以便用户远程翻阅幻灯片;但如果用户选择共享文本编辑器,视频会议 Web 应用会立即将焦点切换到所捕获的标签页或窗口。

使用条件焦点 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 解析之后立即调用一次。最后一次调用会替换之前的所有调用。

更准确地说:- 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 解析后,如果用户分享的是屏幕(而非标签页或窗口)。

示例

您可以运行演示来体验条件焦点。

功能检测

如需检查是否支持 CaptureController.setFocusBehavior(),请使用:

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

反馈

Chrome 团队和 Web 标准社区希望了解您在使用条件性焦点方面的体验。

介绍一下设计

条件聚焦功能是否未按预期运行?或者,是否有缺少的方法或属性需要您来实现自己的想法?对安全模型有疑问或意见?

  • GitHub 代码库中提交规范问题,或在现有问题中添加您的想法。

实现存在问题?

您是否发现 Chrome 的实现存在 bug?还是实现与规范不同?

显示支持

您是否计划使用条件焦点?您的公开支持有助于 Chrome 团队确定功能的优先级,并向其他浏览器供应商展示支持这些功能的重要性。

请向 @ChromiumDev 发送推文,告诉我们您在何处以及如何使用该功能。

致谢

主打图片,摄影师:Elena Taranenko

感谢 Rachel Andrew 审阅本文。