Amélioration du partage d'écran avec la mise au point conditionnelle

François Beaufort
François Beaufort

Browser Support

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

Source

L'API Screen Capture permet à l'utilisateur de sélectionner un onglet, une fenêtre ou un écran à capturer en tant que flux multimédia. Ce flux peut ensuite être enregistré ou partagé avec d'autres personnes sur le réseau. Cette documentation présente Conditional Focus, un mécanisme permettant aux applications Web de contrôler si l'onglet ou la fenêtre capturé sera mis en avant au début de la capture, ou si la page de capture restera mise en avant.

Prise en charge des navigateurs

Conditional Focus est disponible à partir de Chrome 109.

Arrière-plan

Lorsqu'une application Web commence à capturer un onglet ou une fenêtre, le navigateur doit prendre une décision : la surface capturée doit-elle être mise au premier plan ou la page de capture doit-elle rester mise en avant ? La réponse dépend de la raison pour laquelle getDisplayMedia() est appelé et de la surface que l'utilisateur finit par sélectionner.

Prenons l'exemple d'une application Web de visioconférence hypothétique. En lisant track.getSettings().displaySurface et en examinant potentiellement le descripteur de capture, l'application Web de visioconférence peut comprendre ce que l'utilisateur a choisi de partager. Ensuite :

  • Si l'onglet ou la fenêtre capturé peut être contrôlé à distance, la visioconférence reste mise en avant.
  • Sinon, l'onglet ou la fenêtre capturé est mis en avant.

Dans l'exemple ci-dessus, l'application Web de visioconférence reste mise en avant si l'utilisateur partage une présentation de diapositives, ce qui lui permet de les faire défiler à distance. Toutefois, si l'utilisateur choisit de partager un éditeur de texte, l'application Web de visioconférence passe immédiatement à l'onglet ou à la fenêtre capturé.

Utiliser l'API Conditional Focus

Instanciez un CaptureController et transmettez-le à getDisplayMedia(). En appelant setFocusBehavior() immédiatement après la résolution de la promesse renvoyée par getDiplayMedia(), vous pouvez contrôler si l'onglet ou la fenêtre capturé sera mis en avant ou non. Cela n'est possible que si l'utilisateur a partagé un onglet ou une fenêtre.

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

Lorsque vous décidez de mettre en avant ou non, vous pouvez tenir compte du descripteur de capture.

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

Il est même possible de décider de mettre en avant ou non avant d'appeler 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 });

Vous pouvez appeler setFocusBehavior() un nombre arbitraire de fois avant la résolution de la promesse, ou au maximum une fois immédiatement après la résolution de la promesse. La dernière invocation remplace toutes les invocations précédentes.

Plus précisément :

  • La promesse renvoyée par getDisplayMedia() se résout sur une microtâche. L'appel de setFocusBehavior() après la fin de cette microtâche génère une erreur.
  • L'appel de setFocusBehavior() plus d'une seconde après le début de la capture est une opération sans effet.

Autrement dit, les deux extraits suivants échoueront :

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

L'appel de setFocusBehavior() génère également une erreur dans les cas suivants :

  • La piste vidéo du flux renvoyé par getDisplayMedia() n'est pas "en direct".
  • Après la résolution de la promesse renvoyée par getDisplayMedia(), si l'utilisateur a partagé un écran (et non un onglet ou une fenêtre).

Échantillon

Vous pouvez tester Conditional Focus en exécutant la démo.

Détection de fonctionnalités

Pour vérifier si CaptureController.setFocusBehavior() est compatible, utilisez :

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

Commentaires

L'équipe Chrome et la communauté des normes Web souhaitent connaître votre expérience avec Conditional Focus.

Parlez-nous de la conception

Y a-t-il quelque chose dans Conditional Focus qui ne fonctionne pas comme prévu ? Ou manque-t-il des méthodes ou des propriétés dont vous avez besoin pour mettre en œuvre votre idée ? Vous avez une question ou un commentaire sur le modèle de sécurité ?

  • Signalez un problème de spécification dans le dépôt GitHub ou ajoutez vos commentaires à un problème existant.

Problème lors de l'implémentation ?

Avez-vous trouvé un bug dans l'implémentation de Chrome ? Ou l'implémentation est-elle différente de la spécification ?

  • Signalez un bug sur https://new.crbug.com. Veillez à inclure autant de détails que possible, ainsi que des instructions pour reproduire le problème.

Affichez votre soutien

Prévoyez-vous d'utiliser Conditional Focus ? Votre soutien public aide l'équipe Chrome à hiérarchiser les fonctionnalités et montre aux autres fournisseurs de navigateurs à quel point il est essentiel de les prendre en charge.

Envoyez un tweet à @ChromiumDev pour nous indiquer où et comment vous l'utilisez.

Remerciements

Merci à Rachel Andrew d'avoir examiné ce document.