Skip to content

slightlyoff/unadjusted_pointer_lock_explainer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 

Repository files navigation

Unadjusted Pointer Lock Movement Explained

Authors:

Participate

Spec PR

Introduction

The Pointer Lock API allows an element to “capture” mouse (or other pointer) movements and hides visible pointers. This is an important capability for games and other rich media applications. The Unadjusted Movement flag improves Pointer Lock for certain gaming cases by returning “raw” OS values for pointer position without acceleration addition or correction. This is critical in scenarios such as first-person shooter games that require ultra-precise pointer control(as seen in this reddit post about Stadia.

Goals

Developers of some games are unable to provide comparable mouse accuracy via the existing Pointer Lock API as they are through native applications. This places users at a disadvantage and causes games to “feel mushy”. Those developers have requested a mechanism for requesting movements reported as they would be in, e.g., the windows Raw Input mode. When applications request and receive pointer locks in this mode, it should allow them to provide significantly more accuracy relative to underlying mouse movement than potentially post-processed position data.

As a secondary goal, we seek to modernize this API to support Promises and provide considerably more detail about error states.

Non-goals

It’s a non-goal to provide raw input data beyond the already-reported position information that pointer APIs (mouse events, etc.) already report.

This API also does not seek to provide control over device polling frequency.

Lastly, it is a non-goal to provide access to underlying OS-specific acceleration calculations for inputs or support simultaneous delivery of both adjusted and unadjusted values.

Requesting Unadjusted Movement Values

To use the proposed extensions to the existing Pointer Lock API, we introduce a property bag to the requestPointerLock method and wait on the returned promise. We show the same example in Promises and async/await styles below:

let el = document.getElementById("pointer_capture");

// With "raw" promises:
el.onclick = (evt) => {
  el.requestPointerLock({ unadjustedMovement: true })
    .then(() => {
     console.log("hooray! We got pointer lock");
    })
    .catch((error) => {
      console.log("Pointer lock capture failed:", error);

      // Some platforms do not support unadjusted movement. If you
      // would like PointerLock anyway, request again.
      if (error.name == "NotSupportedError") {
        targetElement.requestPointerLock();
      }
   });
};

// Using async/await syntax:
el.onclick = async (evt) => {
  try {
    let result = await el.requestPointerLock({ unadjustedMovement: true });
   console.log("hooray! We got pointer lock");
  } catch (error) {
    console.log("Pointer lock capture failed:", error);

    // Some platforms do not support unadjusted movement. If you
    // would like PointerLock anyway, request again.
    if (error.name == "NotSupportedError") {
      targetElement.requestPointerLock();
    }
  }
};

Using Unadjusted Values

The events generated by a Pointer Lock with unadjusted movement look similar to those without: MouseEvent objects with positional information provided by existing properties. Unadjusted movement will provide more “raw” information about the movementX and movementY properties, but the types remain identical.

Detailed design discussion

Promise error state considerations

We introduce a new Promise API in this proposal. One subtle consequence of introducing this mechanism in addition to the existing pointerlockchange and pointerlockerror events is that it is possible to re-request locks with different options. E.g.:

Property bag vs. positional arguments

Per the TAG's Design Principles, we choose a design that avoids adding boolean positional parameters to the existing API, instead opting for an extensible property bag with named key values.

Fingerprinting concern

Comparing adjusted and unadjusted inputs may allow sites to detect a user’s acceleration settings. The asynchronous, promise-based design of the Pointer Lock API enables a permission or usage indication UI should UAs deem that necessary in future to guard against this risk.

Integration with the Permissions API

Following on from questions related to exposing user configuration, one might reasonably expect an async API that creates a permission request to integrate with the Permissions API. The existing Pointer Lock spec does not, and the additions proposed here do not include that extension, and we suggest that if/when UAs extend their UIs to request explicit user consent (rather than user activation), that such an addition would be warranted.

Considered alternatives

Raw values in addition to adjusted values

Certain platforms make it challenging to deliver both values simultaneously in a reliable way, particularly Windows and Linux. It may be possible to provide this, but developer interest in receiving both values has been low and concerns about code being written to expect one style and receiving another has not been an issue in practice.

Always provide raw values + adjustment functions

One alternative design might be to always provide raw values whilst giving access to acceleration functions and, perhaps, a short log of recent events from which to calculate acceleration. This alternative was not chosen because:

  • Acceleration functions applied by OSes may be difficult to determine with high precision, particularly in the face of user settings which may be difficult to query
  • Code which expects (or is resilient to) adjusted values may cease to work
  • Requiring developers to process location information poses a burden for fidelity in some cases with dubious benefit to most
  • Lastly, developers have not explicitly requested access to these functions, and providing them may exacerbate fingerprinting concerns.

Force changes from unadjusted to adjusted to not happen too often

One fingerprinting concern is an application switching back and forth between unadjusted movement and adjusted movement to determine the users acceleration setting. While most users leave the OS default some might have more specific settings which could be used to identify them. One way to mitigate these concerns is to require a time delay between switches. However, this will break some legitimate use cases and does not completely mitigate the issue. One could imagine a first person shooter where unadjusted movement is off while in the game however adjusted movement is turned on when a menu is popped up. If that menu is up and then someone comes around a corner the user might have to very quickly switch back to the game and if they cannot get unadjusted movement their aim would be horrible for that period of time while they waived the required time to switch back. Also, if timed right only a few switches would be needed at various mouse speeds to determine the acceleration setting. So a smart application could still use this to determine acceleration settings.

References & acknowledgements

  • Spec Authors: James Hollyer, Navid Zolghadr
  • Reviewers: Dominic Denicola, Marcos Cáceres
  • Explainer Author: Alex Russell, James Hollyer
  • Spec Change: w3c/pointerlock#49

About

An Explainer for Pointer Lock Movement

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors