├── .github ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── auto-publish.yml │ └── tidy.yml ├── .gitignore ├── .pr-preview.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── FeatureRequests.md ├── LICENSE.md ├── README.md ├── index.html ├── publish ├── Errata.md ├── index-2013-10-31-LCWD-flattened.html ├── index-2013-10-31-LCWD.html ├── index-2013-12-17-CR-flattened.html ├── index-2016-07-05-CR-flattened.html ├── index-2016-07-05-CR.html ├── index-2016-08-30-PR-flattened.html ├── index-2016-10-27-REC-flattened.html ├── index-v2-2016-11-22-FPWD-flattened.html └── index-v2-2018-02-08-WD-flattened.html ├── tests ├── movementX_Y_basic-manual.html ├── movementX_Y_no-jumps-manual.html ├── pointerlock_basic-manual.html ├── pointerlock_fullscreen-manual.html ├── pointerlock_indefinite-manual.html ├── pointerlock_leave_Tab-manual.html ├── pointerlock_leave_UA-manual.html ├── pointerlock_remove_target-manual.html ├── resources │ ├── LICENSE │ ├── readme.md │ ├── testharness.css │ ├── testharness.js │ └── testharnessreport.js └── test-results │ ├── Ch53.json │ ├── Ed25.json │ ├── Ff51.json │ ├── all.html │ ├── analysis.css │ ├── bootstrap.min.css │ ├── complete-fails.html │ └── less-than-2.html ├── tidyconfig.txt └── w3c.json /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Closes #??? 2 | 3 | The following tasks have been completed: 4 | 5 | * [ ] Modified Web platform tests (link to pull request) 6 | 7 | Implementation commitment: 8 | 9 | * [ ] WebKit (https://bugs.webkit.org/show_bug.cgi?id=) 10 | * [ ] Chromium (https://bugs.chromium.org/p/chromium/issues/detail?id=) 11 | * [ ] Gecko (https://bugzilla.mozilla.org/show_bug.cgi?id=) -------------------------------------------------------------------------------- /.github/workflows/auto-publish.yml: -------------------------------------------------------------------------------- 1 | name: Node CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - gh-pages 7 | pull_request: {} 8 | 9 | jobs: 10 | validate-and-publish: 11 | name: Validate and Publish 12 | runs-on: ubuntu-latest # only linux supported at present 13 | steps: 14 | - uses: actions/checkout@v2 15 | - uses: w3c/spec-prod@v2 16 | with: 17 | TOOLCHAIN: respec 18 | VALIDATE_LINKS: true 19 | W3C_ECHIDNA_TOKEN: ${{ secrets.ECHIDNA_TOKEN }} 20 | W3C_WG_DECISION_URL: "https://lists.w3.org/Archives/Public/public-webapps/2014JulSep/0627.html" 21 | W3C_NOTIFICATIONS_CC: "${{ secrets.CC }}" 22 | W3C_BUILD_OVERRIDE: | 23 | specStatus: WD 24 | shortName: pointerlock-2 25 | -------------------------------------------------------------------------------- /.github/workflows/tidy.yml: -------------------------------------------------------------------------------- 1 | name: Tidy document 2 | on: 3 | workflow_dispatch: {} 4 | push: 5 | branches: 6 | - gh-pages 7 | 8 | jobs: 9 | tidy: 10 | name: Tidy up 11 | runs-on: macos-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - run: brew install tidy-html5 15 | - run: tidy -config tidyconfig.txt -o index.html index.html 16 | - uses: peter-evans/create-pull-request@v3 17 | with: 18 | title: "Tidied up document using tidy-html5" 19 | commit-message: "chore: tidy up index.html" 20 | branch: html-tidy 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .hg 2 | .hgignore 3 | -------------------------------------------------------------------------------- /.pr-preview.json: -------------------------------------------------------------------------------- 1 | { 2 | "src_file": "index.html", 3 | "type": "respec" 4 | } -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | All documentation, code and communication under this repository are covered by the [W3C Code of Ethics and Professional Conduct](https://www.w3.org/Consortium/cepc/). 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributions to this repository are intended to become part of Recommendation-track documents governed by the 2 | [W3C Patent Policy](http://www.w3.org/Consortium/Patent-Policy-20040205/) and 3 | [Software and Document License](http://www.w3.org/Consortium/Legal/copyright-software). To make substantive contributions to specifications, you must either participate 4 | in the relevant W3C Working Group or make a non-member patent licensing commitment. 5 | 6 | If you are not the sole contributor to a contribution (pull request), please identify all 7 | contributors in the pull request comment. 8 | 9 | To add a contributor (other than yourself, that's automatic), mark them one per line as follows: 10 | 11 | ``` 12 | +@github_username 13 | ``` 14 | 15 | If you added a contributor by mistake, you can remove them in a comment with: 16 | 17 | ``` 18 | -@github_username 19 | ``` 20 | 21 | If you are making a pull request on behalf of someone else but you had no part in designing the 22 | feature, you can remove yourself with the above syntax. 23 | 24 | # Tests 25 | 26 | For normative changes, a corresponding 27 | [web-platform-tests](https://github.com/web-platform-tests/wpt) PR is highly appreciated. Typically, 28 | both PRs will be merged at the same time. Note that a test change that contradicts the spec should 29 | not be merged before the corresponding spec change. If testing is not practical, please explain why 30 | and if appropriate [file an issue](https://github.com/web-platform-tests/wpt/issues/new) to follow 31 | up later. Add the `type:untestable` or `type:missing-coverage` label as appropriate. 32 | -------------------------------------------------------------------------------- /FeatureRequests.md: -------------------------------------------------------------------------------- 1 | # Features to be considered for Next Version 2 | 3 | Feature requests and new requirements for the next version of the [Pointer Lock specification](https://w3c.github.io/pointerlock/) are gathered here for consideration in subsiquent versions of the specification. 4 | 5 | Submit a feature request by filing a [Pointer Lock Issue](https://github.com/w3c/pointerlock/issues) or submiting a pull request with changes to this document. 6 | 7 | ## Pointer Clip: Limiting movement of the cursor without hiding it 8 | 9 | https://github.com/w3c/pointerlock/issues/27 10 | 11 | * Restrict pointer to a rectangle (while either windowed or in fullscreen (relevant for multi-display)) 12 | * Suppress any user agent or operating system UI elements that appear when hovering cursor in a region. This prevents e.g. a "hover near top of screen to bring down fullscreen exit instruction reminder" or the Mac OSX Dock that appears at screen edges. 13 | * Security issues would then be essentially the same as pointer lock, the difference being that a) the pointer is not hidden, b) the pointer is not warped, c) the pointer is bounded by the area specified by the web app - not the user agent selected rectangle used as an implementation detail of pointer lock. 14 | * [Notes on Pointer Clip from a Chromium discussion](https://docs.google.com/a/chromium.org/document/d/1lfU5BwiBaC0CeqsbUWLGGKtAr5tho6PBrN2zXk3he6A/edit?pli=1). 15 | * See thread [Problems with mouse-edge scrolling and games](http://lists.w3.org/Archives/Public/public-webapps/2014JanMar/0473.html). 16 | 17 | 18 | ## Raw movement data, not pixel location clamped, and unmodified by operating system 'acceleration' or 'ballistics' 19 | 20 | * Operating systems perform conditioning of mouse input data to facilitate use for a system pointer. Typically faster mouse movement results in a larger pointer movement for the same distance traveled. Some articles on this topic: 21 | * http://blog.codinghorror.com/mouse-ballistics/ 22 | * https://msdn.microsoft.com/en-us/library/windows/desktop/ee418864.aspx 23 | * Sub pixel movement accuracy doesn't offer a pixel based screen pointer an advantage, but may have meaningful interpretation by applications using Pointer Lock. 24 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | All documents in this Repository are licensed by contributors 2 | under the 3 | [W3C Software and Document License](http://www.w3.org/Consortium/Legal/copyright-software). -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | The Web Applications Working Group's 2 | 3 | [Pointer Lock 2 Specification](https://w3c.github.io/pointerlock/) 4 | 5 | which extends the initial 6 | 7 | [Pointer Lock W3C Recommendation Specification](https://www.w3.org/TR/pointerlock/). 8 | 9 | See also the [Pointer Lock Feature Requests](FeatureRequests.md). 10 | -------------------------------------------------------------------------------- /publish/Errata.md: -------------------------------------------------------------------------------- 1 | # Pointer Lock Errata for W3C Recommendation 20 October 2016 2 | 3 | This document describes the known errata and proposed corrections for the Pointer Lock API published as an [Recommendation](https://www.w3.org/TR/pointerlock/) on 20 October 2016. -------------------------------------------------------------------------------- /publish/index-2013-10-31-LCWD.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Pointer Lock 5 | 6 | 7 | 12 | 13 | 80 | 81 | 91 | 92 | 97 | 98 | 99 |
100 | This specification defines an API that provides scripted access to raw 101 | mouse movement data while locking the target of mouse events to a single 102 | element and removing the cursor from view. This is an essential input 103 | mode for certain classes of applications, especially first person 104 | perspective 3D applications and 3D modelling software. 105 |
106 | 107 |
108 | A history of changes to this document can be found at 109 | 110 | http://dvcs.w3.org/hg/pointerlock/log/default/index.html 111 |
112 | 113 |
114 | 115 |

Introduction

116 | 117 |

The Pointer Lock API provides for input methods of applications based on 118 | the movement of the mouse, not just the absolute position of a cursor. A 119 | popular example is that of first person movement controls in three 120 | dimensional graphics applications such as games. Movement of the mouse is 121 | interpreted for rotation of the view-port, there is no limit to how far 122 | movement can go, and no mouse cursor is displayed.

123 | 124 |

