浏览器支持
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
借助 Screen Capture API,用户可以选择要以媒体流形式截取的标签页、窗口或屏幕。然后,您可以录制此直播,也可以通过网络与他人分享。本文档介绍了条件聚焦,这是一种供 Web 应用控制的机制,可控制在捕获开始时是聚焦于捕获的标签页或窗口,还是让捕获页面保持聚焦状态。
浏览器支持
Chrome 109 及更高版本提供条件对焦功能。
背景
当 Web 应用开始捕获标签页或窗口时,浏览器会面对一个决定:是将捕获的 Surface 置于最前端,还是让捕获页面保持聚焦状态?答案取决于调用 getDisplayMedia()
的原因,以及用户最终选择的 surface。
假设有一个假设的视频会议 Web 应用。通过读取 track.getSettings().displaySurface
并检查捕获句柄,视频会议 Web 应用可以了解用户选择分享的内容。然后,执行以下操作:
- 如果可以远程控制截取的标签页或窗口,请将视频会议画面置于焦点。
- 否则,请聚焦于截取的标签页或窗口。
在上面的示例中,如果共享演示文稿,视频会议 Web 应用将保留焦点,允许用户远程翻阅幻灯片;但如果用户选择共享文本编辑器,视频会议 Web 应用会立即将焦点切换到截取的标签页或窗口。
使用 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 解析后立即调用一次。最后一次调用会覆盖之前的所有调用。
更准确地说:
- 返回的 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()
返回的流的视频轨道不是 "live"。- 如果用户共享了屏幕(而非标签页或窗口),则在返回的 promise 解析之后。
getDisplayMedia()
示例
您可以通过运行 Glitch 上的演示来体验条件对焦功能。请务必查看源代码。
功能检测
如需检查 CaptureController.setFocusBehavior()
是否受支持,请使用以下命令:
if (
"CaptureController" in window &&
"setFocusBehavior" in CaptureController.prototype
) {
// CaptureController.setFocusBehavior() is supported.
}
反馈
Chrome 团队和网络标准社区希望了解您使用条件焦点的体验。
向我们介绍设计
条件焦点是否有什么未达到您的预期?或者,您是否缺少实现自己的想法所需的方法或属性?对安全模型有疑问或意见?
- 在 GitHub 代码库中提交规范问题,或者添加您对现有问题的看法。
实施时遇到问题?
您在 Chrome 的实现过程中是否发现了错误?或者,实现是否与规范不同?
- 访问 https://new.crbug.com 提交 bug。请务必提供尽可能多的细节,并提供关于重现的简单说明。Glitch 非常适用于共享代码。
表示支持
您打算使用条件聚焦吗?您的公开支持有助于 Chrome 团队确定各项功能的优先级,并向其他浏览器供应商展示支持这些功能的重要性。
请向 @ChromiumDev 发送 tweet 消息,告诉我们您在何处以及如何使用它。
实用链接
致谢
主打图片:Elena Taranenko。
感谢 Rachel Andrew 审核本文。