조건부 포커스로 화면 공유 개선

François Beaufort
François Beaufort

브라우저 지원

  • Chrome: 109
  • Edge: 109
  • Firefox: 지원되지 않음
  • Safari: 지원되지 않음

소스

Screen Capture API를 사용하면 사용자가 미디어 스트림으로 캡처할 탭, 창 또는 화면을 선택할 수 있습니다. 그런 다음 이 스트림을 네트워크를 통해 녹화하거나 다른 사용자와 공유할 수 있습니다. 이 문서에서는 캡처가 시작될 때 캡처된 탭 또는 창에 포커스가 있는지 또는 캡처 페이지에 포커스가 계속 있는지 웹 앱에서 제어하는 메커니즘인 조건부 포커스를 소개합니다.

브라우저 지원

조건부 포커스는 Chrome 109부터 사용할 수 있습니다.

배경

웹 앱이 탭이나 창 캡처를 시작하면 브라우저는 캡처된 노출 영역을 포그라운드로 가져와야 할지 아니면 캡처 페이지에 포커스를 유지해야 할지 결정해야 합니다. 답변은 getDisplayMedia()를 호출하는 이유와 사용자가 선택하는 노출 영역에 따라 다릅니다.

가상의 화상 회의 웹 앱을 생각해 보세요. 화상 회의 웹 앱은 track.getSettings().displaySurface를 읽고 Capture Handle을 검사하여 사용자가 공유하기로 선택한 항목을 파악할 수 있습니다. 그런 다음 아래를 실행합니다.

  • 캡처된 탭이나 창을 원격으로 제어할 수 있는 경우 화상 회의에 초점을 맞춥니다.
  • 그렇지 않으면 캡처된 탭 또는 창에 포커스를 맞춥니다.

위 예시에서 화상 회의 웹 앱은 슬라이드 자료 공유 시 포커스를 유지하므로 사용자가 원격으로 슬라이드를 넘길 수 있습니다. 하지만 사용자가 텍스트 편집기를 공유하도록 선택하면 화상 회의 웹 앱은 포커스를 캡처된 탭 또는 창으로 즉시 전환합니다.

Conditional Focus API 사용

CaptureController를 인스턴스화하여 getDisplayMedia()에 전달합니다. getDiplayMedia()가 반환한 프라미스가 해결된 직후 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");
}

포커스를 맞출지 결정할 때 Capture Handle을 고려할 수 있습니다.

// 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()를 호출하면 오류가 발생합니다. - 캡처가 시작된 후 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()에서 반환된 스트림의 동영상 트랙이 '실시간'이 아닙니다.
  • 사용자가 탭이나 창이 아닌 화면을 공유한 경우 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에 트윗을 보내 사용 중이신 위치와 방법을 알려주세요.

감사의 말씀

엘레나 타란엔코의 히어로 이미지

이 도움말을 검토해 주신 레이첼 앤드류님께 감사드립니다.