Pointer Lock is related to Mouse Capture [[MDN-SETCAPTURE]]. Capture provides 125 | continued event delivery to a target element while a mouse is being 126 | dragged, but ceases when the mouse button is released. Pointer Lock differs 127 | by being persistent, not limited by screen boundaries, sending events 128 | regardless of mouse button state, hiding the cursor, and not releasing 129 | until an API call or specific default unlock gesture by the user.

130 | 131 |

Pointer Lock deals with capturing a single resource and relating it to 132 | a single element. This is similar to the Fullscreen API [[FULLSCREEN]], which 133 | promotes a single element to be full screen. The Pointer Lock API chooses 134 | to pattern the resource capture, state change, and release API as closely 135 | as possible after the Fullscreen API.

136 | 137 |

The Pointer Lock interaction mode was previously referred to as 138 | mouse lock. The name was changed as many different controller types 139 | besides mice can manipulate the on screen pointing cursor, and they are 140 | all impacted.

141 | 142 |
143 | 144 |
145 |

146 | This specification defines conformance criteria that apply to a single 147 | product: the user agent that implements 148 | the interfaces that it contains. 149 |

150 | 151 |

152 | Implementations that use ECMAScript to implement the APIs defined in 153 | this specification MUST implement them in a manner consistent with the 154 | ECMAScript Bindings defined in the Web IDL specification [[!WEBIDL]] as 155 | this specification uses that specification and terminology. 156 |

157 | 158 |

159 | A conforming implementation is required to implement all fields 160 | defined in this specification. 161 |

162 |
163 | 164 |
165 |

Glossary

166 | 167 |
Engagement gesture
168 |
169 | An event generated by the user agent as a result of user interaction 170 | intended to interact with the page. e.g. click, but not 171 | mousemove. 172 | Engagement gestures are any events included in the definition of being 173 | 174 | allowed to show a popup 175 | with the addition of keypress and keyup. 176 |
177 | 178 | 179 |
180 | 181 |
182 |

pointerlockchange and pointerlockerror Events

183 | 184 |

Two events are used to communicate pointer lock state change or 185 | an error in changing state. They are named pointerlockchange 186 | and pointerlockerror. If pointer lock is entered or exited 187 | for any reason a pointerlockchange event must be sent.

188 | 189 |

User agents 190 | must deliver these events by 192 | queuing a task to 194 | fire an event of the appropriate name with its 195 | bubble attribute set to false to the pointer lock 196 | target element's 198 | node document.

199 |
200 | 201 |
202 |

Element Interface

203 |

204 | The Element interface is extended to provide the ability to 205 | request the the pointer be locked. 206 |

207 | 208 |
209 |
void requestPointerLock()
210 |
211 | 212 | 213 |

Requests that the pointer be locked to a DOM element 214 | target. The user agent determines if pointer lock 215 | state will be entered and upon lock state change or error must send 216 | either a pointerlockchange or pointerlockerror 217 | event respectively. 218 | 219 |

Pointer lock must succeed only if the document object's 220 | 221 | active sandboxing flag set does not have the 222 | sandboxed pointer lock browsing context flag set. 223 | 224 |

Pointer lock must succeed only if the target is 225 | in 226 | the 227 | active document 228 | of a 229 | browsing context 230 | which is (or has an 231 | ancestor browsing context 232 | which is) in focus by a window which is in focus by the 233 | operating system's window manager. The target element and its 234 | browsing context 235 | need not be in focus.

236 | 237 |

If a user has exited pointer lock via the default unlock user 238 | gesture, or pointer lock has not previously been entered for this 239 | document, an event generated as a result of an 240 | engagement gesture must be received by the document before 241 | requestPointerLock will succeed.

242 | 243 |

244 | This ensures a user can leave a 245 | document that constantly attempts to lock the pointer. The document 246 | will be blocked from locking upon initial navigation or re-acquiring 247 | lock unless the user re-engages directly with the document.

248 | 249 | Conversely, if pointer lock is exited via exitPointerLock 250 | no engagement gesture is required to reenter pointer lock. This enables 251 | applications that frequently move between interaction modes, and 252 | ones that may do so based on a timer or remote network activity. 253 |

254 | 255 | Pointer lock is commonly combined with fullscreen [[FULLSCREEN]], and 256 | if an engagement gesture is used to enter fullscreen it is sufficient 257 | for a subsequent requestPointerLock. 258 |

259 | 260 |

If any element (including this one) in the same document 261 | is already locked (or pending lock) the pointer 262 | lock target must be updated to this element and a 263 | pointerlockchange event sent.

264 | 265 |

If any element in another document is already locked the request 266 | must fail and a pointerlockerror event be sent.

267 | 268 |

Once in the locked state the user agent must fire all relevant 269 | user generated MouseEvent events (for example: 270 | mousemove, mousedown, mouseup, 271 | click, wheel)[[!DOM-LEVEL-3-CORE]] 272 | to the target of pointer lock, and not fire mouse events to 273 | other elements. Events that require the concept of a mouse cursor must 274 | not be dispatched (for example: mouseover, 275 | mouseout, drag, drop).

276 | 277 |

In the locked state the system mouse cursor 278 | must be hidden. Movement and button presses of the mouse must not 279 | cause the window to lose focus.

280 | 281 |

Synthetic mouse events created by application script act the same 282 | regardless of lock state.

283 |

284 |
285 |
286 | 287 |
288 |

Extensions to the Document Interface

289 | 290 |
291 |
attribute EventHandler? onpointerlockchange
292 |
293 | 294 | 295 |

An event handler 296 | for pointerlockchange events.

297 |
298 | 299 |
attribute EventHandler? onpointerlockerror
300 |
301 | 302 | 303 |

An event handler 304 | for pointerlockerror events.

305 |
306 | 307 |
readonly attribute Element? pointerLockElement
308 |
309 | 310 | 311 |

Returns the element set as the target for mouse events 312 | while the pointer is locked. Null if lock is pending, pointer is 313 | unlocked, or if the target is in another document.

314 |
315 | 316 |
void exitPointerLock ()
317 |
318 | 319 | 320 |

Initiates an exit from pointer lock state if currently locked 321 | to a target in this document, 322 | and sends a pointerlockchange event when the lock state 323 | has been exited.

324 | 325 |

The system mouse cursor must be displayed again and positioned at 326 | the same location that it was when pointer lock was entered (the same 327 | location that is reported in screenX/Y 328 | when the pointer is locked).

329 |
330 |
331 |
332 | 333 |
334 |

Extensions to the MouseEvent Interface

335 | 336 |

User agents must extend the MouseEvent interface [DOMMOUSE] 338 | with two members:

339 | 340 |
341 |
readonly attribute long movementX
342 |
343 |
readonly attribute long movementY
344 |
345 |
346 | 347 |

The members movementX and movementY must 348 | provide the change in position of the pointer, as if the values of 349 | screenX/Y were stored between two subsequent 350 | mousemove events eNow and 351 | ePrevious and the difference taken 352 | movementX = eNow.screenX-ePrevious.screenX.

353 | 354 |

movementX/Y must be zero for all mouse events 355 | except mousemove. All motion data must be delivered via 356 | mousemove events such that between any two mouse events 357 | earlierEvent and currentEvent the value of 358 | currentEvent.screenX-earlierEvent.screenX is equivalent to 359 | the sum of all movementX values received on 360 | mousemove events after earlierEvent.

361 | 362 |

movementX/Y must be valid regardless of pointer 363 | lock state.

364 | 365 |

When unlocked, the system cursor can exit and re-enter the user 366 | agent window. If it does so and the user agent was not the 367 | target of operating system mouse move events then the most recent pointer 368 | position will be unknown to the user agent and 369 | movementX/Y can not be computed and must be set 370 | to zero.

371 | 372 |

When pointer lock is enabled clientX, clientY, 373 | screenX, and screenY must hold constant values 374 | as if the pointer did not move at all once pointer lock was entered. But 375 | movementX/Y must continue to provide the change 376 | in position of the pointer as when the pointer is unlocked. There will be no 377 | limit to movementX/Y values if the mouse is 378 | continuously moved in a single direction. The concept of the mouse cursor 379 | will have been removed, and it will not move off the window or be clamped 380 | by a screen edge.

381 |
382 | 383 |
384 |

Requirements

385 | 386 |

A default unlock gesture must always be available that 387 | will exit pointer lock.

388 |

The ESC key is the recommended default unlock 389 | gesture for user agents with keyboard input. It is recommended that 390 | the unlock gesture also match any used to exit fullscreen 391 | [[FULLSCREEN]].

392 | 393 |

Pointer lock must be exited if the 394 | target is removed from its document, or the user agent, 395 | window, or tab loses focus. Moving focus between elements of 396 | active documents, 397 | including between 398 | browsing contexts, 399 | does not exit pointer lock. E.g. using the keyboard 400 | to move focus between contents of frames or iframes will not exit.

401 | 402 |

Pointer lock must not be exited when fullscreen [[FULLSCREEN]] is 403 | entered or exited unless the pointer is required to enable interaction 404 | with the user agent graphical user interface or the default 405 | unlock gesture was used to exit both fullscreen and pointer 406 | lock.

407 |
408 | 409 |
410 |

Use Cases

411 | 412 |
413 |

Relative view-port rotation of free moving virtual actors

414 | 415 |

A player on a first/third person game will need to control the 416 | view-port orientation. A widely used method is the use of mouse movements 417 | to control the viewing angle. This kind of application can use the Pointer 418 | Lock API to allow a complete freedom of control over the viewport's yaw 419 | and pitch even when the user is not pressing mouse buttons. Those buttons 420 | can be used for other actions while constantly providing navigation via 421 | mouse movement.

422 |
423 | 424 |
425 |

Free rotation of 3D models or panning of 2D layers

