Signatur
Beschreibung
Wenn Nutzer über navigator.mediaDevices.getDisplayMedia() einen Browser-Tab oder ein Fenster zum Teilen auswählen, holt der Browser diese Oberfläche normalerweise in den Vordergrund. Mit setFocusBehavior() eines CaptureController-Objekts kann die aufnehmende Anwendung das steuern. Sie kann den Fokus auf die geteilte Oberfläche wechseln lassen ("focus-captured-surface") oder selbst im Vordergrund bleiben ("no-focus-change").
Das ist vor allem für Videokonferenz- und Präsentations-Apps nützlich. Wer zum Beispiel ein Folien-Fenster teilt, will meist sofort dorthin wechseln. Wer dagegen einen Tab nur zur Vorschau oder Aufnahme mitschneidet, will oft in der eigenen Oberfläche bleiben, etwa um die Videokacheln der Teilnehmer im Blick zu behalten.
Den Controller übergibt man im Optionsobjekt als controller an getDisplayMedia(). Die Methode lässt sich vor dem Aufruf von getDisplayMedia() oder unmittelbar nach dem Erfüllen des Promise aufrufen. Im zweiten Fall kann man je nach Art der gewählten Oberfläche entscheiden, die man über track.getSettings().displaySurface ausliest. Wartet man zu lange, nimmt der Browser sein Standardverhalten an (Fokuswechsel), und spätere Aufrufe lösen einen Fehler aus.
Die Methode gilt nur für Tabs (displaySurface === "browser") und Fenster ("window"). Bei einem ganzen Bildschirm ("monitor") gibt es keinen Fokus, der gewechselt werden könnte.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $focusBehavior Pflicht | "focus-captured-surface" | "no-focus-change" | "focus-captured-surface": Der geteilte Tab bzw. das geteilte Fenster wird in den Vordergrund geholt (Standardverhalten des Browsers). "no-focus-change": Der Fokus bleibt auf der aufnehmenden Seite. |
Rückgabewert
Beispiele
Fokus je nach gewählter Oberfläche steuern
const shareScreen = async () => {
const controller = new CaptureController();
const stream = await navigator.mediaDevices.getDisplayMedia({
video: true,
controller,
});
// Direkt nach dem Erfüllen des Promise entscheiden – nicht erst später!
const [track] = stream.getVideoTracks();
const { displaySurface } = track.getSettings();
if (displaySurface === 'browser') {
// Geteilten Tab in den Vordergrund holen
controller.setFocusBehavior('focus-captured-surface');
} else if (displaySurface === 'window') {
// Bei Fenstern in der eigenen App bleiben
controller.setFocusBehavior('no-focus-change');
}
console.log('Geteilt wird:', displaySurface);
return stream;
};
document.querySelector('#share').addEventListener('click', shareScreen);
Fokus schon vor dem Aufruf festlegen
const startRecording = async () => {
const controller = new CaptureController();
// Vor getDisplayMedia() gesetzt: gilt unabhängig von der Auswahl
controller.setFocusBehavior('no-focus-change');
const stream = await navigator.mediaDevices.getDisplayMedia({
video: true,
controller,
});
document.querySelector('video#preview').srcObject = stream;
console.log('Aufnahme läuft, Fokus bleibt in der App.');
};
document.querySelector('#record').addEventListener('click', startRecording);
Feature-Erkennung mit Fehlerbehandlung
const share = async (keepFocus) => {
const options = { video: true };
let controller;
if ('CaptureController' in window &&
'setFocusBehavior' in CaptureController.prototype) {
controller = new CaptureController();
options.controller = controller;
}
const stream = await navigator.mediaDevices.getDisplayMedia(options);
try {
controller?.setFocusBehavior(
keepFocus ? 'no-focus-change' : 'focus-captured-surface'
);
} catch (err) {
// z. B. InvalidStateError, wenn der Zeitpunkt verpasst wurde
console.warn('Fokusverhalten nicht gesetzt:', err.name);
}
return stream;
};
document.querySelector('#share').addEventListener('click', () => share(true));
// Wichtig · Fallstricke
- Zeitfenster: Nach dem Erfüllen des Promise muss der Aufruf sofort erfolgen, also im selben Task ohne weiteres
awaitauf langsame Vorgänge. Andernfalls greift das Standardverhalten, und die Methode wirft einenInvalidStateError. - InvalidStateError tritt außerdem auf, wenn die Aufnahme bereits beendet ist, der Track also den Zustand
"ended"hat, oder wenn der Controller schon an einen anderen Aufruf gebunden ist. Je Aufnahme ist ein eigenerCaptureControllernötig. - Nur Tabs und Fenster: Bei
displaySurface === "monitor"hat die Methode keinen sinnvollen Effekt. Prüfe die Oberfläche deshalb vorher mitgetSettings(). - Kompatibilität: Die Methode ist experimentell und bisher nur in Chromium-Browsern ab Version 109 verfügbar, nicht auf Mobilgeräten. Firefox und Safari unterstützen sie nicht. Verwende Feature-Erkennung.
- Es gelten die Voraussetzungen von
getDisplayMedia(): ein sicherer Kontext (HTTPS), eine Nutzeraktion wie ein Klick sowie gegebenenfalls die Permissions-Policydisplay-capturein iframes.