Melhor compartilhamento de tela com o Foco condicional

Francisco Beaufort
François Beaufort
Elad alon
Alon Elad

Compatibilidade com navegadores

  • 109
  • 109
  • x
  • x

Origem

A API Screen Capture permite que o usuário selecione uma guia, janela ou tela para capturar como um stream de mídia. Essa transmissão pode ser gravada ou compartilhada com outras pessoas pela rede. Esta documentação apresenta o Conditional Focus, um mecanismo para aplicativos da Web controlarem se a guia ou janela capturada será focada quando a captura for iniciada ou se a página de captura permanecerá focada.

Suporte ao navegador

O Foco condicional está disponível no Chrome 109.

Contexto

Quando um aplicativo da Web começa a capturar uma guia ou janela, o navegador precisa decidir: a superfície capturada deve ficar em destaque ou a página de captura deve permanecer focada? A resposta depende do motivo da chamada de getDisplayMedia() e da plataforma que o usuário seleciona.

Considere um app da Web de videoconferência hipotético. Ao ler track.getSettings().displaySurface e talvez examinar a alça de captura, o app da Web de videoconferência vai entender o que o usuário escolheu compartilhar. Depois:

  • Se for possível controlar remotamente a guia ou janela capturada, mantenha a videoconferência em foco.
  • Caso contrário, direcione o foco para a guia ou janela capturada.

No exemplo acima, o app da Web de videoconferência vai manter o foco se compartilhar uma apresentação de slides, permitindo que o usuário navegue remotamente pelos slides. Mas, se o usuário optar por compartilhar um editor de texto, o app da Web de videoconferência vai mudar o foco imediatamente para a guia ou janela capturada.

Como usar a API Conditional Focus

Instancie um CaptureController e o transmita para getDisplayMedia(). Ao chamar setFocusBehavior() imediatamente após a promessa retornada da getDiplayMedia() ser resolvida, você pode controlar se a guia ou a janela capturada será focada ou não. Isso só poderá ser feito se o usuário tiver compartilhado uma guia ou janela.

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");
}

Ao decidir se você vai usar o foco, considere o identificador de captura.

// 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");
}

É possível até decidir se quer focar antes de chamar 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 });

É possível chamar setFocusBehavior() arbitrariamente várias vezes antes que a promessa seja resolvida ou, no máximo, uma vez imediatamente após ela ser resolvida. A última invocação substitui todas as anteriores.

Mais precisamente: - a promessa retornada de getDisplayMedia() é resolvida em uma microtarefa. Chamar setFocusBehavior() depois que a microtarefa for concluída gera um erro. - Chamar setFocusBehavior() mais de um segundo após o início da captura é um ambiente autônomo.

Ou seja, os dois snippets a seguir vão falhar:

// 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");

Chamar setFocusBehavior() também gera estes casos:

  • a faixa de vídeo do stream retornado por getDisplayMedia() não está "ao vivo".
  • depois que a promessa retornada da getDisplayMedia() for resolvida, se o usuário tiver compartilhado uma tela (não uma guia ou janela).

Exemplo

Você pode brincar com o Foco condicional executando a demonstração no Glitch. Confira o código-fonte.

Detecção de recursos

Para conferir se CaptureController.setFocusBehavior() é compatível, use:

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

Feedback

A equipe do Chrome e a comunidade de padrões da Web querem saber mais sobre suas experiências com o Conditional Focus.

Fale sobre o design

Há algo sobre o Foco condicional que não funciona como esperado? Ou faltam métodos ou propriedades que você precisa implementar para implementar sua ideia? Tem alguma dúvida ou comentário sobre o modelo de segurança?

  • Registre um problema específico no repositório do GitHub (link em inglês) ou adicione suas ideias a um problema existente.

Problemas com a implementação?

Você encontrou um bug na implementação do Chrome? Ou a implementação é diferente da especificação?

  • Informe um bug em https://new.crbug.com. Lembre-se de incluir o máximo de detalhes possível e instruções simples de reprodução. O Glitch funciona bem para compartilhar código.

Mostrar apoio

Você planeja usar o Foco condicional? O suporte público ajuda a equipe do Chrome a priorizar recursos e mostra a outros fornecedores de navegadores como é importante oferecer suporte a eles.

Envie um tweet para @ChromiumDev e informe onde e como você está usando a plataforma.

Agradecimentos

Imagem principal de Elena Taranenko.

Agradecemos a Rachel Andrew pela leitura deste artigo.