426 | 427 |

Users of a three dimensional modeling application will need to rotate 428 | models. A application can use the Pointer Lock API to enable the author to 429 | rotate the model freely in a drag operation without limiting motion. 430 | Without pointer lock a drag would stop providing motion data when the mouse 431 | cursor is limited by the edge of the screen.

432 | 433 |

Similarly, absolute motion panning of a large two dimensional image 434 | could be permitted in a single drag operation without cursor / screen 435 | limits.

436 |
437 | 438 |
439 |

Relative movement of actors

440 | 441 |

A player on a fast reflexes game controls a paddle to bounce back a 442 | ball to the opponent, while allowing the same paddle to execute actions 443 | based on different mouse buttons being pressed. The application can use 444 | the Pointer Lock API to allow the player to react quickly without being 445 | concerned about the mouse cursor leaving the game play area and clicking 446 | another system application, thus breaking the game flow.

447 |
448 | 449 |
450 |

Jog movement over spinner controls

451 | 452 |

When modifying numerically magnitudes in applications sometimes the 453 | user will prefer to "drag" a numeric control by its button handles to 454 | increment or decrement the numeric value. E.g. a spinner with a 455 | number entry text box and arrows pointing up and down that can be 456 | clicked or dragged on to change the value. An 457 | application could use the Pointer Lock API to allow modifying the numeric 458 | values beyond what the logical screen bounds allow. The same could apply 459 | for a control that fast forwards or rewinds a video or audio stream like a 460 | "jog".

461 |
462 | 463 |
464 |

Synthetic cursor interaction with HTML DOM UI

465 | 466 |

Some games use a classical cursor, however they want it to be limited 467 | or controlled in some manner. E.g. limited to the bounds of the game, or 468 | movable by the game. Locking the pointer enables this if the application 469 | creates their own cursor. However HTML and DOM should still be available 470 | to use for user interface. Synthetic mouse events should be permitted to 471 | allow an application defined cursor to interact with DOM. E.g. the 472 | following code should permit a custom cursor to send click events while 473 | the pointer is locked:

474 | 475 |
476 |             document.addEventListener("click", function (e) {
477 |               if (e._isSynthetic)
478 |                 return;
479 |               // send a synthetic click
480 |               var ee = document.createEvent("MouseEvents");
481 |               ee._isSynthetic = true;
482 |               x = myCursor.x;
483 |               y = myCursor.y;
484 |               ee.initMouseEvent("click", true, true, null, 1,
485 |                                 x + e.screenX - e.clientX,
486 |                                 y + e.screenY - e.clientY,
487 |                                 x,
488 |                                 y);
489 |               var target = document.elementFromPoint(x, y)
490 |               if (target)
491 |                 target.dispatchEvent(ee)
492 |             });
493 |         
494 | 495 |

Note that synthetic clicks may not be permitted by a user agent to 496 | produce the same default action as a non-synthetic click. However, 497 | application handlers can still take action and provide user interface with 498 | existing HTML & DOM mechanisms.

499 |
500 | 501 |
502 |

View-port panning by moving a mouse cursor against the bounds of a 503 | view-port.

504 | 505 |

Real Time Strategy games often use this technique. When the player 506 | moves the pointer to the view-port borders, if they "push" the border 507 | with a mouse movement, the view-port is panned over the game area 508 | according to how much they move the mouse. When moving the mouse cursor 509 | within the bounds of the view port it acts at is typically would on a 510 | system. Applications may choose to implement this using pointer lock and 511 | the previous use case of "Synthetic cursor interaction with HTML DOM UI" 512 | to bring cursor behavior completely under their control.

513 |
514 | 515 |
516 |

Game Lobby, timer based pointer lock

517 | 518 |

Games that use pointer lock may desire a traditional UI and system cursor 519 | while players prepare in a game lobby. Games usually start after a short 520 | timer when all players are ready. Ideally the game could then switch to 521 | pointer lock mode without requiring an engagement gesture. 522 | Players should be able 523 | to seamlessly move from the game lobby into game navigation.

524 |
525 | 526 |
527 |

Game Portal

528 | 529 |

Game portals, and other sites such as Facebook and Google Plus, host 530 | games for users to play. These games may be hosted and served from a 531 | different origin from that of the portal site. Embedded games should be 532 | able to lock the pointer, even in non-full screen mode.

533 |
534 | 535 |
536 | 537 |
538 |

Security

539 | 540 |

Security Concerns:

541 | 555 | 556 |

Responses:

557 | 578 | 579 |

Recommendations:

580 | 586 | 587 |

Pointer lock is a required user interaction mode for certain application 588 | types, but carries a usability concern if maliciously used. An attacker 589 | could remove the ability for a user to control their mouse cursor on their 590 | system. User agents will prevent this by always providing a mechanism to 591 | exit pointer lock, by informing the user of how, and by limiting how pointer 592 | lock can be entered.

593 | 594 |

User agents will determine their own appropriate policies, which may be 595 | specialized per device or differ based on user options. 596 |

597 | 598 |
599 |

Frequently Asked Questions

600 | 601 |
602 |

Why not merge with Mouse Capture: setCapture()?

603 | 604 |

Mouse Capture [[MDN-SETCAPTURE]] 605 | handles low security risk mouse event target lock for the duration of a 606 | mouse drag gesture. pointer lock removes the concept of the cursor and 607 | directs all events to a given target. They are related, but 608 | different.

609 | 610 |

If a browser implemented both, it would be reasonable to support a 611 | combination of traits: The security simplicity of "automatically release 612 | lock when mouse up" and the increased functionality of total control over 613 | mouse input and removal of the system cursor. The security trait would 614 | allow more permissive use of the feature for applications that only 615 | required a short burst of pointer lock during a drag event.

616 | 617 |

This functionality is omitted from the initial version of this spec 618 | because it helps the minor use cases in windowed mode but we still do not 619 | have an implementation solving the major ones. And, to implement this a 620 | browser must implement both, which none does yet. It is not clear if this 621 | feature should live on .lock or on .setCapture. If both were 622 | implemented, either API could be augmented fairly easily to offer the 623 | hybrid functionality.

624 |
625 | 626 |
627 |

Why not repurpose MouseEvent's .clientX/Y .screenX/Y?

628 | 629 |

Even in non locked state, the delta values of mouse movement are 630 | useful. Changing the meaning of .client or .screen based on lock state 631 | would also cause easy errors in code not carefully monitoring the lock 632 | state.

633 |
634 | 635 |
636 |

Why use .movementX/Y instead of .deltaX/Y?

637 | 638 |

When the pointer is locked 'wheel' events should be sent to the pointer 639 | lock target element just as 'mousemove' events are. There is a naming 640 | conflict with .deltaX/Y/Z as defined in DOM 642 | 3 'wheel' event.

643 |
644 | 645 |
646 |

Why bundle all functionality (hiding cursor, providing mouse deltas) 647 | instead of using CSS to hide the cursor, always providing delta values, 648 | and offering an API to restrict the cursor movement to a portion of the 649 | web page?

650 | 651 |

There are good motivations to provide a more fine grained approach. 652 | E.g. the use case "View-port panning by moving a mouse cursor against the 653 | bounds of a view-port" doesn't require hiding the mouse cursor, only 654 | bounding it and always having delta values available. Also, this 655 | specification defines the movement deltas to be taken from how the system 656 | mouse cursor moves, which incorporates operating system filtering and 657 | acceleration of the mouse movement data. Applications may desire access 658 | to a more raw form of movement data prior to adjustments appropriate for a 659 | mouse cursor. Also, raw data may provide better than pixel level accuracy 660 | for movement, as well as higher frequency updates. Providing the raw 661 | delta movement would also not require special permission or mode from a 662 | user, and for some set of applications that do not require bounding the 663 | cursor may reduce the security barriers and prompts needed.

664 | 665 |

There are two justifications for postponing this finer grained 666 | approach. The first is a concern of specifying what units mouse movement 667 | data are provided in. This specification defines .movementX/Y precisely 668 | as the same values that could be recorded when the mouse is not under lock 669 | by changes in .screenX/Y. Implementations across multiple user agents and 670 | operating systems will easily be able to meet that requirement and provide 671 | application developers and users with a consistent experience. Further, 672 | users are expected to have already configured the full system of hardware 673 | input and operating system options resulting in a comfortable control the 674 | system mouse cursor. By specifying .movementX/Y in the same units mouse 675 | lock API applications will be instantly usable to all users because they 676 | have already settled their preferences.

677 | 678 |

Secondly, the implementation of providing movement data and bounding 679 | the mouse cursor is more difficult in the fine grained approach. Bundling 680 | the features together gives implementations freedom to use a variety of 681 | techniques as appropriate on each operating system and is more practical 682 | to implement. Direct APIs do not exist on all platforms (Win, Mac, Linux) 683 | to bound the cursor to a specific rectangle, and prototypes have not yet 684 | been developed to demonstrate building that behavior by e.g. invisible 685 | windows with xlib or manual cursor movement on Mac. Unaccelerated Delta 686 | values have been proposed to be accessed by reading raw Human Interface 687 | Device (HID) data. E.g. WM_INPUT messages on windows, and USB device 688 | APIs on Mac / Linux. The challenge here is interpreting and normalizing 689 | the units to some consistent and specifiable scale. Also, most APIs 690 | considered to date are limited to USB devices.

691 | 692 |

It would be reasonable to consider adding these capabilities in the 693 | future, as the currently specified pointer lock API would be easy to 694 | continue to support if the finer grained delta and confinement features 695 | were implemented.

696 | 697 |

The bundled API is selected for implementation practicality, because 698 | the desired use cases are supported, and because it will not conflict with 699 | future improvements as discussed here.

700 |
701 | 702 |
703 |

