Copyright © 2021 W3C ® ( MIT , ERCIM , Keio , Beihang ). W3C liability , trademark and permissive document license rules apply.
This section describes the status of this document at the time of its publication. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at https://www.w3.org/TR/.
A history of changes to this document can be found at http://dvcs.w3.org/hg/pointerlock/log/default/index.html
Summary of changes since W3C Recommendation 27 October 2016 :
This document was published by the Web Applications Working Group as an Editor's Draft.
Publication as an Editor's Draft does not imply endorsement by W3C and its Members.
This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.
This document was produced by a group operating under the W3C Patent Policy . W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy .
This document is governed by the 2 November 2021 W3C Process Document .
This section is non-normative.
The Pointer Lock API provides applications the ability to directly interpret mouse movements as an input method, rather than being limited to only read the position of the mouse cursor. A popular example is that of first person movement controls in three dimensional graphics applications such as games: movement of the mouse is interpreted to control the rotation/direction of the player's camera; no mouse cursor is displayed, and the movement is not limited to the traditional boundaries (such as the user agent's window, or the overall screen) that the mouse cursor is usually subject to, meaning that any mouse movements can be tracked indefinitely in any direction.
Pointer
Lock
is
related
to
Mouse
Capture
[
MSDN-SETCAPTURE
]
[
MDN-SETCAPTURE
]
(Mouse
Capture
is
unspecified:
bug
14600
).
Capture
provides
continued
event
delivery
to
a
target
element
while
a
mouse
is
being
dragged,
but
ceases
when
the
mouse
button
is
released.
Pointer
Lock
differs
by
being
persistent,
not
limited
by
screen
boundaries,
sending
events
regardless
of
mouse
button
state,
hiding
the
cursor,
and
not
releasing
until
an
API
call
or
specific
default
unlock
gesture
by
the
user.
Pointer Lock deals with capturing a single resource and relating it to a single element. This is similar to the Fullscreen API [ FULLSCREEN ], which promotes a single element to be full screen. The Pointer Lock API chooses to pattern the resource capture, state change, and release API as closely as possible after the Fullscreen API.
The Pointer Lock interaction mode was previously referred to as mouse lock. The name was changed as many different controller types besides mice can manipulate the on screen pointing cursor, and they are all impacted.
pointerlockchange
and
pointerlockerror
Events
Two events are used to communicate pointer lock state change or an error in changing state. They are named pointerlockchange and pointerlockerror . If pointer lock is entered or exited for any reason a pointerlockchange event must be sent.
User
agents
must
deliver
these
events
by
queuing
a
task
to
fire
an
event
of
the
appropriate
name
with
its
bubbles
attribute
[
DOM
]
set
to
false
to
the
pointer
lock
target
element's
node
document
.
Magnification software increases the size of content on the screen. It uses the mouse to move the magnified point of focus around. When a pointer lock is initiated, the magnification software needs to switch to using the keyboard to move the magnified point of focus around instead. When a pointerlockchange event is fired, web browsers therefore need to make sure the event is communicated to assistive technologies like screen magnifiers.
Element
Interface
The Element interface is extended to provide the ability to request the the pointer be locked.
WebIDLpartial interface Element {
undefined requestPointerLock
();
};
requestPointerLock()
method
Requests
that
the
pointer
be
locked
to
a
DOM
element
target
.
The
user
agent
determines
if
pointer
lock
state
will
be
entered
entered,
and
upon
lock
state
change
or
error
must
MUST
send
either
a
pointerlockchange
or
pointerlockerror
event
respectively.
Pointer
lock
must
not
succeed
MUST
fail
if
the
document
object's
active
sandboxing
flag
set
has
the
sandboxed
pointer
lock
browsing
context
flag
set.
Pointer
lock
must
not
succeed
MUST
fail
unless
the
target
's
shadow-including
root
is
the
active
document
of
a
browsing
context
which
is
(or
has
an
ancestor
browsing
context
which
is)
in
focus
by
a
window
which
is
in
focus
by
the
operating
system's
window
manager.
The
target
element
and
its
browsing
context
need
not
be
in
focus.
If
a
user
has
exited
pointer
Pointer
lock
via
the
default
unlock
gesture
is
a
transient
activation-gated
API
,
or
pointer
lock
has
not
previously
been
entered
for
this
document,
an
event
generated
as
therefore
a
result
of
an
engagement
gesture
must
be
received
by
the
document
before
requestPointerLock
()
will
succeed.
Note
This
ensures
a
user
can
leave
a
document
that
constantly
attempts
to
lock
call
MUST
fail
if
the
pointer.
The
document
will
be
blocked
from
relevant
global
object
of
this
does
not
have
transient
activation
.
This
prevents
locking
upon
initial
navigation
or
re-acquiring
lock
unless
the
user
re-engages
directly
with
the
document.
without
user's
attention.
Conversely,
if
pointer
lock
A
requestPointerLock
()
call
immediately
after
the
default
unlock
gesture
MUST
fail
even
when
transient
activation
is
exited
via
available,
to
prevent
malicious
sites
from
acquiring
an
unescapable
locked
state
through
repeated
lock
attempts.
On
the
other
hand,
a
requestPointerLock
()
call
immediately
after
a
programmatic
lock
exit
(through
a
exitPointerLock
()
no
engagement
gesture
call)
MUST
succeed
when
transient
activation
is
required
available,
to
reenter
pointer
lock.
This
enables
enable
applications
that
frequently
to
move
frequently
between
interaction
modes,
and
ones
that
may
do
so
based
on
possibly
through
a
timer
or
remote
network
activity.
If any element (including this one), whose shadow-including root is same as this element's shadow-including root , is already locked (or pending lock) the pointer lock target must be updated to this element and a pointerlockchange event sent.
If any element, whose shadow-including root is a different document, is already locked the request must fail and a pointerlockerror event be sent.
Once
in
the
locked
state
the
user
agent
must
fire
all
relevant
user
generated
MouseEvent
events
(for
example:
mousemove
,
mousedown
,
mouseup
,
click
,
and
wheel
)
[
ui-events
]
to
the
target
of
pointer
lock,
and
not
fire
mouse
events
to
other
elements.
Events
that
require
the
concept
of
a
mouse
cursor
must
not
be
dispatched
(for
example:
mouseover
,
mouseout
,
drag
,
and
drop
).
In the locked state the system mouse cursor must be hidden. Movement and button presses of the mouse must not cause the window to lose focus.
Synthetic mouse events created by application script act the same regardless of lock state.
Document
Interface
WebIDLpartial interface Document {
attribute EventHandler onpointerlockchange
;
attribute EventHandler onpointerlockerror
;
undefined exitPointerLock
();
};
onpointerlockchange
attribute
An event handler idl attribute for pointerlockchange events.
onpointerlockerror
attribute
An event handler idl attribute for pointerlockerror events.
exitPointerLock()
method
Initiates an exit from pointer lock state if currently locked to a target whose shadow-including root is this document, and sends a pointerlockchange event when the lock state has been exited.
The
system
mouse
cursor
must
be
displayed
again
and
positioned
at
the
same
location
that
it
was
when
pointer
lock
was
entered
(the
same
location
that
is
reported
in
screenX
,
screenY
,
when
the
pointer
is
locked).
DocumentOrShadowRoot
Mixin
WebIDLpartial interface mixin DocumentOrShadowRoot {
readonly attribute Element ? pointerLockElement
;
};
pointerLockElement
While the pointer is locked, returns the result of retargeting the element, which is the target for mouse events, against this element if the result and this element are in the same tree, otherwise returns null.
Returns null if lock is pending or if pointer is unlocked.
<body>
<div id="host1">
<shadow-root id="root1">
<canvas id="canvas1"></canvas>
</shadow-root>
</div>
<div id="host2">
<shadow-root id="root2">
<canvas id="canvas2"></canvas>
</shadow-root>
</div>
</
body
>
Note:
the
example
uses
fictional
shadow-root
element
to
denote
a
shadow
root
instance.
If
#canvas1
is
the
target,
document.pointerLockElement
returns
#host1
,
and
root1.pointerLockElement
returns
#canvas1
.
The
result
of
retargeting
#canvas1
against
#root2
is
#host1
,
but
as
#host1
is
not
in
the
same
tree
as
#root2
,
null
will
be
returned
for
root2.pointerLockElement
.
MouseEvent
Interface
WebIDLpartial interface MouseEvent {
readonly attribute double movementX
;
readonly attribute double movementY
;
};
movementX
attribute
movementY
attribute
The
attributes
movementX
movementY
must
provide
the
change
in
position
of
the
pointer,
as
if
the
values
of
screenX
,
screenY
,
were
stored
between
two
subsequent
mousemove
events
eNow
and
ePrevious
and
the
difference
taken
movementX
=
eNow.screenX-ePrevious.screenX
.
movementX
/
movementY
must
be
zero
for
all
mouse
events
except
mousemove
.
All
motion
data
must
be
delivered
via
mousemove
events
such
that
between
any
two
mouse
events
earlierEvent
and
currentEvent
the
value
of
currentEvent.screenX-earlierEvent.screenX
is
equivalent
to
the
sum
of
all
movementX
movementY
/code>
events
after
earlierEvent
,
with
the
exception
of
when
screenX
can
not
be
updated
because
the
pointer
is
clipped
by
the
user
agent
screen
boundaries.
movementX
/
movementY
must
be
updated
regardless
of
pointer
lock
state.
When
unlocked,
the
system
cursor
can
exit
and
re-enter
the
user
agent
window.
If
it
does
so
and
the
user
agent
was
not
the
target
of
operating
system
mouse
move
events
then
the
most
recent
pointer
position
will
be
unknown
to
the
user
agent
and
movementX
/
movementY
can
not
be
computed
and
must
be
set
to
zero.
When
pointer
lock
is
enabled
clientX
,
clientY
,
screenX
,
and
screenY
must
hold
constant
values
as
if
the
pointer
did
not
move
at
all
once
pointer
lock
was
entered.
But
movementX
/
movementY
must
continue
to
provide
the
change
in
position
of
the
pointer
as
when
the
pointer
is
unlocked.
There
will
be
no
limit
to
movementX
/
movementY
values
if
the
mouse
is
continuously
moved
in
a
single
direction.
The
concept
of
the
mouse
cursor
will
have
been
removed,
and
it
will
not
move
off
the
window
or
be
clamped
by
a
screen
edge.
The
un-initialized
value
of
movementX
/
movementY
must
be
0
.
Large
movement
values
must
not
appear
in
situations
when
mouse
input
is
interupted,
such
as
the
mouse
cursor
leaving
the
window
and
then
re-entering
at
another
location.
If
a
User
agent
experiences
a
gap
in
receiving
mouse
input
data
from
the
operating
system
then
the
next
generated
mousemove
event
must
have
movementX
/
movementY
set
to
0
.
These
gaps
may
appear
for
example
when
the
User
agent
receives
a
mouse
leaving
event
at
the
window
system
API.
As
an
exception
mouse
capture
may
allow
the
User
agent
to
continue
receiving
mouse
events
when
the
cursor
moves
outside
the
window.
MouseEventInit
Dictionary
WebIDLpartial dictionary MouseEventInit {
double movementX
= 0;
double movementY
= 0;
};
movementX
member
movementY
member
movementX
and
movementY
are
used
to
initialize
respective
members
of
MouseEvent
.
A default unlock gesture must always be available that will exit pointer lock.
Pointer lock must be exited if the target becomes disconnected , or the user agent , window, or tab loses focus. Moving focus between elements of active documents , including between browsing contexts , does not exit pointer lock. E.g. using the keyboard to move focus between contents of frames or iframes will not exit.
Pointer lock must not be exited when fullscreen [ FULLSCREEN ] is entered or exited unless the pointer is required to enable interaction with the user agent graphical user interface, the default unlock gesture was used to exit both fullscreen and pointer lock, or window or tab focus was lost.
This section is non-normative.
A player on a first/third person game will need to control the view-port orientation. A widely used method is the use of mouse movements to control the viewing angle. This kind of application can use the Pointer Lock API to allow a complete freedom of control over the viewport's yaw and pitch even when the user is not pressing mouse buttons. Those buttons can be used for other actions while constantly providing navigation via mouse movement.
Users of a three dimensional modeling application will need to rotate models. A application can use the Pointer Lock API to enable the author to rotate the model freely in a drag operation without limiting motion. Without pointer lock a drag would stop providing motion data when the mouse cursor is limited by the edge of the screen.
Similarly, absolute motion panning of a large two dimensional image could be permitted in a single drag operation without cursor / screen limits.
A player on a fast reflexes game controls a paddle to bounce back a ball to the opponent, while allowing the same paddle to execute actions based on different mouse buttons being pressed. The application can use the Pointer Lock API to allow the player to react quickly without being concerned about the mouse cursor leaving the game play area and clicking another system application, thus breaking the game flow.
When modifying numerically magnitudes in applications sometimes the user will prefer to "drag" a numeric control by its button handles to increment or decrement the numeric value. E.g. a spinner with a number entry text box and arrows pointing up and down that can be clicked or dragged on to change the value. An application could use the Pointer Lock API to allow modifying the numeric values beyond what the logical screen bounds allow. The same could apply for a control that fast forwards or rewinds a video or audio stream like a "jog".
Some games use a classical cursor, however they want it to be limited or controlled in some manner. E.g. limited to the bounds of the game, or movable by the game. Locking the pointer enables this if the application creates their own cursor. However HTML and DOM should still be available to use for user interface. Synthetic mouse events should be permitted to allow an application defined cursor to interact with DOM. E.g. the following code should permit a custom cursor to send click events while the pointer is locked:
document.addEventListener("click", function (e) {
if (e._isSynthetic)
return;
// send a synthetic click
var ee = document.createEvent("MouseEvents");
ee._isSynthetic = true;
x = myCursor.x;
y = myCursor.y;
ee.initMouseEvent("click", true, true, null, 1,
x + e.screenX - e.clientX,
y + e.screenY - e.clientY,
x,
y);
var target = document.elementFromPoint(x, y);
if (target)
target.dispatchEvent(ee);
});
Note that synthetic clicks may not be permitted by a user agent to produce the same default action as a non-synthetic click. However, application handlers can still take action and provide user interface with existing HTML & DOM mechanisms.
Real Time Strategy games often use this technique. When the player moves the pointer to the view-port borders, if they "push" the border with a mouse movement, the view-port is panned over the game area according to how much they move the mouse. When moving the mouse cursor within the bounds of the view port it acts at is typically would on a system. Applications may choose to implement this using pointer lock and the previous use case of "Synthetic cursor interaction with HTML DOM UI" to bring cursor behavior completely under their control.
Games
that
use
pointer
lock
may
desire
a
traditional
UI
and
system
cursor
while
players
prepare
in
a
game
lobby.
Games
usually
start
after
a
short
timer
when
all
players
are
ready.
Ideally
the
game
could
then
switch
to
pointer
lock
mode
without
requiring
an
engagement
gesture
a
user
activation
.
Players
should
be
able
to
seamlessly
move
from
the
game
lobby
into
game
navigation.
Game portals, and other sites such as Facebook and Google Plus, host games for users to play. These games may be hosted and served from a different origin from that of the portal site. Embedded games should be able to lock the pointer, even in non-full screen mode.
This section is non-normative.
Security Concerns:
Responses:
Recommendations:
Pointer lock is a required user interaction mode for certain application types, but carries a usability concern if maliciously used. An attacker could remove the ability for a user to control their mouse cursor on their system. User agents will prevent this by always providing a mechanism to exit pointer lock, by informing the user of how, and by limiting how pointer lock can be entered.
User agents will determine their own appropriate policies, which may be specialized per device or differ based on user options.
This section is non-normative.
Mouse Capture [ MDN-SETCAPTURE ] handles low security risk mouse event target lock for the duration of a mouse drag gesture. Pointer lock removes the concept of the cursor and directs all events to a given target. They are related, but different.
If a browser implemented both, it would be reasonable to support a combination of traits: The security simplicity of "automatically release lock when mouse up" and the increased functionality of total control over mouse input and removal of the system cursor. The security trait would allow more permissive use of the feature for applications that only required a short burst of pointer lock during a drag event.
This functionality is omitted from the initial version of this spec because it helps the minor use cases in windowed mode but we still do not have an implementation solving the major ones. And, to implement this a browser must implement both, which none does yet. It is not clear if this feature should live on .lock or on .setCapture. If both were implemented, either API could be augmented fairly easily to offer the hybrid functionality.
Even in non locked state, the delta values of mouse movement are useful. Changing the meaning of .client or .screen based on lock state would also cause easy errors in code not carefully monitoring the lock state.
When the pointer is locked 'wheel' events should be sent to the pointer lock target element just as 'mousemove' events are. There is a naming conflict with .deltaX/Y/Z as defined in DOM 3 'wheel' event .
There are good motivations to provide a more fine grained approach. E.g. the use case "View-port panning by moving a mouse cursor against the bounds of a view-port" doesn't require hiding the mouse cursor, only bounding it and always having delta values available. Also, this specification defines the movement deltas to be taken from how the system mouse cursor moves, which incorporates operating system filtering and acceleration of the mouse movement data. Applications may desire access to a more raw form of movement data prior to adjustments appropriate for a mouse cursor. Also, raw data may provide better than pixel level accuracy for movement, as well as higher frequency updates. Providing the raw delta movement would also not require special permission or mode from a user, and for some set of applications that do not require bounding the cursor may reduce the security barriers and prompts needed.
There are two justifications for postponing this finer grained approach. The first is a concern of specifying what units mouse movement data are provided in. This specification defines .movementX/Y precisely as the same values that could be recorded when the mouse is not under lock by changes in .screenX/Y. Implementations across multiple user agents and operating systems will easily be able to meet that requirement and provide application developers and users with a consistent experience. Further, users are expected to have already configured the full system of hardware input and operating system options resulting in a comfortable control the system mouse cursor. By specifying .movementX/Y in the same units mouse lock API applications will be instantly usable to all users because they have already settled their preferences.
Secondly, the implementation of providing movement data and bounding the mouse cursor is more difficult in the fine grained approach. Bundling the features together gives implementations freedom to use a variety of techniques as appropriate on each operating system and is more practical to implement. Direct APIs do not exist on major desktop platforms (Windows, Mac OS X, Linux) to bound the cursor to a specific rectangle, and prototypes have not yet been developed to demonstrate building that behavior by e.g. invisible windows with Xlib or manual cursor movement on Mac. Unaccelerated Delta values have been proposed to be accessed by reading raw Human Interface Device (HID) data. E.g. WM_INPUT messages on Windows, and USB device APIs on Mac OS X / Linux. The challenge here is interpreting and normalizing the units to some consistent and specifiable scale. Also, most APIs considered to date are limited to USB devices.
It would be reasonable to consider adding these capabilities in the future, as the currently specified pointer lock API would be easy to continue to support if the finer grained delta and confinement features were implemented.
The bundled API is selected for implementation practicality, because the desired use cases are supported, and because it will not conflict with future improvements as discussed here.
Not yet, for the same reasons in the previous question: "Why bundle all functionality (hiding cursor, providing mouse deltas) instead of using CSS to hide the cursor, always providing delta values, and offering an API to restrict the cursor movement to a portion of the web page?" .
When under pointer lock many mouse events remain relevant, e.g. click, mousedown, etc. These all share the same event data structure MouseEvent. If movement data were reported via a new data structure then a new event would be needed for reporting delta movement. The new data structure would have many parallels to MouseEvent to offer the same conveniences, e.g. button and modifier key states. When handling click, down, and up events would the existing mousedown, mouseup be used? If so, they would provide .clientX/Y and .screenX/Y with no useful data, but would lack the convenience of containing the current movement data. Or, new events would also be required for when the mouse is locked.
Also, movementX/Y are convenient even when the mouse is not locked. This spec requires movement members to always be valid, even when the mouse cursor exists. This reduces code required to track the last cursor state and mouseover/mouseout transitions if applications wish to make use of delta motion of the mouse.
The only negative of adding movementX/Y to MouseEvent appears to be the unused values in clientX/Y and screenX/Y when under pointer lock. This does not seem to be a significant problem.
Therefore the minimal change to add movementX/Y to MouseEvent is selected to reduce API and implementation complexity.
Consider a game with a 3D view controlled by moving the mouse cursor, while the user may still chat with other users via a text console. It is reasonable for the application to accept text input to an element that is different than where mouse events are being dispatched. This is similar to pre-existing behavior of receiving mousemove events over any element while typing into a form on a page.
As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.
The key word MUST in this document is to be interpreted as described in BCP 14 [ RFC2119 ] [ RFC8174 ] when, and only when, they appear in all capitals, as shown here.
This specification defines conformance criteria that apply to a single product: the user agent that implements the interfaces that it contains.
This section is non-normative.
Many thanks to lots of people who made contributions to the discussions of this specification:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: