1. 소개
풍부하게 상호작용하는 웹사이트, 게임 및 원격 데스크톱/애플리케이션 스트리밍 경험은 몰입형 전체 화면 경험을 제공하려 한다. 이를 달성하기 위해 사이트는 전체 화면 모드에 있을 때 특수 키와 키보드 단축키에 접근할 필요가 있으며, 이를 탐색, 메뉴 또는 게임 기능에 사용할 수 있다. 필요할 수 있는 키의 예로는 Escape, Alt+Tab, Cmd+`, 그리고 Ctrl+N이 있다.
기본적으로 이러한 키는 브라우저나 기반 운영 체제가 캡처하므로 웹 애플리케이션에서 사용할 수 없다. Keyboard Lock API는 웹사이트가 OS가 허용하는 모든 사용 가능한 키를 캡처하고 사용할 수 있게 한다.
2. Keyboard Lock API
2.1. Navigator 인터페이스
partial interface Navigator { [SecureContext ,SameObject ]readonly attribute Keyboard ; };keyboard
2.2. Keyboard 인터페이스
[SecureContext ,Exposed =Window ]interface :Keyboard EventTarget {Promise <undefined >(lock optional sequence <DOMString >= []);keyCodes undefined (); };unlock
keyboard 객체에는 keyboard lock 활성화가 있으며, 이는 Keyboard Lock이 활성화될 때 true로 설정되는 boolean이다. 기본적으로 이는 false로 설정된다.
keyboard 객체에는 예약된 키 코드가 있으며, 이는 DOMString의 집합이다. 각 DOMString은 키 코드 속성 값으로서, [UIEvents-Code]에 정의된 유효한 값이다. 기본적으로 이 집합은 비어 있다(keyboard lock 활성화가 활성화되어 있다면 모든 키를 캡처하게 된다).
keyboard 객체에는 keyboard lock 작업 큐가 있으며, 이는 새 병렬 큐 시작의 결과로 초기화된다.
참고: Keyboard
인터페이스는 EventTarget을
상속한다. 이는
layoutchange와 같은
일부 키보드 관련 이벤트를 처리할 수 있어야 하기 때문이다.
2.2.1. lock()
lock()이
호출되면, 사용자 에이전트는
다음 단계를 실행해야 한다:
-
p를 새 Promise로 둔다.
-
현재 활성 최상위 브라우징 컨텍스트에서 현재 실행 중이 아니면, 다음을 수행한다.
-
p를 "
InvalidStateError"DOMException으로 거부한다.
-
-
다음 단계를 keyboard lock 작업 큐에 큐에 추가한다:
-
예약된 키 코드를 빈 집합으로 재설정한다.
-
선택적
keyCodes인수가 존재하면, 다음 하위 단계를 실행한다:-
keyCodes안의 각 문자열 key에 대해 각각에 대해:-
key가 유효한 키 코드 속성 값이 아니면, 다음을 수행한다.
-
keyboard lock 활성화를 false로 설정한다.
-
p를 "
InvalidAccessError"DOMException으로 거부한다.
-
-
-
-
keyboard lock 활성화가 현재 false이면, 다음 하위 단계를 실행한다:
-
선택적으로 시스템 키 누름 핸들러를 등록한다.
-
keyboard lock 활성화를 true로 설정한다.
-
-
keyboard lock 작업 큐에 보류 중인
lock()작업이 있으면, 다음을 수행한다.-
keyboard lock 활성화를 false로 설정한다.
-
p를 "
AbortError" DOMException으로 거부한다.
-
-
p를 해결한다.
-
-
p를 반환한다.
참고: lock()이
중간에 unlock()
호출 없이 여러 번 호출되면,
마지막 요청 호출에 지정된 keyCodes만
효력을 가진다.
첫 번째 호출이 완료되기 전에 두 번째 lock()
호출이 이루어지면,
첫 번째 호출은 "AbortError"로
거부된다.
lock()을
호출한다:
navigator.keyboard.lock(["KeyW", "KeyA", "KeyS", "KeyD"]);
이는 키 누름에 어떤 modifier가 사용되든 관계없이 이러한 키를 캡처한다. 표준 US QWERTY 레이아웃을 가정하면, KeyW를 등록하면 "W", Shift+"W", Control+"W", Control+Shift+"W" 및 "W"와 함께 사용되는 모든 다른 키 modifier 조합이 앱으로 전송되도록 보장한다. KeyA, KeyS 및 KeyD에 대해서도 마찬가지이다.
navigator.keyboard.lock(["Delete"]);
이는 대부분의 Delete 키 누름(예: Shift+Delete, Control+Delete, Shift+Control+Delete)을 사용할 수 있게 하지만, Windows에서는 “secure attention sequence”인 Control+Alt+Delete를 사용할 수 있게 하지 않는다.
2.2.2. unlock()
unlock()이
호출되면, 사용자 에이전트는
다음 단계를 실행해야 한다:
-
다음 단계를 keyboard lock 작업 큐에 큐에 추가한다:
-
keyboard lock 활성화가 true이면, 다음 하위 단계를 실행한다:
-
keyboard lock 활성화를 false로 설정한다.
-
예약된 키 코드를 빈 시퀀스로 재설정한다.
-
참고: 문서가 닫히면, 사용자 에이전트는
[system key press handler=]가 있다면
그것이 등록 해제되도록 unlock()을
암묵적으로 호출해야 한다.
3. 키보드 키 누름 처리
3.1. 시스템 키 누름 핸들러
시스템 키 누름 핸들러는 플랫폼 수준에서 키를 필터링하는 데 사용할 수 있는 플랫폼별 핸들러이다. Keyboard Lock 기능은 일반적으로 브라우저에서 사용할 수 없는 키 누름(예: Cmd/Alt-Tab)에 대한 접근을 제공하기 위한 것이므로, 대부분의 플랫폼에서는 특수한 핸들러 설정이 필요하다.시스템 키 누름 핸들러는 다음 속성을 가져야 한다:
-
모든 사용자 에이전트 키보드 단축키가 처리되기 전에 키 누름을 처리해야 한다.
-
가능한 경우, 모든 시스템 키보드 단축키가 처리되기 전에 키 누름을 처리해야 한다.
3.1.1. 등록
시스템 키 누름 핸들러를 등록하려면, 사용자 에이전트는 플랫폼이 새 키 누름을 처리하기 시작할 때마다 호출될 저수준 hook을 추가하기 위해 플랫폼별 단계를 따라야 한다.
시스템 키 누름 핸들러를 추가하는 정확한 절차는 플랫폼마다 다르다. 일반 플랫폼에서 키 누름을 처리하기 위한 저수준 hook을 등록하는 방법의 예는 Windows의 경우 [LowLevelKeyboardProc], Mac OS X의 경우 [QuartzEventServices], X Windows의 경우 [GrabKeyboard]를 보라.
참고: 사용자 에이전트가 이미 다른 목적으로 키 누름 핸들러를 등록해 둔 경우, 위에서 언급한 요구 사항을 충족한다는 가정하에 해당 핸들러를 Keyboard Lock 기능을 지원하도록 선택적으로 확장할 수 있다.
3.1.2. 등록 해제
시스템 키 누름 핸들러 등록을 해제하려면, 사용자 에이전트는 새 키 누름을 처리하기 위한 (이전에 추가된) 저수준 hook을 제거하기 위해 플랫폼별 단계를 따라야 한다.
시스템 키 누름 핸들러 등록과 마찬가지로, 시스템 키 누름 핸들러 등록 해제 절차도 플랫폼별이다. 자세한 내용과 예제는 § 3.1.1 등록에 나열된 참고 문헌을 보라.
3.2. 키보드 이벤트 처리
사용자가 키를 누른 것에 대한 응답으로, 시스템 키 누름 핸들러가 등록되어 있다면, 다음 단계를 실행해야 한다:
-
최상위 브라우징 컨텍스트의 현재 포커스된 영역의 전체 화면 요소가 null이 아니면 isFullscreen을 true로 설정한다 ([Fullscreen] 참조).
참고: 예를 들어 포커스를 가진 시스템 대화상자가 표시되고 있다면, 전체 화면 요소는 포커스를 가지지 않을 것이다.
-
isFullscreen 및 keyboard lock 활성화가 모두 true로 설정되어 있으면, 다음 하위 단계를 실행한다:
-
keyEvent를 새 키 누름에 대한 키 이벤트로 둔다.
-
code를 keyEvent의
code속성 값으로 둔다. -
예약된 키 코드가 비어 있거나 code가 예약된 키 코드에 나열되어 있으면, 다음 하위 단계를 실행한다:
-
code가 "Escape"와 같으면, 다음 하위 단계를 실행한다:
-
사용자가 Escape 키를 길게 눌러 전체 화면에서 빠져나올 수 있음을 알려주는 메시지를 선택적으로 화면 위에 표시한다.
-
키가 2초 동안 눌려 있으면, 키보드 핸들러에서 빠져나와 정상 처리를 위해 사용자 에이전트에 키를 전달한다(그러면 전체 화면 (및 pointer lock이 활성화된 경우 pointer lock)에서 빠져나온다).
-
-
정상적인 사용자 에이전트 처리를 우회하여 keyEvent를 전체 화면 문서 또는 요소에 직접 디스패치한다.
-
-
그렇지 않으면, 키 이벤트를 일반적으로 처리되는 방식으로 처리한다. 즉, 키 이벤트를 디스패치하거나 일반적인 키보드 단축키 동작을 수행한다.
-
참고: 이 API는 "best effort" 기반으로 동작한다. 적합한 구현이 가능한 모든 키 조합에 대해 OS 기본 동작을 재정의할 수 있어야 하는 것은 아니다. 특히 대부분의 플랫폼에는 애플리케이션이 재정의할 수 없는 “secure attention sequence”(예: Windows의 Ctrl-Alt-Del)가 있으며, 이 명세는 그것을 대체하지 않는다.
참고: 이 API를 구현할 때, 사용자 에이전트는 키보드 이벤트가 페이지에 디스패치되는 순서를 변경하지 않도록 주의해야 한다. 예약된 키 코드 집합에 포함된 키는 해당 집합에 포함되지 않았더라면 전송되었을 것과 같은 상대적 순서로 디스패치되어야 한다.
4. 다른 웹 플랫폼 API와의 통합
[Fullscreen] 및 [PointerLock]는 페이지가 사용자 경험의 일부 (각각 화면 및 마우스 커서)를 일시적으로 제어할 수 있게 하는 API이다. 이러한 기능의 악용 우려 때문에, 이들은 사용자가 해당 기능에서 빠져나오기 위해 의존할 수 있는 "escape" 또는 "unlock" 제스처를 제공한다. 기본적으로 이 제스처는 Escape 키를 누르는 것이며, 이는 이 API가 캡처할 수 있는 키 중 하나이다.
4.1. Escape 키에 대한 특별 고려 사항
Escape 키와 관련된 특별 동작 때문에, lock()
요청에 Escape 키가 포함되면, 사용자 에이전트는 변경된 동작을 고려하기 위해
UX에 추가 변경을 해야 할 수 있다.
예를 들어, JavaScript가 시작한 전체 화면이 활성화될 때 사용자 에이전트가 "전체 화면에서 나가려면 ESC를 누르세요"라는 사용자 메시지를 표시한다면, keyboard lock이 적용 중일 때 해당 메시지는 "전체 화면에서 나가려면 ESC를 길게 누르세요"로 업데이트되어야 한다.
전체 화면이 이미 적용된 후 keyboard lock이 활성화되면, 사용자는
전체 화면에서 나가는 방법에 대한 여러 메시지를 보게 될 수 있다.
이러한 이유로, 개발자는 전체 화면에 들어가기 전에
lock()을
호출할 것을 권장한다:
navigator.keyboard.lock(); document.documentElement.requestFullscreen();
keyboard lock과 전체 화면에서 빠져나올 때에도 여러 사용자 메시지와 관련된 비슷한 우려가 있으므로, 반대 순서로 호출하는 것이 권장된다:
document.exitFullscreen(); navigator.keyboard.unlock();
일반적으로 개발자는 실제로 Escape 키가 필요한 경우에만 잠긴 키 집합에 Escape 키를 포함해야 한다. 또한 Escape 키가 잠겨 있다면, 개발자는 사용자가 현재 상태에서 빠져나올 수 있게 하는 그 기본 의미를 유지하는 것이 권장된다.
4.2. 전체 화면 고려 사항
최신 사용자 에이전트에서 사용할 수 있는 전체 화면에는 두 가지 유형이 있다: JavaScript가 시작한 전체 화면([Fullscreen] API를 통한 것)과 사용자가 시작한 전체 화면(사용자가 키보드 단축키를 사용해 전체 화면에 들어가는 경우). 사용자가 시작한 전체 화면은 흔히 "F11" 전체 화면이라고 불린다. 이는 전체 화면 모드에 들어가고 나가는 데 사용되는 일반적인 키 단축키이기 때문이다.
F11 전체 화면과 JavaScript(JS) 전체 화면은 같은 방식으로 동작하지 않는다. 사용자가 F11 전체 화면에 들어가면, 들어갈 때 사용한 동일한 키보드 단축키로만 빠져나올 수 있으며, 이 경우 exitFullscreen() 함수는 동작하지 않는다. 또한 JS 전체 화면에서 일반적으로 발생하는 전체 화면 이벤트는 F11 전체 화면에서는 전송되지 않는다.
이러한 차이(및 F11 전체 화면에 대한 표준 단축키가 없다는 점) 때문에, Keyboard Lock API는 JavaScript가 시작한 전체 화면이 활성화되어 있을 때만 유효하다. F11 전체 화면 중에는 keyboard event에 대한 Keyboard Lock 처리가 발생하지 않는다.
5. Pointer Lock 고려 사항
앞서 언급한 UX 변경 외에는 Pointer Lock의 동작에 변경 사항이 없다.
Pointer Lock이 전체 화면 밖에서 활성화되어 있으면, Keyboard Lock은 활성화될 수 없다.
Pointer Lock, Keyboard Lock, 전체 화면이 모두 활성화되어 있으면, Keyboard Lock에 Escape 키가 포함되지 않는 한 동작은 변경되지 않는다. 그 경우 유일한 변경 사항은 (위에서 언급한 것처럼) UX에 대한 것이다.
6. 모바일 장치 고려 사항
이는 키보드 중심 API이고 모바일 장치에는 일반적으로 물리 키보드가 없으므로, 이 API는 일반적으로 모바일 장치에 존재하거나 지원되지 않을 것이다.
하지만 물리 키보드가 연결되어 있을 때 의미가 있다면, 모바일 장치는 이 API를 지원하도록 선택할 수 있다.
7. 보안 고려 사항
이 API와 관련된 한 가지 우려는 모든 키를 가로채고 ([Fullscreen] 및 [PointerLock] API와 함께) 사용자가 웹 페이지에서 빠져나오지 못하게 하는 데 사용될 수 있다는 점이다.
이를 방지하기 위해, 사용자 에이전트는 API가 모든 키를 요청한 경우에도 사용자가 keyboard lock에서 빠져나올 방법을 제공해야 한다.
이 명세는 길게(2초 초과) Escape 키를 누르면 Keyboard Lock에서 빠져나오도록 트리거하는 지원을 요구한다. 또한 사용자 에이전트는 Keyboard Lock에서 빠져나오는 대체 방법을 제공하도록 선택할 수도 있다.
8. 개인정보 보호 고려 사항
해당 없음. 이 API는 현재 사용자에 대한 어떠한 개인정보도 사용하거나 드러내지 않는다.
9. 감사의 말
이 제안서의 작성으로 이어진 논의에 참여해 준 다음 사람들에게 감사한다:
Jon Dahlke (Google), Joe Downing (Google)