Улучшенное совместное использование экрана с помощью условного фокуса

Франсуа Бофор
François Beaufort

Поддержка браузера

  • 109
  • 109
  • Икс
  • Икс

Источник

API захвата экрана позволяет пользователю выбрать вкладку, окно или экран для захвата в виде медиапотока. Этот поток затем можно записать или поделиться с другими по сети. В этой документации представлен условный фокус — механизм, позволяющий веб-приложениям контролировать, будет ли захваченная вкладка или окно фокусироваться при запуске захвата или же страница захвата останется в фокусе.

Поддержка браузера

Условный фокус доступен в Chrome 109.

Фон

Когда веб-приложение начинает захватывать вкладку или окно, браузер сталкивается с решением: следует ли вывести захваченную поверхность на передний план или же страница захвата должна оставаться в фокусе? Ответ зависит от причины вызова getDisplayMedia() и, на первый взгляд, пользователь в конечном итоге выбирает.

Рассмотрим гипотетическое веб-приложение для видеоконференций. Прочитав track.getSettings().displaySurface и, возможно, проверив Capture Handle , веб-приложение для видеоконференций может понять, чем пользователь решил поделиться. Затем:

  • Если захваченной вкладкой или окном можно управлять удаленно, держите видеоконференцию в фокусе.
  • В противном случае переместите фокус на захваченную вкладку или окно.

В приведенном выше примере веб-приложение для видеоконференций сохранит фокус при совместном использовании набора слайдов, позволяя пользователю удаленно пролистывать слайды; но если пользователь решит поделиться текстовым редактором, веб-приложение для видеоконференций немедленно переключит фокус на захваченную вкладку или окно.

Использование API условного фокуса

Создайте экземпляр CaptureController и передайте его getDisplayMedia() . Вызвав setFocusBehavior() сразу после разрешения возвращенного обещания getDiplayMedia() , вы можете контролировать, будет ли захваченная вкладка или окно фокусироваться или нет. Это можно сделать только в том случае, если пользователь поделился вкладкой или окном.

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() сколько угодно раз до того, как обещание будет разрешено, или не более одного раза сразу после разрешения обещания. Последний вызов отменяет все предыдущие вызовы.

Точнее: — Возвращаемое обещание getDisplayMedia() разрешается на микрозадаче. Вызов setFocusBehavior() после завершения микрозадачи вызывает ошибку. - Вызов 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() , если пользователь поделился экраном (а не вкладкой или окном).

Образец

Вы можете поиграть с Условным фокусом, запустив демо-версию на Glitch. Обязательно ознакомьтесь с исходным кодом .

Обнаружение функций

Чтобы проверить, поддерживается ли CaptureController.setFocusBehavior() , используйте:

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

Обратная связь

Команда Chrome и сообщество веб-стандартов хотят услышать о вашем опыте использования условного фокуса.

Расскажите о дизайне

Есть ли в условном фокусе что-то, что не работает так, как вы ожидали? Или вам не хватает методов или свойств, необходимых для реализации вашей идеи? У вас есть вопрос или комментарий по модели безопасности?

  • Сообщите о проблеме спецификации в репозитории GitHub или добавьте свои мысли к существующей проблеме.

Проблема с реализацией?

Вы нашли ошибку в реализации Chrome? Или реализация отличается от спецификации?

  • Сообщите об ошибке на https://new.crbug.com . Обязательно включите как можно больше деталей и простые инструкции по воспроизведению. Glitch хорошо подходит для обмена кодом.

Показать поддержку

Планируете ли вы использовать условный фокус? Ваша публичная поддержка помогает команде Chrome расставлять приоритеты в функциях и показывает другим поставщикам браузеров, насколько важно их поддерживать.

Отправьте твит @ChromiumDev и сообщите нам, где и как вы его используете.

Благодарности

Образ героя Елены Тараненко .

Спасибо Рэйчел Эндрю за рецензирование этой статьи.