-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathindex.bs
448 lines (333 loc) · 16.9 KB
/
index.bs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
<h1>Keyboard Lock</h1>
<pre class="metadata">
Shortname: keyboard-lock
Level:
Group: webplatform
Status: CG-DRAFT
ED: https://wicg.github.io/keyboard-lock/
Repository: wicg/keyboard-lock
Editor:
Gary Kacmarcik, Google, [email protected]
Jamie Walch, Google, [email protected]
Abstract:
This specification defines an API that allows websites to
capture keys that are normally reserved by the underlying host
operating system. It is intended to be used by web
applications that provide a fullscreen immersive experience
(like games or remote access apps).
Status Text:
This document is an editor's draft proposed as a First Public Working Draft.
</pre>
<pre class="anchors">
urlPrefix: http://www.w3.org/TR/uievents-code/#; type: dfn; spec: uievents-code;
text: key code attribute value
urlPrefix: https://fullscreen.spec.whatwg.org/#; type: dfn; spec: fullscreen;
text: fullscreen element
urlPrefix: https://html.spec.whatwg.org/#; type: dfn; spec: html;
text: currently focused area of a top-level browsing context
text: top-level browsing context
urlPrefix: http://www.w3.org/TR/uievents-code/#code-; type: dfn; spec: uievents-code;
text: Delete
text: KeyA
text: KeyD
text: KeyS
text: KeyW
spec: ecma-262; urlPrefix: http://tc39.github.io/ecma262/
type: dfn
text: promise; url: sec-promise-objects
</pre>
<pre class="biblio">
{
"QuartzEventServices": {
"title": "Quartz Event Services",
"href": "https://developer.apple.com/reference/coregraphics/1658572-quartz_event_services"
},
"GrabKeyboard": {
"title": "X11 GrabKeyboard API",
"href": "https://www.x.org/releases/X11R7.7/doc/xproto/x11protocol.html#requests:GrabKeyboard"
},
"LowLevelKeyboardProc": {
"title": "LowLevelKeyboardProc documentation on MSDN",
"href": "https://msdn.microsoft.com/en-us/library/windows/desktop/ms644985(v=vs.85).aspx"
}
}
</pre>
<h2 id="introduction">Introduction</h2>
Richly interactive web sites, games and remote
desktop/application streaming experiences want to provide an
immersive, full screen experience. To accomplish this, sites
need access to special keys and keyboard shortcuts while they
are in full screen mode so that they can be used for
navigation, menus or gaming functionality. Some examples of
the keys that may be required are Escape, Alt+Tab, Cmd+`, and
Ctrl+N.
By default, these keys are not available to the web application because
they are captured by the browser or the underlying operating
system. The Keyboard Lock API enables websites to capture and use
all available keys allowed by the OS.
<h2 id="API">Keyboard Lock API</h2>
<h3 id="navigator-interface">Navigator Interface</h3>
<pre class="idl" data-highlight="webidl">
partial interface Navigator {
[SecureContext, SameObject] readonly attribute Keyboard keyboard;
};
</pre>
<div id="navigator-idl" dfn-for="Navigator">
<div class="algorithm" data-algorithm="navigator-keyboard">
<h4 id="h-navigator-keyboard"><dfn>keyboard</h4>
The [=keyboard=] attribute must return the {{Navigator}}'s {{Keyboard}} object.
</div>
</div><!-- dfn-for Navigator -->
<h3 id="keyboard-interface">Keyboard Interface</h3>
<pre class="idl" data-highlight="webidl">
[SecureContext, Exposed=Window]
interface Keyboard : EventTarget {
Promise<undefined> lock(optional sequence<DOMString> keyCodes = []);
undefined unlock();
};
</pre>
<div id="keyboard-idl" dfn-for="Keyboard">
The keyboard object has <dfn>enable keyboard lock</dfn>, which is a
boolean that is set to true when Keyboard Lock is enabled.
By default, this is set to false.
The keyboard object has <dfn>reserved key codes</dfn>, which is a
set of DOMStrings, each of which is a valid [=key code attribute value=]
as defined in [[UIEvents-Code]].
By default this set is empty (which would capture all keys
if [=enable keyboard lock=] was enabled).
The keyboard object has a <dfn>keyboard lock task queue</dfn> which is
initialized to the result of [=starting a new parallel queue=].
Note: The {{Keyboard}} interface inherits from {{EventTarget}} because
it needs to be able to handle some keyboard-releated events like
<a href="https://wicg.github.io/keyboard-map/#layoutchange-event"><code>layoutchange</code></a>.
<div class="algorithm" data-algorithm="keyboard-lock">
<h4 id="h-keyboard-lock"><dfn export>lock()</dfn></h4>
When {{lock()}} is called, the user agent must
run the following steps:
1. Let |p| be a new [=Promise=].
1. If not currently executing in the currently active [=top-level browsing context=], then
1. Reject |p| with an "{{InvalidStateError}}" {{DOMException}}.
1. [=Enqueue the following steps=] to the [=keyboard lock task queue=]:
1. Reset [=reserved key codes=] to be an empty set.
1. If the optional {{keyCodes}} argument is present, run the
following substeps:
1. [=list/For each=] string |key| in {{keyCodes}}:
1. If |key| is not a valid [=key code attribute value=], then
1. Set [=enable keyboard lock=] to be false.
1. Reject |p| with an "{{InvalidAccessError}}" {{DOMException}}.
1. [=set/Append=] |key| to [=reserved key codes=].
1. If [=enable keyboard lock=] is currently false, run the following
substeps:
1. Optionally, [=register a system key press handler=].
1. Set [=enable keyboard lock=] to be true.
1. If there is a pending {{lock()}} task in the [=keyboard lock task queue=], then
1. Set [=enable keyboard lock=] to be false.
1. Reject the |p| with an "{{AbortError}}" DOMException.
1. Resolve |p|.
1. Return |p|.
<div></div>
Note: If {{lock()}} is called multiple times without an
intervening call to {{unlock()}}, then only the
{{keyCodes}} specified in the last request call will be in effect.
If a second call to {{lock()}} is made before the first one has finished,
then the first one will be rejected with "{{AbortError}}".
<div class="example">
To capture all keys, simply call {{lock()}} with no arguments:
<pre>
navigator.keyboard.lock();
</pre>
</div>
<div class="example">
To capture the "W", "A", "S", and "D" keys, call {{lock()}} with
a list that contains the [=key code attribute value=] for each of these keys:
<pre>
navigator.keyboard.lock(["KeyW", "KeyA", "KeyS", "KeyD"]);
</pre>
This will capture these keys regardless of which modifiers are used with the
key press. Assuming a standard US QWERTY layout, registering [=KeyW=] will
ensure that "W", Shift+"W", Control+"W", Control+Shift+"W", and all other key
modifier combinations with "W" will be sent to the app. Similarly for
[=KeyA=], [=KeyS=] and [=KeyD=].
</div>
<div class="example">
Note that requesting a key is not a guarantee that all modified versions will
be made available to the app. As an example, consider [=Delete=]
<pre>
navigator.keyboard.lock(["Delete"]);
</pre>
While this will make most Delete key presses available (e.g., Shift+Delete,
Control+Delete, Shift+Control+Delete), on Windows it will not make available
the “secure attention sequence” Control+Alt+Delete.
</div>
</div><!-- lock() -->
<div class="algorithm" data-algorithm="keyboard-unlock">
<h4 id="h-keyboard-unlock"><dfn export>unlock()</dfn></h4>
When {{unlock()}} is called, the user agent must
run the following steps:
1. [=Enqueue the following steps=] to the [=keyboard lock task queue=]:
1. If [=enable keyboard lock=] is true, then run the following substeps:
1. [=Unregister the system key press handler=].
1. Set [=enable keyboard lock=] to be false.
1. Reset [=reserved key codes=] to be an empty sequence.
<div></div>
Note: When a document is closed, the user agent MUST implicitly call
{{unlock()}} so that the [system key press handler=] (if any) is
unregistered.
</div><!-- unlock() -->
</div><!-- dfn-for Keyboard -->
<h2 id="handling-events">Handling Keyboard Key Presses</h2>
<h3 id="key-press-handler">System Key Press Handler</h3>
A <dfn>system key press handler</dfn> is an platform-specific handler
that can be used to filter keys at the platform level. Since
Keyboard Lock feature is intended to provide access to key
presses that are not normally made available to the browser (for
example, Cmd/Alt-Tab), most platforms will require a special handler
to be set up.
The [=system key press handler=] must have the following properties:
* It must process key presses before any user agent keyboard shortcuts
are handled.
* Wherever possible, it should process key presses before any system
keyboard shortcuts are processed.
<h4 id="registering">Registering</h4>
To <dfn>register a system key press handler</dfn>, the user agent
will need to follow the platform-specific steps to add a low-level
hook that will be called whenever the platform begins to process a
new key press.
The exact process for adding a [=system key press handler=] varies
from platform to platform. For examples of how to register a
low-level hook to process key presses on common platforms, see
[[LowLevelKeyboardProc]] for Windows, [[QuartzEventServices]] for
Mac OS X and [[GrabKeyboard]] for X Windows.
Note: If the user agent already has a key press handler registered
for another purpose, then it can optionally extend that handler to
support the Keyboard Lock feature (assuming it meets the
requirements mentioned above).
<h4 id="unregistering">Unregistering</h4>
To <dfn>unregister the system key press handler</dfn>, the user
agent will need to follow the platform-specific steps to remove the
(previously added) low-level hook for processing new key press.
As with registering system key press handlers, the process for
unregistering system key press handlers is also platform-specific.
See the references listed in [[#registering]] for more details and
examples.
<h3 id="handling-keyboard-events">Handling Keyboard Events</h3>
In response to the user pressing a key, if a
[=system key press handler=] has been
<a lt="register a system key press handler">registered</a>,
it should run the following steps:
1. Let |isFullscreen| be set to true if the [=fullscreen element=] of the
[=currently focused area of a top-level browsing context=] is non-null
(see [[Fullscreen]]).
Note: The [=fullscreen element=] would not have focus, for example, if
there was a system dialog being displayed with focus.
1. If |isFullscreen| and [=enable keyboard lock=] are all set
to true, then run the following substeps:
1. Let |keyEvent| be the key event for the new key press.
1. Let |code| be the value of the {{KeyboardEvent/code}} attribute of |keyEvent|.
1. If [=reserved key codes=] is empty or if |code| is listed in
[=reserved key codes=], then run the following substeps:
1. If |code| is equal to "Escape", then run the following
substeps:
1. Optionally overlay a message on the screen telling the
user that they can Hold the Escape key to exit from
fullscreen.
1. If the key is held for 2 seconds, then exit from the
keyboard handler and pass the key on to the user agent
for normal processing (which will exit fullscreen
(and pointer lock, if active)).
1. Dispatch |keyEvent| directly to the fullsceen document or element,
bypassing any normal user agent processing.
1. Else, handle the key event as it normally would be handled,
either by dispatching a key event or performing the
usual keyboard shortcut action.
Note: This API operates on a "best effort" basis.
It is not required that a conforming implementation be able to
override the OS default behaviour for every possible key combination.
Specifically, most platforms have a “secure attention sequence” (e.g.,
Ctrl-Alt-Del on Windows) that applications cannot override; this
specification does not supersede that.
Note: When implementing this API, user agents should take care not to change
the order in which keyboard events are dispatched to the page. Keys that are
included in the set of [=reserved key codes=] must be dispatched in the same
relative order that they would have been sent had they not been included in the
set.
<h2 id="interactions">Integration With Other Web Platform APIs</h2>
[[Fullscreen]] and [[PointerLock]] are APIs that allow the page to temporarily take
control of part of the user's experience (screen and mouse cursor, respectively).
Because of the concern for abuse of these features, they provide an "escape" or
"unlock" gesture that the user can rely on to exit those features. By default,
this gesture is pressing the Escape key, which is one of the keys that can be
captured by this API.
<h3 id="escape-key">Special Considerations with the Escape Key</h3>
Because of the special actions associated with the Escape key, when the {{lock()}}
request includes the Escape key, the user agent may need to make additional
changes to the UX to account for the changed behavior.
For example, if the user agent shows a user message "Press ESC to exit fullscreen"
when Javascript-initiated fullscreen is activated, then that message will need to
be updated when keyboard lock is in effect to read "Press and hold ESC to exit
fullscreen".
If keyboard lock is activated after fullscreen is already in effect, then the user
my see multiple messages about how to exit fullscreen.
For this reason, we recommend that developers call {{lock()}} before they enter
fullscreen:
<pre>
navigator.keyboard.lock();
document.documentElement.requestFullscreen();
</pre>
A similar concern with multiple user messages exists when exiting keyboard lock and
fullscreen, so it is recommended to call them in the reverse order:
<pre>
document.exitFullscreen();
navigator.keyboard.unlock();
</pre>
In general, developers should only include the Escape key in the set of locked
keys if they actually have need for that key. And it is recommended that, if the
Escape key is locked, the developer should maintain its primary meaning of
allowing the user to exit their current state.
<h3 id="fullscreen-considerations">Fullscreen Considerations</h3>
There are two different types of fullscreen available in modern user agents:
JavaScript-initiated fullscreen (via the [[Fullscreen]] API) and
user-initiated fullscreen (when the user enters fullscreen using a keyboard
shortcut). The user-initiated fullscreen is often referred to as "F11"
fullscreen since that is a common key shortcut used to enter and exit
fullscreen mode.
F11 fullscreen and JavaScript (JS) fullscreen do not behave the same way.
When a user enters F11 fullscreen, they can only exit it via the same
keyboard shortcut that they used to enter it -- the exitFullscreen()
function will not work in this case. In addition, fullscreen events that are
normally fired for JS fullscreen are not sent for F11 fullscreen.
Because of these differences (and because there is no standard shortcut
for F11 fullscreen), the Keyboard Lock API is only valid when the
a JavaScript-initiated fullscreen is active. During F11 fullscreen, no
Keyboard Lock processing of keyboard events will take place.
<h2 id="pointerlock-considerations">Pointer Lock Considerations</h2>
Other than the UX changes noted earlier, there are no changes to the operation
of Pointer Lock.
When Pointer Lock is enabled outside of fullscreen, then Keyboard Lock cannot
be enabled.
When Pointer Lock, Keyboard Lock and Fullscreen are all enabled, then the behavior
is unchanged unless Keyboard Lock includes the Escape key. In that case, the
only chages are to the UX (as noted above).
<h2 id="mobile">Mobile Device Considerations</h2>
Since this is a keyboard-focused API and mobile devices do not commonly
have physical keyboards, this API will not typically be present or
supported on mobile devices.
However, mobile devices may choose to support this API if it makes sense to
do so when a physical keyboard is connected.
<h2 id="security">Security Considerations</h2>
One concern with this API is that it could be used to grab all of the keys
and (in conjunction with the [[Fullscreen]] and [[PointerLock]] API) prevent
the user from exiting the web page.
To prevent this, the user agent MUST provide a way for the user to exit from
keyboard lock even if all of the keys are requested by the API.
This specification requires support for allowing a long (more than 2 second) Escape
key press to trigger an exit from Keyboard Lock. In addition, user agents may choose
to also provide alternate ways to exit Keyboard Lock.
<h2 id="privacy">Privacy Considerations</h2>
Not applicable. This API does not use or reveal any personal information
about the current user.
<h2 id="acknowledgements-contributors">Acknowledgements</h2>
Thanks to the following people for the discussions that lead
to the creation of this proposal:
Jon Dahlke (Google),
Joe Downing (Google)