High resolution deltas / High frequency updates?

704 | 705 |

Not yet, for the same reasons in the previous Q. See "Why bundle all 706 | functionality (hiding cursor, providing mouse deltas) instead of using CSS 707 | to hide the cursor, always providing delta values, and offering an API to 708 | restrict the cursor movement to a portion of the web page?" above.

709 |
710 | 711 |
712 |

Why modify MouseEvent and reuse existing mouse events instead of 713 | creating a mouse delta event?

714 | 715 |

When under pointer lock many mouse events remain relevant, e.g. click, 716 | mousedown, etc. These all share the same event data structure MouseEvent. 717 | If movement data were reported via a new data structure then a new event 718 | would be needed for reporting delta movement. The new data structure 719 | would have many parallels to MouseEvent to offer the same conveniences, 720 | e.g. button and modifier key states. When handling click, down, and up 721 | events would the existing mousedown, mouseup be used? If so, they would 722 | provide .clientX/Y and .screenX/Y with no useful data, but would lack the 723 | convenience of containing the current movement data. Or, new events would 724 | also be required for when the mouse is locked.

725 | 726 |

Also, movementX/Y are convenient even when the mouse is not locked. 727 | This spec requires movement members to always be valid, even when the 728 | mouse cursor exists. This reduces code required to track the last cursor 729 | state and mouseover/mouseout transitions if applications wish to make 730 | use of delta motion of the mouse.

731 | 732 |

The only negative of adding movementX/Y to MouseEvent appears to be the 733 | unused values in clientX/Y and screenX/Y when under pointer lock. This does 734 | not seem to be a significant problem.

735 | 736 |

Therefore the minimal change to add movementX/Y to MouseEvent is 737 | selected to reduce API and implementation complexity.

738 |
739 | 740 |
741 |

Why separate targets for mouse events under pointer lock and keyboard 742 | input focus?

743 | 744 |

Consider a game with a 3D view controlled by moving the mouse cursor, 745 | while the user may still chat with other users via a text console. It is 746 | reasonable for the application to accept text input to an element that is 747 | different than where mouse events are being dispatched. This is similar 748 | to pre-existing behavior of receiving mousemove events over any element 749 | while typing into a form on a page.

750 |
751 | 752 |
753 | 754 |
755 |

Acknowledgments

756 | 757 |

Many have made contributions to the discussions of this 758 | specification:

759 | 760 | 777 |
778 | 779 | 780 | -------------------------------------------------------------------------------- /publish/index-2016-07-05-CR.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Pointer Lock 5 | 6 | 7 | 12 | 13 | 99 | 100 | 110 | 111 | 112 |
113 | This specification defines an API that provides scripted access to raw 114 | mouse movement data while locking the target of mouse events to a single 115 | element and removing the cursor from view. This is an essential input 116 | mode for certain classes of applications, especially first person 117 | perspective 3D applications and 3D modeling software. 118 |
119 | 120 |
121 |

122 | A history of changes to this document can be found at 123 | 124 | http://dvcs.w3.org/hg/pointerlock/log/default/index.html 125 |

126 |

127 | Summary of changes: 128 |

152 | 153 |
154 | 155 |

Introduction

156 | 157 |

The Pointer Lock API provides for input methods of applications based on 158 | the movement of the mouse, not just the absolute position of a cursor. A 159 | popular example is that of first person movement controls in three 160 | dimensional graphics applications such as games. Movement of the mouse is 161 | interpreted for rotation of the view-port, there is no limit to how far 162 | movement can go, and no mouse cursor is displayed.

163 | 164 |

Pointer Lock is related to 165 | Mouse Capture [[MSDN-SETCAPTURE]] [[MDN-SETCAPTURE]] 166 | (Mouse Capture is unspecified: bug 167 | 14600). 168 | Capture provides 169 | continued event delivery to a target element while a mouse is being 170 | dragged, but ceases when the mouse button is released. Pointer Lock differs 171 | by being persistent, not limited by screen boundaries, sending events 172 | regardless of mouse button state, hiding the cursor, and not releasing 173 | until an API call or specific default unlock gesture by the user.

174 | 175 |

Pointer Lock deals with capturing a single resource and relating it to 176 | a single element. This is similar to the Fullscreen API [[FULLSCREEN]], which 177 | promotes a single element to be full screen. The Pointer Lock API chooses 178 | to pattern the resource capture, state change, and release API as closely 179 | as possible after the Fullscreen API.

180 | 181 |

The Pointer Lock interaction mode was previously referred to as 182 | mouse lock. The name was changed as many different controller types 183 | besides mice can manipulate the on screen pointing cursor, and they are 184 | all impacted.

185 | 186 |
187 | 188 |
189 |

190 | This specification defines conformance criteria that apply to a single 191 | product: the user agent that implements 192 | the interfaces that it contains. 193 |

194 | 195 |

196 | Implementations that use ECMAScript to implement the APIs defined in 197 | this specification MUST implement them in a manner consistent with the 198 | ECMAScript Bindings defined in the Web IDL specification [[!WEBIDL]] as 199 | this specification uses that specification and terminology. 200 |

201 | 202 |

203 | A conforming implementation is required to implement all fields 204 | defined in this specification. 205 |

206 |
207 | 208 |
209 |

Glossary

210 | 211 |
Engagement gesture
212 |
213 | An event generated by the user agent as a result of user interaction 214 | processed by the user agent to interact with the page. e.g. click, but not 215 | mousemove. 216 | Engagement gestures are any events included in the definition of being 217 | 218 | allowed to show a popup 219 | with the addition of keypress and keyup. 220 | Note that operating system level accessibility and internationalization 221 | features may intercept gestures before the user agent processes them 222 | for interaction with a page. E.g. multiple key press codes used to enter 223 | an extended international character. 224 |
225 | 226 | 227 |
228 | 229 |
230 |

pointerlockchange and pointerlockerror Events

231 | 232 |

Two events are used to communicate pointer lock state change or 233 | an error in changing state. They are named pointerlockchange 234 | and pointerlockerror. If pointer lock is entered or exited 235 | for any reason a pointerlockchange event must be sent.

236 | 237 |

User agents 238 | must deliver these events by 240 | queuing a task to 242 | fire an event of the appropriate name with its 243 | bubbles attribute [[!DOM4]] 244 | set to false to the pointer lock 245 | target element's 247 | node document.

248 | 249 |

Magnification software increases the size of content on 250 | the screen. It uses the mouse to move the magnified point of focus 251 | around. When a pointer lock is initiated, the magnification software 252 | needs to switch to using the keyboard to move the magnified point of 253 | focus around instead. When a pointerlockchange event is fired, web 254 | browsers therefore need to make sure the event is communicated to 255 | assistive technologies like screen magnifiers.

256 |
257 | 258 |
259 |

Extensions to the Element Interface

260 |

261 | The Element interface is extended to provide the ability to 262 | request the the pointer be locked. 263 |

264 | 265 |
266 |
void requestPointerLock()
267 |
268 | 269 | 270 |

Requests that the pointer be locked to a DOM element 271 | target. The user agent determines if pointer lock 272 | state will be entered and upon lock state change or error must send 273 | either a pointerlockchange or pointerlockerror 274 | event respectively. 275 | 276 |

Pointer lock must succeed only if the document object's 277 | 278 | active sandboxing flag set does not have the 279 | sandboxed pointer lock browsing context flag set. 280 | 281 |

Pointer lock must succeed only if the target is 282 | in 283 | the 284 | active document 285 | of a 286 | browsing context 287 | which is (or has an 288 | ancestor browsing context 289 | which is) in focus by a window which is in focus by the 290 | operating system's window manager. The target element and its 291 | browsing context 292 | need not be in focus.

293 | 294 |

If a user has exited pointer lock via the default unlock user 295 | gesture, or pointer lock has not previously been entered for this 296 | document, an event generated as a result of an 297 | engagement gesture must be received by the document before 298 | requestPointerLock will succeed.

299 | 300 |

301 | This ensures a user can leave a 302 | document that constantly attempts to lock the pointer. The document 303 | will be blocked from locking upon initial navigation or re-acquiring 304 | lock unless the user re-engages directly with the document.

305 | 306 | Conversely, if pointer lock is exited via exitPointerLock 307 | no engagement gesture is required to reenter pointer lock. This enables 308 | applications that frequently move between interaction modes, and 309 | ones that may do so based on a timer or remote network activity. 310 |

311 | 312 | Pointer lock is commonly combined with fullscreen [[FULLSCREEN]], and 313 | if an engagement gesture is used to enter fullscreen it is sufficient 314 | for a subsequent requestPointerLock. 315 |

316 | 317 |

If any element (including this one) in the same document 318 | is already locked (or pending lock) the pointer 319 | lock target must be updated to this element and a 320 | pointerlockchange event sent.

321 | 322 |

If any element in another document is already locked the request 323 | must fail and a pointerlockerror event be sent.

324 | 325 |

Once in the locked state the user agent must fire all relevant 326 | user generated MouseEvent events (for example: 327 | mousemove, mousedown, mouseup, 328 | click, and wheel)[[!UIEVENTS]] 329 | to the target of pointer lock, and not fire mouse events to 330 | other elements. Events that require the concept of a mouse cursor must 331 | not be dispatched (for example: mouseover, 332 | mouseout, drag, and drop).

333 | 334 |

In the locked state the system mouse cursor 335 | must be hidden. Movement and button presses of the mouse must not 336 | cause the window to lose focus.

337 | 338 |

Synthetic mouse events created by application script act the same 339 | regardless of lock state.

340 |

341 |
342 |
343 | 344 |
345 |

Extensions to the Document Interface

346 | 347 |
348 |
attribute EventHandler onpointerlockchange
349 |
350 | 351 | 352 |

An event handler 353 | for pointerlockchange events.

354 |
355 | 356 |
attribute EventHandler onpointerlockerror
357 |
358 | 359 | 360 |

An event handler 361 | for pointerlockerror events.

362 |
363 | 364 |
readonly attribute Element? pointerLockElement
365 |
366 | 367 | 368 |

Returns the element set as the target for mouse events 369 | while the pointer is locked. Null if lock is pending, pointer is 370 | unlocked, or if the target is in another document.

371 |
372 | 373 |
void exitPointerLock ()
374 |
375 | 376 | 377 |

Initiates an exit from pointer lock state if currently locked 378 | to a target in this document, 379 | and sends a pointerlockchange event when the lock state 380 | has been exited.

381 | 382 |

The system mouse cursor must be displayed again and positioned at 383 | the same location that it was when pointer lock was entered (the same 384 | location that is reported in screenX, screenY, 385 | when the pointer is locked).

386 |
387 |
388 |
389 | 390 |
391 |

Extensions to the MouseEvent Interface

392 | 393 |

User agents must extend the MouseEvent interface 394 | [[!UIEVENTS]] 395 | with two members:

396 | 397 |
398 |
readonly attribute long movementX
399 |
400 |
readonly attribute long movementY
401 |
402 |
403 | 404 |

The members movementX and movementY must 405 | provide the change in position of the pointer, as if the values of 406 | screenX, screenY, were stored between two subsequent 407 | mousemove events eNow and 408 | ePrevious and the difference taken 409 | movementX = eNow.screenX-ePrevious.screenX.

410 | 411 |

movementX/Y must be zero for all mouse events 412 | except mousemove. All motion data must be delivered via 413 | mousemove events such that between any two mouse events 414 | earlierEvent and currentEvent the value of 415 | currentEvent.screenX-earlierEvent.screenX is equivalent to 416 | the sum of all movementX values received on 417 | mousemove events after earlierEvent, with 418 | the exception of when screenX can not be updated because the pointer 419 | is clipped by the user agent screen boundaries.

420 | 421 |

movementX/Y must be updated regardless of pointer 422 | lock state.

423 | 424 |

When unlocked, the system cursor can exit and re-enter the user 425 | agent window. If it does so and the user agent was not the 426 | target of operating system mouse move events then the most recent pointer 427 | position will be unknown to the user agent and 428 | movementX/Y can not be computed and must be set 429 | to zero.

430 | 431 |

When pointer lock is enabled clientX, clientY, 432 | screenX, and screenY must hold constant values 433 | as if the pointer did not move at all once pointer lock was entered. But 434 | movementX/Y must continue to provide the change 435 | in position of the pointer as when the pointer is unlocked. There will be no 436 | limit to movementX/Y values if the mouse is 437 | continuously moved in a single direction. The concept of the mouse cursor 438 | will have been removed, and it will not move off the window or be clamped 439 | by a screen edge.

440 | 441 |

The un-initialized value of movementX/Y must 442 | be 0.

443 |
444 | 445 |
446 |

Extensions to the MouseEventInit Dictionary

447 | 448 |

User agents must extend the MouseEventInit dictionary 449 | [[!UIEVENTS]] with two members movementX and 450 | movementY used to initialize respective members 451 | of MouseEvent.

452 | 453 |
454 |
long movementX = 0
455 |
456 |
long movementY = 0
457 |
458 |
459 |
460 | 461 |
462 |

Requirements

463 | 464 |

A default unlock gesture must always be available that 465 | will exit pointer lock.

466 |

The ESC key is the recommended default unlock 467 | gesture for user agents with keyboard input. It is recommended that 468 | the unlock gesture also match any used to exit fullscreen 469 | [[FULLSCREEN]].

470 | 471 |

Pointer lock must be exited if the 472 | target is removed from its document, or the user agent, 473 | window, or tab loses focus. Moving focus between elements of 474 | active documents, 475 | including between 476 | browsing contexts, 477 | does not exit pointer lock. E.g. using the keyboard 478 | to move focus between contents of frames or iframes will not exit.

479 | 480 |

Pointer lock must not be exited when fullscreen [[FULLSCREEN]] is 481 | entered or exited unless the pointer is required to enable interaction 482 | with the user agent graphical user interface, the default 483 | unlock gesture was used to exit both fullscreen and pointer 484 | lock, or window or tab focus was lost.

485 |
486 | 487 |
488 |

Use Cases

489 | 490 |
491 |

Relative view-port rotation of free moving virtual actors

492 | 493 |

A player on a first/third person game will need to control the 494 | view-port orientation. A widely used method is the use of mouse movements 495 | to control the viewing angle. This kind of application can use the Pointer 496 | Lock API to allow a complete freedom of control over the viewport's yaw 497 | and pitch even when the user is not pressing mouse buttons. Those buttons 498 | can be used for other actions while constantly providing navigation via 499 | mouse movement.

500 |
501 | 502 |
503 |

Free rotation of 3D models or panning of 2D layers

504 | 505 |

Users of a three dimensional modeling application will need to rotate 506 | models. A application can use the Pointer Lock API to enable the author to 507 | rotate the model freely in a drag operation without limiting motion. 508 | Without pointer lock a drag would stop providing motion data when the mouse 509 | cursor is limited by the edge of the screen.

510 | 511 |

Similarly, absolute motion panning of a large two dimensional image 512 | could be permitted in a single drag operation without cursor / screen 513 | limits.

514 |
515 | 516 |
517 |

Relative movement of actors

518 | 519 |

A player on a fast reflexes game controls a paddle to bounce back a 520 | ball to the opponent, while allowing the same paddle to execute actions 521 | based on different mouse buttons being pressed. The application can use 522 | the Pointer Lock API to allow the player to react quickly without being 523 | concerned about the mouse cursor leaving the game play area and clicking 524 | another system application, thus breaking the game flow.

525 |
526 | 527 |
528 |

Jog movement over spinner controls

529 | 530 |

When modifying numerically magnitudes in applications sometimes the 531 | user will prefer to "drag" a numeric control by its button handles to 532 | increment or decrement the numeric value. E.g. a spinner with a 533 | number entry text box and arrows pointing up and down that can be 534 | clicked or dragged on to change the value. An 535 | application could use the Pointer Lock API to allow modifying the numeric 536 | values beyond what the logical screen bounds allow. The same could apply 537 | for a control that fast forwards or rewinds a video or audio stream like a 538 | "jog".

539 |
540 | 541 |
542 |

Synthetic cursor interaction with HTML DOM UI

543 | 544 |

Some games use a classical cursor, however they want it to be limited 545 | or controlled in some manner. E.g. limited to the bounds of the game, or 546 | movable by the game. Locking the pointer enables this if the application 547 | creates their own cursor. However HTML and DOM should still be available 548 | to use for user interface. Synthetic mouse events should be permitted to 549 | allow an application defined cursor to interact with DOM. E.g. the 550 | following code should permit a custom cursor to send click events while 551 | the pointer is locked:

552 | 553 |
554 |             document.addEventListener("click", function (e) {
555 |               if (e._isSynthetic)
556 |                 return;
557 |               // send a synthetic click
558 |               var ee = document.createEvent("MouseEvents");
559 |               ee._isSynthetic = true;
560 |               x = myCursor.x;
561 |               y = myCursor.y;
562 |               ee.initMouseEvent("click", true, true, null, 1,
563 |                                 x + e.screenX - e.clientX,
564 |                                 y + e.screenY - e.clientY,
565 |                                 x,
566 |                                 y);
567 |               var target = document.elementFromPoint(x, y);
568 |               if (target)
569 |                 target.dispatchEvent(ee);
570 |             });
571 |         
572 | 573 |

Note that synthetic clicks may not be permitted by a user agent to 574 | produce the same default action as a non-synthetic click. However, 575 | application handlers can still take action and provide user interface with 576 | existing HTML & DOM mechanisms.

577 |
578 | 579 |
580 |

View-port panning by moving a mouse cursor against the bounds of a 581 | view-port.

582 | 583 |

Real Time Strategy games often use this technique. When the player 584 | moves the pointer to the view-port borders, if they "push" the border 585 | with a mouse movement, the view-port is panned over the game area 586 | according to how much they move the mouse. When moving the mouse cursor 587 | within the bounds of the view port it acts at is typically would on a 588 | system. Applications may choose to implement this using pointer lock and 589 | the previous use case of "Synthetic cursor interaction with HTML DOM UI" 590 | to bring cursor behavior completely under their control.

591 |
592 | 593 |
594 |

Game Lobby, timer based pointer lock

595 | 596 |

Games that use pointer lock may desire a traditional UI and system cursor 597 | while players prepare in a game lobby. Games usually start after a short 598 | timer when all players are ready. Ideally the game could then switch to 599 | pointer lock mode without requiring an engagement gesture. 600 | Players should be able 601 | to seamlessly move from the game lobby into game navigation.

602 |
603 | 604 |
605 |

Game Portal

606 | 607 |

Game portals, and other sites such as Facebook and Google Plus, host 608 | games for users to play. These games may be hosted and served from a 609 | different origin from that of the portal site. Embedded games should be 610 | able to lock the pointer, even in non-full screen mode.

611 |
612 | 613 |
614 | 615 |
616 |

Security

617 | 618 |

Security Concerns:

619 | 633 | 634 |

Responses:

635 | 656 | 657 |

Recommendations:

658 | 664 | 665 |

Pointer lock is a required user interaction mode for certain application 666 | types, but carries a usability concern if maliciously used. An attacker 667 | could remove the ability for a user to control their mouse cursor on their 668 | system. User agents will prevent this by always providing a mechanism to 669 | exit pointer lock, by informing the user of how, and by limiting how pointer 670 | lock can be entered.

671 | 672 |

User agents will determine their own appropriate policies, which may be 673 | specialized per device or differ based on user options. 674 |

675 | 676 |
677 |

Frequently Asked Questions

678 | 679 |
680 |

Why not merge with Mouse Capture: setCapture()?

681 | 682 |

Mouse Capture [[MDN-SETCAPTURE]] 683 | handles low security risk mouse event target lock for the duration of a 684 | mouse drag gesture. Pointer lock removes the concept of the cursor and 685 | directs all events to a given target. They are related, but 686 | different.

687 | 688 |

If a browser implemented both, it would be reasonable to support a 689 | combination of traits: The security simplicity of "automatically release 690 | lock when mouse up" and the increased functionality of total control over 691 | mouse input and removal of the system cursor. The security trait would 692 | allow more permissive use of the feature for applications that only 693 | required a short burst of pointer lock during a drag event.

694 | 695 |

This functionality is omitted from the initial version of this spec 696 | because it helps the minor use cases in windowed mode but we still do not 697 | have an implementation solving the major ones. And, to implement this a 698 | browser must implement both, which none does yet. It is not clear if this 699 | feature should live on .lock or on .setCapture. If both were 700 | implemented, either API could be augmented fairly easily to offer the 701 | hybrid functionality.

702 |
703 | 704 |
705 |

Why not repurpose MouseEvent's .clientX/Y .screenX/Y?

706 | 707 |

Even in non locked state, the delta values of mouse movement are 708 | useful. Changing the meaning of .client or .screen based on lock state 709 | would also cause easy errors in code not carefully monitoring the lock 710 | state.

711 |
712 | 713 |
714 |

Why use .movementX/Y instead of .deltaX/Y?

715 | 716 |

When the pointer is locked 'wheel' events should be sent to the pointer 717 | lock target element just as 'mousemove' events are. There is a naming 718 | conflict with .deltaX/Y/Z as defined in DOM 720 | 3 'wheel' event.

721 |
722 | 723 |
724 |

Why bundle all functionality (hiding cursor, providing mouse deltas) 725 | instead of using CSS to hide the cursor, always providing delta values, 726 | and offering an API to restrict the cursor movement to a portion of the 727 | web page?

728 | 729 |

There are good motivations to provide a more fine grained approach. 730 | E.g. the use case "View-port panning by moving a mouse cursor against the 731 | bounds of a view-port" doesn't require hiding the mouse cursor, only 732 | bounding it and always having delta values available. Also, this 733 | specification defines the movement deltas to be taken from how the system 734 | mouse cursor moves, which incorporates operating system filtering and 735 | acceleration of the mouse movement data. Applications may desire access 736 | to a more raw form of movement data prior to adjustments appropriate for a 737 | mouse cursor. Also, raw data may provide better than pixel level accuracy 738 | for movement, as well as higher frequency updates. Providing the raw 739 | delta movement would also not require special permission or mode from a 740 | user, and for some set of applications that do not require bounding the 741 | cursor may reduce the security barriers and prompts needed.

742 | 743 |

There are two justifications for postponing this finer grained 744 | approach. The first is a concern of specifying what units mouse movement 745 | data are provided in. This specification defines .movementX/Y precisely 746 | as the same values that could be recorded when the mouse is not under lock 747 | by changes in .screenX/Y. Implementations across multiple user agents and 748 | operating systems will easily be able to meet that requirement and provide 749 | application developers and users with a consistent experience. Further, 750 | users are expected to have already configured the full system of hardware 751 | input and operating system options resulting in a comfortable control the 752 | system mouse cursor. By specifying .movementX/Y in the same units mouse 753 | lock API applications will be instantly usable to all users because they 754 | have already settled their preferences.

755 | 756 |

Secondly, the implementation of providing movement data and bounding 757 | the mouse cursor is more difficult in the fine grained approach. Bundling 758 | the features together gives implementations freedom to use a variety of 759 | techniques as appropriate on each operating system and is more practical 760 | to implement. Direct APIs do not exist on major desktop platforms 761 | (Windows, Mac OS X, Linux) 762 | to bound the cursor to a specific rectangle, and prototypes have not yet 763 | been developed to demonstrate building that behavior by e.g. 764 | 765 | invisible windows 766 | with Xlib 767 | or manual cursor movement on Mac. Unaccelerated Delta 768 | values have been proposed to be accessed by reading raw Human Interface 769 | Device (HID) data. E.g. WM_INPUT messages on Windows, and USB device 770 | APIs on Mac OS X / Linux. The challenge here is interpreting and normalizing 771 | the units to some consistent and specifiable scale. Also, most APIs 772 | considered to date are limited to USB devices.

773 | 774 |

It would be reasonable to consider adding these capabilities in the 775 | future, as the currently specified pointer lock API would be easy to 776 | continue to support if the finer grained delta and confinement features 777 | were implemented.

778 | 779 |

The bundled API is selected for implementation practicality, because 780 | the desired use cases are supported, and because it will not conflict with 781 | future improvements as discussed here.

782 |
783 | 784 |
785 |

High resolution deltas / High frequency updates?

786 | 787 |

Not yet, for the same reasons in the previous question: 788 | "Why bundle all 789 | functionality (hiding cursor, providing mouse deltas) instead of using CSS 790 | to hide the cursor, always providing delta values, and offering an API to 791 | restrict the cursor movement to a portion of the web page?".

792 |
793 | 794 |
795 |

Why modify MouseEvent and reuse existing mouse events instead of 796 | creating a mouse delta event?

797 | 798 |

When under pointer lock many mouse events remain relevant, e.g. click, 799 | mousedown, etc. These all share the same event data structure MouseEvent. 800 | If movement data were reported via a new data structure then a new event 801 | would be needed for reporting delta movement. The new data structure 802 | would have many parallels to MouseEvent to offer the same conveniences, 803 | e.g. button and modifier key states. When handling click, down, and up 804 | events would the existing mousedown, mouseup be used? If so, they would 805 | provide .clientX/Y and .screenX/Y with no useful data, but would lack the 806 | convenience of containing the current movement data. Or, new events would 807 | also be required for when the mouse is locked.

808 | 809 |

Also, movementX/Y are convenient even when the mouse is not locked. 810 | This spec requires movement members to always be valid, even when the 811 | mouse cursor exists. This reduces code required to track the last cursor 812 | state and mouseover/mouseout transitions if applications wish to make 813 | use of delta motion of the mouse.

814 | 815 |

The only negative of adding movementX/Y to MouseEvent appears to be the 816 | unused values in clientX/Y and screenX/Y when under pointer lock. This does 817 | not seem to be a significant problem.

818 | 819 |

Therefore the minimal change to add movementX/Y to MouseEvent is 820 | selected to reduce API and implementation complexity.

821 |
822 | 823 |
824 |

Why separate targets for mouse events under pointer lock and keyboard 825 | input focus?

826 | 827 |

Consider a game with a 3D view controlled by moving the mouse cursor, 828 | while the user may still chat with other users via a text console. It is 829 | reasonable for the application to accept text input to an element that is 830 | different than where mouse events are being dispatched. This is similar 831 | to pre-existing behavior of receiving mousemove events over any element 832 | while typing into a form on a page.

833 |
834 | 835 |
836 | 837 |
838 |

Acknowledgments

839 | 840 |

Many have made contributions to the discussions of this 841 | specification:

842 | 843 | 865 |
866 | 867 | 868 | -------------------------------------------------------------------------------- /tests/movementX_Y_basic-manual.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 15 | 16 | 17 |

Description

18 |

This test if movementX/Y can provide the change in position of the pointer, as if movementX/Y = eNow.screenX/Y-ePrevious.screenX/Y

19 |
20 | 21 |

Manual Test Steps:

22 |

23 |

    24 |
  1. Click to start Test1.
  2. 25 |
  3. Move the mouse within the window, slow and fast, like a scribble.
  4. 26 |
  5. Click again to end test.
  6. 27 |
28 |

29 |
30 | 31 |
Waiting... Click to start loging.
32 |
33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
XY
client_init:XY
client_last:XY
client_delta:XY
movement_sum:XY
movement:XY
41 |
42 |
43 | 44 |
45 | 46 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /tests/movementX_Y_no-jumps-manual.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 15 | 16 | 17 |

Description

18 |

This test that movementX/Y do not jump by a large value when exiting and re-entering the window.

19 |
20 | 21 |

Manual Test Steps:

22 |

23 |

    24 |
  1. Make sure the window is not maximized.
  2. 25 |
  3. Click to start Test.
  4. 26 |
  5. Move the mouse slowly out of the window. 27 |
  6. Move as fast as needed to a different location outside the window at least 100 pixels away
  7. 28 |
  8. Slowly re-enter the window.
  9. 29 |
  10. Click again to end tests.
  11. 30 |
31 |

32 |
33 | 34 |
Waiting... Click to start loging.
35 |
36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 |
XY
client_init:XY
client_last:XY
client_delta:XY
movement_sum:XY
movement:XY
44 |
45 |
46 | 47 |
48 | 49 | 140 | 141 | 142 | -------------------------------------------------------------------------------- /tests/pointerlock_basic-manual.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 27 | 28 | 29 |

Description

30 |

This test validates that the pointer properly be locked in a DOM element, and exit afterwards.

31 |
32 | 33 |

Manual Test Steps:

34 |

35 |

    36 |
  1. Click the "Lock Target" to test if requestPointerLock() and exitPointerLock() causing a pointerlockchange event.
  2. 37 |
  3. Confirm the lock with a user action (in Firefox).
  4. 38 |
  5. Exit the pointer lock with a user action (usually 'esc'), to test if the cursor is at the same location.
  6. 39 |
  7. Click the "ReEnterLock" to test that no engagement gesture is required to reenter pointer lock if pointer lock is exited via exitPointerLock.
  8. 40 |
  9. Exit the pointer lock with a user action (usually 'esc').
  10. 41 |
  11. Click the "RepeatLock" to validate that each requestPointerLock() will fire a pointerlockchange event.
  12. 42 |
  13. Exit the pointer lock with a user action (usually 'esc').
  14. 43 |
44 |

45 |
46 | 47 | 48 | 49 | 50 |
Waiting... Please click the "Lock Target" button.
51 |
Target
52 |
53 | 54 |
55 | 56 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /tests/pointerlock_fullscreen-manual.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 34 | 35 | 36 |

Description

37 |

This test validates that pointer lock won't be exited when fullscreen is entered or exited, unless fullscreen is exited with the same user gesture as pointer lock.

38 |
39 | 40 |

Manual Test Steps:

41 |

42 |

    43 |
  1. Click the "scriptExitFullscreen" button.
  2. 44 |
  3. If the exitFullscreen doesn't work, use the menu (or any other interaction except for the "esc" key) to exit fullscreen.
  4. 45 |
  5. First test case done.
  6. 46 |
  7. Click the "gestureExitFullscreen" button.
  8. 47 |
  9. Use the "esc" key to exit fullscreen.
  10. 48 |
  11. Second test case done.
  12. 49 |
50 |

51 |
52 | 53 | 54 | 55 | 56 |
57 |
Waiting... Please click the "scriptExitFullscreen" button.
58 |
Target
59 |
60 |
61 | 62 |
63 | 64 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /tests/pointerlock_indefinite-manual.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 25 | 26 | 27 |

Description

28 |

This test validates that movementX/Y provided indefinitely even when the mouse cursor would have otherwise hit the edge of a screen.

29 |
30 | 31 |

Manual Test Steps:

32 |

33 |

    34 |
  1. Click the "lockTarget" button to request a pointer lock.
  2. 35 |
  3. Move the pointer constantly in a diagonal direction (e.g. up and right).
  4. 36 |
  5. Test is done.
  6. 37 |
38 |

39 |
40 | 41 | 42 | 43 |
44 |
Click the "lockTarget" button.
45 |

screenSize: NaN

46 |

movementX_sum: NaN

47 |

movementY_sum: NaN

48 |
49 |
50 | 51 |
52 | 53 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /tests/pointerlock_leave_Tab-manual.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 34 | 35 | 36 |

Description

37 |

This test validates that pointer lock will be lost the user agent / window loses focus.

38 |
39 | 40 |

Manual Test Steps:

41 |

42 |

    43 |
  1. Click the "lockTarget" button to request a pointer lock.
  2. 44 |
  3. Focus to another tab with keyboard (Ctrl-TAB).
  4. 45 |
  5. Test is done.
  6. 46 |
47 |

48 |
49 | 50 | 51 | 52 |
53 |
Click the "lockTarget" button.
54 |
Target
55 |
56 |
57 | 58 |
59 | 60 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /tests/pointerlock_leave_UA-manual.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 34 | 35 | 36 |

Description

37 |

This test validates that pointer lock will be lost the user agent / window loses focus.

38 |
39 | 40 |

Manual Test Steps:

41 |

42 |

    43 |
  1. Click the "lockTarget" button to request a pointer lock.
  2. 44 |
  3. Focus to another window with keyboard (ALT-TAB).
  4. 45 |
  5. Test is done.
  6. 46 |
47 |

48 |
49 | 50 | 51 | 52 |
53 |
Click the "lockTarget" button.
54 |
Target
55 |
56 |
57 | 58 |
59 | 60 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /tests/pointerlock_remove_target-manual.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 34 | 35 | 36 |

Description

37 |

This test validates that pointer lock will be lost when the target is disconnected.

38 |
39 | 40 |

Manual Test Steps:

41 |

42 |

    43 |
  1. Click the "lockTarget" button to request a pointer lock.
  2. 44 |
  3. Test is done.
  4. 45 |
46 |

47 |
48 | 49 | 50 | 51 |
52 |
Click the "lockTarget" button.
53 |
Target
54 |
55 |
56 | 57 |
58 | 59 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /tests/resources/LICENSE: -------------------------------------------------------------------------------- 1 | W3C 3-clause BSD License 2 | 3 | http://www.w3.org/Consortium/Legal/2008/03-bsd-license.html 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * Redistributions of works must retain the original copyright notice, 10 | this list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the original copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the W3C nor the names of its contributors may be 17 | used to endorse or promote products derived from this work without 18 | specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /tests/resources/readme.md: -------------------------------------------------------------------------------- 1 | ## Introdution ## 2 | 3 | testharness.js provides a framework for writing low-level tests of 4 | browser functionality in javascript. It provides a convenient API for 5 | making assertions and is intended to work for both simple synchronous 6 | tests and for tests of asynchronous behaviour. 7 | 8 | ## Getting Started ## 9 | 10 | To use testharness.js you must include two scripts, in the order given: 11 | 12 | ``` html 13 | 14 | 15 | ``` 16 | 17 | ## Full documentation ## 18 | 19 | Full user documentation for the API is in the 20 | [docs/api.md](https://github.com/w3c/testharness.js/blob/master/docs/api.md) file. 21 | 22 | You can also read a tutorial on 23 | [Using testharness.js](http://darobin.github.com/test-harness-tutorial/docs/using-testharness.html). 24 | -------------------------------------------------------------------------------- /tests/resources/testharness.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-family:DejaVu Sans, Bitstream Vera Sans, Arial, Sans; 3 | } 4 | 5 | #log .warning, 6 | #log .warning a { 7 | color: black; 8 | background: yellow; 9 | } 10 | 11 | #log .error, 12 | #log .error a { 13 | color: white; 14 | background: red; 15 | } 16 | 17 | section#summary { 18 | margin-bottom:1em; 19 | } 20 | 21 | table#results { 22 | border-collapse:collapse; 23 | table-layout:fixed; 24 | width:100%; 25 | } 26 | 27 | table#results th:first-child, 28 | table#results td:first-child { 29 | width:4em; 30 | } 31 | 32 | table#results th:last-child, 33 | table#results td:last-child { 34 | width:50%; 35 | } 36 | 37 | table#results.assertions th:last-child, 38 | table#results.assertions td:last-child { 39 | width:35%; 40 | } 41 | 42 | table#results th { 43 | padding:0; 44 | padding-bottom:0.5em; 45 | border-bottom:medium solid black; 46 | } 47 | 48 | table#results td { 49 | padding:1em; 50 | padding-bottom:0.5em; 51 | border-bottom:thin solid black; 52 | } 53 | 54 | tr.pass > td:first-child { 55 | color:green; 56 | } 57 | 58 | tr.fail > td:first-child { 59 | color:red; 60 | } 61 | 62 | tr.timeout > td:first-child { 63 | color:red; 64 | } 65 | 66 | tr.notrun > td:first-child { 67 | color:blue; 68 | } 69 | 70 | .pass > td:first-child, .fail > td:first-child, .timeout > td:first-child, .notrun > td:first-child { 71 | font-variant:small-caps; 72 | } 73 | 74 | table#results span { 75 | display:block; 76 | } 77 | 78 | table#results span.expected { 79 | font-family:DejaVu Sans Mono, Bitstream Vera Sans Mono, Monospace; 80 | white-space:pre; 81 | } 82 | 83 | table#results span.actual { 84 | font-family:DejaVu Sans Mono, Bitstream Vera Sans Mono, Monospace; 85 | white-space:pre; 86 | } 87 | 88 | span.ok { 89 | color:green; 90 | } 91 | 92 | tr.error { 93 | color:red; 94 | } 95 | 96 | span.timeout { 97 | color:red; 98 | } 99 | 100 | span.ok, span.timeout, span.error { 101 | font-variant:small-caps; 102 | } -------------------------------------------------------------------------------- /tests/resources/testharnessreport.js: -------------------------------------------------------------------------------- 1 | /*global add_completion_callback, setup */ 2 | /* 3 | * This file is intended for vendors to implement 4 | * code needed to integrate testharness.js tests with their own test systems. 5 | * 6 | * The default implementation extracts metadata from the tests and validates 7 | * it against the cached version that should be present in the test source 8 | * file. If the cache is not found or is out of sync, source code suitable for 9 | * caching the metadata is optionally generated. 10 | * 11 | * The cached metadata is present for extraction by test processing tools that 12 | * are unable to execute javascript. 13 | * 14 | * Metadata is attached to tests via the properties parameter in the test 15 | * constructor. See testharness.js for details. 16 | * 17 | * Typically test system integration will attach callbacks when each test has 18 | * run, using add_result_callback(callback(test)), or when the whole test file 19 | * has completed, using 20 | * add_completion_callback(callback(tests, harness_status)). 21 | * 22 | * For more documentation about the callback functions and the 23 | * parameters they are called with see testharness.js 24 | */ 25 | 26 | 27 | 28 | var metadata_generator = { 29 | 30 | currentMetadata: {}, 31 | cachedMetadata: false, 32 | metadataProperties: ['help', 'assert', 'author'], 33 | 34 | error: function(message) { 35 | var messageElement = document.createElement('p'); 36 | messageElement.setAttribute('class', 'error'); 37 | this.appendText(messageElement, message); 38 | 39 | var summary = document.getElementById('summary'); 40 | if (summary) { 41 | summary.parentNode.insertBefore(messageElement, summary); 42 | } 43 | else { 44 | document.body.appendChild(messageElement); 45 | } 46 | }, 47 | 48 | /** 49 | * Ensure property value has contact information 50 | */ 51 | validateContact: function(test, propertyName) { 52 | var result = true; 53 | var value = test.properties[propertyName]; 54 | var values = Array.isArray(value) ? value : [value]; 55 | for (var index = 0; index < values.length; index++) { 56 | value = values[index]; 57 | var re = /(\S+)(\s*)<(.*)>(.*)/; 58 | if (! re.test(value)) { 59 | re = /(\S+)(\s+)(http[s]?:\/\/)(.*)/; 60 | if (! re.test(value)) { 61 | this.error('Metadata property "' + propertyName + 62 | '" for test: "' + test.name + 63 | '" must have name and contact information ' + 64 | '("name " or "name http(s)://")'); 65 | result = false; 66 | } 67 | } 68 | } 69 | return result; 70 | }, 71 | 72 | /** 73 | * Extract metadata from test object 74 | */ 75 | extractFromTest: function(test) { 76 | var testMetadata = {}; 77 | // filter out metadata from other properties in test 78 | for (var metaIndex = 0; metaIndex < this.metadataProperties.length; 79 | metaIndex++) { 80 | var meta = this.metadataProperties[metaIndex]; 81 | if (test.properties.hasOwnProperty(meta)) { 82 | if ('author' == meta) { 83 | this.validateContact(test, meta); 84 | } 85 | testMetadata[meta] = test.properties[meta]; 86 | } 87 | } 88 | return testMetadata; 89 | }, 90 | 91 | /** 92 | * Compare cached metadata to extracted metadata 93 | */ 94 | validateCache: function() { 95 | for (var testName in this.currentMetadata) { 96 | if (! this.cachedMetadata.hasOwnProperty(testName)) { 97 | return false; 98 | } 99 | var testMetadata = this.currentMetadata[testName]; 100 | var cachedTestMetadata = this.cachedMetadata[testName]; 101 | delete this.cachedMetadata[testName]; 102 | 103 | for (var metaIndex = 0; metaIndex < this.metadataProperties.length; 104 | metaIndex++) { 105 | var meta = this.metadataProperties[metaIndex]; 106 | if (cachedTestMetadata.hasOwnProperty(meta) && 107 | testMetadata.hasOwnProperty(meta)) { 108 | if (Array.isArray(cachedTestMetadata[meta])) { 109 | if (! Array.isArray(testMetadata[meta])) { 110 | return false; 111 | } 112 | if (cachedTestMetadata[meta].length == 113 | testMetadata[meta].length) { 114 | for (var index = 0; 115 | index < cachedTestMetadata[meta].length; 116 | index++) { 117 | if (cachedTestMetadata[meta][index] != 118 | testMetadata[meta][index]) { 119 | return false; 120 | } 121 | } 122 | } 123 | else { 124 | return false; 125 | } 126 | } 127 | else { 128 | if (Array.isArray(testMetadata[meta])) { 129 | return false; 130 | } 131 | if (cachedTestMetadata[meta] != testMetadata[meta]) { 132 | return false; 133 | } 134 | } 135 | } 136 | else if (cachedTestMetadata.hasOwnProperty(meta) || 137 | testMetadata.hasOwnProperty(meta)) { 138 | return false; 139 | } 140 | } 141 | } 142 | for (var testName in this.cachedMetadata) { 143 | return false; 144 | } 145 | return true; 146 | }, 147 | 148 | appendText: function(elemement, text) { 149 | elemement.appendChild(document.createTextNode(text)); 150 | }, 151 | 152 | jsonifyArray: function(arrayValue, indent) { 153 | var output = '['; 154 | 155 | if (1 == arrayValue.length) { 156 | output += JSON.stringify(arrayValue[0]); 157 | } 158 | else { 159 | for (var index = 0; index < arrayValue.length; index++) { 160 | if (0 < index) { 161 | output += ',\n ' + indent; 162 | } 163 | output += JSON.stringify(arrayValue[index]); 164 | } 165 | } 166 | output += ']'; 167 | return output; 168 | }, 169 | 170 | jsonifyObject: function(objectValue, indent) { 171 | var output = '{'; 172 | var value; 173 | 174 | var count = 0; 175 | for (var property in objectValue) { 176 | ++count; 177 | if (Array.isArray(objectValue[property]) || 178 | ('object' == typeof(value))) { 179 | ++count; 180 | } 181 | } 182 | if (1 == count) { 183 | for (var property in objectValue) { 184 | output += ' "' + property + '": ' + 185 | JSON.stringify(objectValue[property]) + 186 | ' '; 187 | } 188 | } 189 | else { 190 | var first = true; 191 | for (var property in objectValue) { 192 | if (! first) { 193 | output += ','; 194 | } 195 | first = false; 196 | output += '\n ' + indent + '"' + property + '": '; 197 | value = objectValue[property]; 198 | if (Array.isArray(value)) { 199 | output += this.jsonifyArray(value, indent + 200 | ' '.substr(0, 5 + property.length)); 201 | } 202 | else if ('object' == typeof(value)) { 203 | output += this.jsonifyObject(value, indent + ' '); 204 | } 205 | else { 206 | output += JSON.stringify(value); 207 | } 208 | } 209 | if (1 < output.length) { 210 | output += '\n' + indent; 211 | } 212 | } 213 | output += '}'; 214 | return output; 215 | }, 216 | 217 | /** 218 | * Generate javascript source code for captured metadata 219 | * Metadata is in pretty-printed JSON format 220 | */ 221 | generateSource: function() { 222 | /* "\/" is used instead of a plain forward slash so that the contents 223 | of testharnessreport.js can (for convenience) be copy-pasted into a 224 | script tag without issue. Otherwise, the HTML parser would think that 225 | the script ended in the middle of that string literal. */ 226 | var source = 227 | ' 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /tests/test-results/analysis.css: -------------------------------------------------------------------------------- 1 | 2 | th { 3 | text-align: left; 4 | background: #4a89dc; 5 | color: #fff; 6 | } 7 | 8 | td.FAIL { 9 | background: #da4453; 10 | color: #fff; 11 | } 12 | 13 | td.PASS { 14 | background: #37bc9b; 15 | color: #fff; 16 | } 17 | 18 | td.NOTRUN, td.TIMEOUT, td.undefined { 19 | background: #f6bb42; 20 | color: #fff; 21 | } 22 | 23 | table > tbody > tr > td.NOTRUN, table > tbody > tr > td.TIMEOUT { 24 | padding: 8px 2px; 25 | } 26 | 27 | td.OK { 28 | color: transparent; 29 | } 30 | 31 | td.FAIL, td.PASS, td.NOTRUN, td.TIMEOUT, td.undefined, td.OK { 32 | font-size: 0.7em; 33 | text-align: center; 34 | } 35 | 36 | tr.test { 37 | background: #ccd1d9; 38 | } 39 | 40 | tr.test > td:first-of-type { 41 | font-weight: bold; 42 | } 43 | 44 | tr.test small { 45 | font-weight: normal; 46 | } 47 | 48 | tr.subtest > td:first-of-type { 49 | padding-left: 2em; 50 | max-width: 790px; 51 | overflow: hidden; 52 | text-overflow: ellipsis; 53 | white-space: nowrap; 54 | } 55 | 56 | .floatingHeader { 57 | position: fixed; 58 | top: 0; 59 | visibility: hidden; 60 | } 61 | 62 | dd { 63 | padding-left: 2em; 64 | } 65 | -------------------------------------------------------------------------------- /tests/test-results/complete-fails.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Complete Failures 6 | 7 | 8 | 9 | 10 |
11 |
12 |

Complete Failures

13 |
14 |

Completely failed files: 1; Completely failed subtests: 6; Failure level: 6/38 (15.79%)

15 |

Test Files

16 |
  1. /pointerlock/idlharness.html (6/24, 25.00%, 15.79% of total)
  2. 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
TestCh53Ed25Ff51
/pointerlock/idlharness.html (6/24, 25.00%, 15.79% of total)OKOKOK
Element must be primary interface of window.document.documentElementFAILFAILFAIL
Stringification of window.document.documentElementFAILFAILFAIL
Document must be primary interface of window.documentFAILFAILFAIL
Stringification of window.documentFAILFAILFAIL
Document interface: window.document must inherit property "onpointerlockchange" with the proper type (0)FAILFAILFAIL
Document interface: window.document must inherit property "onpointerlockerror" with the proper type (1)FAILFAILFAIL
29 |
30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /tests/test-results/less-than-2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Less Than 2 Passes 6 | 7 | 8 | 9 | 10 |
11 |
12 |

Less Than 2 Passes

13 |
14 |

Test files without 2 passes: 1; Subtests without 2 passes: 6; Failure level: 6/38 (15.79%)

15 |

Test Files

16 |
  1. /pointerlock/idlharness.html (6/24, 25.00%, 15.79% of total)
  2. 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
TestCh53Ed25Ff51
/pointerlock/idlharness.html (6/24, 25.00%, 15.79% of total)OKOKOK
Element must be primary interface of window.document.documentElementFAILFAILFAIL
Stringification of window.document.documentElementFAILFAILFAIL
Document must be primary interface of window.documentFAILFAILFAIL
Stringification of window.documentFAILFAILFAIL
Document interface: window.document must inherit property "onpointerlockchange" with the proper type (0)FAILFAILFAIL
Document interface: window.document must inherit property "onpointerlockerror" with the proper type (1)FAILFAILFAIL
29 |
30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /tidyconfig.txt: -------------------------------------------------------------------------------- 1 | char-encoding: utf8 2 | indent: yes 3 | indent-spaces: 2 4 | wrap: 80 5 | tidy-mark: no 6 | -------------------------------------------------------------------------------- /w3c.json: -------------------------------------------------------------------------------- 1 | { 2 | "group": [ 3 | "114929" 4 | ], 5 | "contacts": [ 6 | "siusin" 7 | ], 8 | "shortName": "pointerlock-2", 9 | "repo-type": "rec-track" 10 | } 11 | --------------------------------------------------------------------------------