Copyright © 2025 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
このセクションは、この文書が公開された時点でのステータスについて説明します。現在の W3C 公開物と、この技術レポートの最新改訂版は W3C 標準および草案一覧 で確認できます。
この文書の変更履歴は https://github.com/w3c/pointerlock/commits/gh-pages/index.html で確認できます。
W3C 勧告 2016年10月27日 以降の変更点の概要:
この文書は Web Applications Working Group により、 勧告トラック を用いて作業草案として公開されました。
作業草案としての公開は、W3C およびそのメンバーによる支持を意味するものではありません。
この文書はドラフトであり、今後随時更新、差し替え、または廃止される可能性があります。この文書を進行中の作業以外のものとして引用するのは適切ではありません。
この文書は W3C 特許ポリシー の下で運営されているグループによって作成されました。 W3C は 関連成果物に関する特許開示の公開リスト を管理しています。このページには特許開示の方法についても記載されています。個人が、必須特許請求項 を含むと信じる特許について実際に知っている場合、その情報は W3C特許ポリシー第6節 に従って開示する必要があります。
この文書は 2025年8月18日 W3C プロセス文書 により管理されています。
このセクションは規範的ではありません。
Pointer Lock APIは、アプリケーションがマウスカーソルの位置を読み取るだけでなく、マウスの動きを直接入力手段として解釈する機能を提供します。一般的な例としては、三次元グラフィックスアプリケーション(例:ゲーム)における一人称の操作があります。マウスの動きがプレイヤーのカメラの回転や方向制御に利用され、マウスカーソルは表示されません。また、マウスカーソルが通常制限される従来の境界(ユーザーエージェントのウィンドウや画面全体など)に縛られず、マウスの動きを任意の方向に無制限で追跡できます。
Pointer LockはMouse Capture[MDN-SETCAPTURE](Mouse Captureは仕様未定義:バグ 14600)と関連しています。Captureは、マウスをドラッグ中にターゲット要素へのイベント配信を継続しますが、マウスボタンが離されると終了します。Pointer Lockは、継続的であり、画面の境界に制限されず、マウスボタンの状態に関係なくイベントを送信し、カーソルを非表示にし、API呼び出しやユーザーによる特定のデフォルト解除ジェスチャーまで解除されません。
Pointer Lockは単一のリソースをキャプチャし、それを単一の要素に関連付ける処理を扱います。これはFullscreen API[FULLSCREEN]と類似しており、Fullscreen APIは単一要素をフルスクリーン化します。Pointer Lock APIは、リソースのキャプチャ、状態変更、解除APIの設計を可能な限りFullscreen APIに倣っています。
Pointer Lockのインタラクションモードは、以前はmouse lockと呼ばれていました。名前が変更されたのは、マウス以外にも様々なコントローラーが画面上のカーソルを操作できるためであり、それらも影響を受けるからです。
pointer lock stateは、単一のDOM要素(pointer-lock target)が全てのマウスイベントを受け取り、カーソルが非表示となる状態です。
pointer lock stateに入ると、ユーザーエージェントは
pointer-lock target、
pointer-lock
options
(PointerLockOptions
)、
cursor
position(Pointer Lock Stateに入った時点のシステムマウスカーソルの位置(screenX
,
screenY
)を表す数値のペア)を持ちます。pointer-lock targetは、ユーザーが生成した全てのMouseEvent
イベント(mousemove
,
mousedown
, mouseup
, click
,
dblclick
, auxclick
, wheel
[ui-events])を受け取ります。他の要素は、pointer
lock state中はこれらのイベントを受け取りません。マウスカーソルの概念が必要なイベント(mouseenter
,
mouseleave
, mouseover
, mouseout
,
drag
, drop
)のディスパッチは行われません。
例だけでなく、これらのイベントを規範的にリストアップすることは可能ですか?
現状の文章でも問題ありませんが、精度不足はマウスイベント全体の仕様の不十分さの表れでもあります。w3c/uievents#200で進展があり次第、この段落はUI Events仕様に処理モデルの実際の変更として移せるでしょう。
一方、現状でも相互運用性のためにイベントリストを明確にすることが助けになります。
例えば、pointer eventsがこの変更の影響を受けるかどうかは明確ではありません。
pointer lock state中でpointer-lock optionsの
unadjustedMovement
メンバーがtrue
の場合、イベント座標はマウス加速などの基盤プラットフォームの挙動に影響されません。つまり、ユーザーエージェントは基盤プラットフォームのAPIを利用して生のイベントを取得できることを保証します。PointerLockOptions
の
unadjustedMovement
がfalse
の場合、ユーザーエージェントは基盤プラットフォームのデフォルトのマウス加速挙動に従います。
pointer lock state中は、システムマウスカーソルが非表示となり、ウィンドウがマウス移動やボタン操作に関係なくフォーカスを失わないようにします。これは基盤となるOS APIを直接または間接的に利用して実現されます。
アプリケーションスクリプトで生成された合成マウスイベントは、ロック状態に関係なく同じように動作します。
WebIDLdictionary PointerLockOptions
{
boolean unadjustedMovement
= false;
};
PointerLockOptions
辞書
ロックモードでポインターの挙動をカスタマイズするためのオプション辞書です。
unadjustedMovement
メンバー
この値がtrue
の場合、ポインターの動きはマウス加速などの基盤プラットフォームによる変更の影響を受けません。
ポインターロック状態の変更、または状態変更時のエラーを通知するために2つのイベントがあります。イベント名はpointerlockchangeおよびpointerlockerrorです。詳細は
3.
Element
インターフェースの拡張のアルゴリズムを参照してください。
拡大表示ソフトウェアは画面上のコンテンツを拡大します。マウスを使って拡大表示のフォーカス位置を移動しますが、ポインターロックが開始されると、拡大表示ソフトウェアはキーボードによる移動に切り替える必要があります。pointerlockchange
イベントが発火された際、Webブラウザは画面拡大ツールなどの支援技術に確実にイベントを通知する必要があります。
elementに対してポインターロックを解除する手順は以下の通りです:
pointerlockchange
とする。
Element
インターフェイスは、ポインタのロックを要求する機能を拡張して提供します。
WebIDLpartial interface Element {
Promise<undefined> requestPointerLock
(optional PointerLockOptions
options = {});
};
const lock_element = document.getElementById("lock_element");
const lock_button = document.getElementById("lock");
lock_button.addEventListener("click", async (event) => {
try {
await lock_element.requestPointerLock({ unadjustedMovement: true });
console.log("successfully locked!");
} catch (e) {
console.log("lock failed with error: ", e);
}
});
PointerLockOptions
options) メソッド
lock
requests queue という名前の 並列キュー
が全てのリクエストをキューイングするために使われます。requestPointerLock()
が呼び出されると、次の手順を実行します:
window
が フォーカス 状態で、this の shadow-including root
が アクティブドキュメント
である ブラウジングコンテキスト(またはフォーカスされていない
祖先
ブラウジングコンテキスト)の場合:
pointerlockerror
、対象は
this の
ノードドキュメント。
WrongDocumentError
"
DOMException
を与える。
この仕様では、非表示ドキュメントからのポインタロック要求を許可すべきではありません。
さらに、ドキュメントが非表示になった場合はポインタロックを解除するべきです。
Document
が過去に
exitPointerLock
()
で
ポインタロックを正常に解除していない場合:
pointerlockerror
、対象は
this の
ノードドキュメント。
NotAllowedError
"
DOMException
を与える。
pointerlockerror
、対象は
this の
ノードドキュメント。
SecurityError
"
DOMException
を与える。
unadjustedMovement
"]
が true で、
プラットフォームが
unadjustedMovement
をサポートしていない場合:
pointerlockerror
、対象は
this の
ノードドキュメント。
NotSupportedError
"
DOMException
を与える。
pointerlockerror
、対象は
this の ノードドキュメント。
InvalidStateError
"
DOMException
を与える。
pointerlockchange
、対象は
this の ノードドキュメント。
pointerlockerror
、対象は
this の ノードドキュメント。
NotSupportedError
"
DOMException
を与える。
pointerlockchange
、対象は this の ノードドキュメント。
WebIDLpartial interface Document {
attribute EventHandler onpointerlockchange
;
attribute EventHandler onpointerlockerror
;
undefined exitPointerLock
();
};
onpointerlockchange
属性
イベントハンドラーIDL属性であり、
pointerlockchange
イベント用です。
onpointerlockerror
属性
イベントハンドラーIDL属性であり、
pointerlockerror
イベント用です。
exitPointerLock()
メソッド
WebIDLpartial interface mixin DocumentOrShadowRoot {
readonly attribute Element? pointerLockElement
;
};
pointerLockElement
ポインタがロックされている間、マウスイベントのターゲットとなる要素を retargeting した結果を返します。この結果と this 要素が同じツリー内にある場合はその要素を、そうでなければ null を返します。
ロックが保留中またはポインタがロック解除されている場合は null を返します。
<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>
この例では、shadow-root
要素は シャドウルート
インスタンスを表す架空の要素です。
#canvas1
がターゲットの場合、document.pointerLockElement
は #host1
を返し、root1.pointerLockElement
は #canvas1
を返します。retargeting で #canvas1
を
#root2
に対して retarget すると #host1
になりますが、#host1
は
#root2
と同じツリー内にないため、root2.pointerLockElement
は null になります。
WebIDLpartial interface MouseEvent {
readonly attribute double movementX
;
readonly attribute double movementY
;
};
movementX
属性
movementY
属性
movementX
および movementY
属性は、ポインタの位置変化量を提供しなければならない。これは、screenX
および
screenY
の値が2つの連続した mousemove
イベント eNow
および
ePrevious
間で保存されていて、その差分 movementX =
eNow.screenX - ePrevious.screenX
を取った場合と同様である。
movementX
および movementY
は、mousemove
および
pointermove
以外のすべてのマウスイベントでは0でなければならない。すべての移動データは mousemove
イベントを通じて届けられるものとし、任意の2つのマウスイベント earlierEvent
と currentEvent
の間で
currentEvent.screenX - earlierEvent.screenX
の値が、それらの間に発生した全ての movementX
の合計と等しくなる。ただし、ポインタが ユーザーエージェント の画面端でクリップされ screenX が更新できない場合を除く。
movementX
および movementY
は、pointer lock
の状態にかかわらず更新されなければならない。
ロック解除時、システムカーソルは ユーザーエージェント ウィンドウを出入りできる。その際、ユーザーエージェント がOSのマウス移動イベントのターゲットでなかった場合、最新のポインタ位置は ユーザーエージェント で不明となり、
movementX
/ movementY
は算出できず、0に設定されなければならない。
ポインタロックが有効なとき、clientX
、clientY
、screenX
、screenY
は、ポインタロックに入った時点からポインタが全く動いていないかのように一定値を保持しなければならない。しかし movementX
および
movementY
は、ロック解除時と同様にポインタの位置変化量を提供し続けなければならない。マウスが一方向へ継続して動かされた場合、movementX
および movementY
の値に制限はない。マウスカーソルの概念がなくなり、ウィンドウ外や画面端で制限されることもない。
movementX
および movementY
の未初期化時の値は
0
でなければならない。
マウス入力が中断された場合(たとえば、マウスカーソルがウィンドウを離れて別の場所から再び入る場合など)に、大きな movement 値が出てはならない。ユーザーエージェント
がOSからのマウス入力データの受信にギャップを経験した場合、次に生成される mousemove
イベントの movementX
および movementY
は 0
に設定されなければならない。たとえば、ユーザーエージェント
がウィンドウシステムAPIでマウス離脱イベントを受信した場合などである。例外として、マウスキャプチャによりカーソルがウィンドウ外に出ても ユーザーエージェント がマウスイベントを受け取り続けることができる場合がある。
WebIDLpartial dictionary MouseEventInit {
double movementX
= 0;
double movementY
= 0;
};
movementX
メンバー
movementY
メンバー
movementX
および movementY
の各メンバーは、それぞれ MouseEvent
の対応するメンバーを初期化するために使用されます。
デフォルト解除ジェスチャーは常に利用可能でなければならず、ポインターロックの解除を ユーザーエージェントの pointer-lock target で行うことができなければならない。
pointer-lock target が 切断されるか、ユーザーエージェント・ウィンドウ・タブのいずれかがフォーカスを失った場合、ポインタロックは解除されなければならない。アクティブドキュメント内の要素間や、ブラウジングコンテキスト間でフォーカスを移動しても、pointer lock は解除されない。例えば、キーボード操作でフレームやiframeの内容間でフォーカスを移動しても解除されない。
フルスクリーン[FULLSCREEN]が開始または終了した際、ユーザーエージェントのグラフィカルユーザーインターフェース操作にポインターが必要な場合、デフォルト解除ジェスチャーによって両方を解除した場合、またはウィンドウやタブのフォーカスが失われた場合を除き、ポインターロックは解除してはならない。
このセクションは規範的ではありません。
一人称/三人称ゲームのプレイヤーは、ビューポートの向きを制御する必要があります。広く使われている方法は、マウス操作による視点の角度制御です。この種のアプリケーションは、Pointer Lock APIを利用することで、ユーザーがマウスボタンを押していなくてもビューポートのヨーやピッチを完全に自由に制御できます。マウスボタンは他のアクションにも利用でき、マウス移動によるナビゲーションが常に提供されます。
三次元モデリングアプリケーションの利用者は、モデルを回転させる必要があります。アプリケーションはPointer Lock APIを使うことで、ドラッグ操作中に制限なくモデルを自由に回転させることができます。ポインターロックがなければ、ドラッグは画面端でカーソル位置が制限されることで動作が止まります。
同様に、二次元画像の絶対的なパンも、カーソルや画面の制限なく一回のドラッグ操作で可能となります。
反射神経が要求されるゲームでは、プレイヤーがパドルを操作してボールを相手に返します。同じパドルで、異なるマウスボタンの押下によって様々なアクションを実行できます。アプリケーションはPointer Lock APIを使うことで、カーソルがゲームプレイ領域から外れて他のアプリケーションをクリックしてしまい、ゲームの流れが途切れることを心配せずに素早い反応を可能にします。
アプリケーションで数値を変更する際、ユーザーは数値コントロールのボタンハンドルをドラッグして数値を増減したいことがあります。例えば、数値入力ボックスと上下の矢印があるスピナーで、クリックやドラッグで値を変更できます。アプリケーションはPointer Lock APIを使うことで、論理的な画面境界を超えて数値を変更できるようになります。同様に、ビデオやオーディオの「ジョグ」コントロールにも適用できます。
一部のゲームでは従来型カーソルを利用しますが、カーソルをゲーム領域に限定したり、ゲーム側で操作したい場合があります。ポインターロックを使えば、アプリケーションが独自のカーソルを作成し、それを制御できます。ただしHTMLとDOMはUIとして利用可能でなければなりません。アプリケーション独自カーソルがDOMとやり取りできるよう、合成マウスイベントも許可されるべきです。例えば、次のコードでポインターロック中にカスタムカーソルからクリックイベントを送信できます:
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);
});
合成クリックは、ユーザーエージェントによって、非合成クリックと同じデフォルト動作が許可されない場合がありますが、アプリケーション側のハンドラは既存のHTMLやDOMの仕組みでUIを提供できます。
リアルタイムストラテジーゲームでは、この手法がよく使われます。プレイヤーがポインターをビューポートの端に動かし、マウス操作で端を「押す」と、マウスの動きに応じてゲーム領域上でビューポートがパンされます。ビューポート内でカーソルを動かす場合は、通常のシステム動作になります。アプリケーションは、ポインターロックと前述の「HTML DOM UIとの合成カーソル操作」を使い、カーソル動作を完全に制御することもできます。
ポインタロックを利用するゲームでは、プレイヤーがゲームロビーで準備している間は従来のUIやシステムカーソルを望む場合があります。ゲームは通常、全てのプレイヤーが準備完了した後、短いタイマーの後に開始されます。理想的には、その後ゲームが ユーザーアクティベーション なしでポインタロックモードへ切り替えられると良いでしょう。 プレイヤーはシームレスにゲームロビーからゲーム内ナビゲーションへ移行できるべきです。
ゲームポータルやFacebook、Google Plusなどのサイトは、ユーザー向けにゲームを提供しています。これらのゲームは、ポータルサイトとは異なるオリジンから配信される場合があります。埋め込みゲームは、フルスクリーンでなくてもポインターロックを利用できるべきです。
このセクションは規範的ではありません。
セキュリティ上の懸念点:
対策:
推奨事項:
ポインターロックは特定のアプリケーションタイプに必須のユーザー操作モードですが、悪意ある利用の場合はユーザビリティ上の懸念があります。攻撃者はユーザーがシステム上のマウスカーソルを操作できなくすることも可能です。ユーザーエージェントは、必ず解除手段を提供し、解除方法を案内し、ポインターロックの開始方法を制限することで、これを防ぎます。
ユーザーエージェントは、端末ごと・ユーザー設定ごとに適切なポリシーを独自に決定します。
このセクションは規範的ではありません。
Mouse Capture[MDN-SETCAPTURE]は、マウスドラッグ中のみ低リスクでマウスイベントターゲットのロックを行います。ポインターロックはカーソルの概念を消し、すべてのイベントを指定ターゲットに送ります。両者は関連していますが異なる機能です。
両方を実装する場合、「マウスボタン離しで自動解除」というセキュリティのシンプルさと、マウス入力を完全制御・カーソル非表示という機能拡張の組み合わせが合理的です。短時間だけドラッグ中ポインターロックする用途には、より許容的な利用が可能になります。
本仕様の初期バージョンでは、この機能は省略されています。ウィンドウモードの一部小さなユースケースには有用ですが、主要ユースケースにはまだ十分な実装がありません。実装には両方のAPIが必要ですが、現時点で両方を実装しているブラウザはありません。また、この機能が.lockと.setCaptureのどちらに属するかも未定です。どちらも実装されれば、どちらのAPIも簡単に拡張してハイブリッド機能を提供できます。
ロックされていない状態でも、マウス移動のデルタ値は有用です。ロック状態によって.clientや.screenの意味を変更すると、ロック状態を十分に考慮しないコードで簡単にエラーが生じます。
ポインターロック中は 'wheel' イベントも pointer-lock target 要素に送るべきです。しかし .deltaX/Y/Z は DOM 3 'wheel' イベントで定義済みの名前と競合するためです。
より細やかな制御を提供する動機は十分あります。例えば「ビューポート境界へのマウスカーソル移動によるパン」ユースケースは、カーソル非表示は不要で、境界制限と常時デルタ値だけが必要です。また、この仕様はマウスカーソルの動きに基づいたmovement deltasを定義していますが、これはOSによるフィルタリングや加速が含まれます。アプリケーションは、マウスカーソル向け調整前のより生の移動データを取得したい場合があります。生データはピクセル以上の精度や高頻度更新も可能です。生のデルタ取得には特別な許可やモードが不要で、カーソルの境界制限不要なアプリにはセキュリティ障壁やプロンプトを減らせます。
この細粒度のアプローチを延期する理由は2つあります。第一は、マウス移動データの単位をどう規定するかという懸念です。本仕様は.movementX/Yを、ロックされていない時の.screenX/Yの変化値とまったく同じ値として定義しています。これにより、複数のユーザーエージェントやOS間でも、アプリ開発者と利用者に一貫した体験を提供できます。さらに、ユーザーはすでにハードウェア入力やOSの設定を好みに調整済みであり、.movementX/Yの単位を同じにすることで、APIアプリがすぐ使えるようになります。
第二に、細粒度アプローチで移動データの提供とカーソルの境界制限を実装するのはより困難です。機能をまとめることで、各OSに応じた様々な技術を自由に使える実装が可能となり、実装面でも現実的です。主要なデスクトッププラットフォーム(Windows、Mac OS X、Linux)には、カーソルを特定矩形に制限する直接APIがなく、Xlibによる不可視ウィンドウやMacの手動カーソル移動の試作も未開発です。未調整デルタ値は生のHIDデータ読み取り(例:WindowsのWM_INPUT、Mac OS X/LinuxのUSBデバイスAPI)で提案されていますが、単位の解釈と正規化が課題です。さらに、これまで検討されたAPIはUSBデバイスに限られます。
将来的にこれらの機能追加は妥当であり、現行のポインターロックAPIは細粒度のデルタや境界制限が実装されても簡単に拡張できます。
現仕様は、実装の現実性・要求ユースケースへの対応・将来改善との衝突回避のため、バンドル型APIを採用しています。
まだ対応していません。理由は前問「すべての機能(カーソル非表示、マウスデルタの提供)をまとめている理由(CSSでカーソルを非表示にしたり、常にデルタ値を提供したり、カーソル移動をウェブページの一部に制限するAPIを提供するのではなく)」と同じです。
ポインターロック中も多くのマウスイベント(クリック、mousedownなど)は有効です。これらはMouseEventという同じイベントデータ構造を共有します。移動データを新しいデータ構造で報告する場合、新しいイベントが必要となり、ボタンや修飾キー状態などの利便性もMouseEventと並ぶ構造が必要です。クリックやdown/upイベントは既存のmousedown/mouseupを使うのか?その場合.clientX/Yや.screenX/Yは有用なデータを持たず、現在の移動データも含まれません。あるいはロック時用に新しいイベントが必要になります。
また、movementX/Yはマウスロックしていない時でも便利です。本仕様は、マウスカーソルが存在する場合でもmovement属性が常に有効であることを求めます。これにより、アプリがマウスデルタを利用する場合、カーソル状態やmouseover/mouseout遷移の追跡コードを削減できます。
唯一のデメリットは、ロック中にclientX/YとscreenX/Y値が未使用になることですが、これは重大な問題ではありません。
よって、MouseEventへのmovementX/Y追加という最小限の変更が、APIと実装の複雑さを減らすために選択されています。
例えば、ユーザーがテキストコンソールでチャットしながら、マウス操作で3Dビューを制御するゲームを考えてみましょう。アプリケーションがマウスイベントの送信先とテキスト入力先を異なる要素に分けて受け付けるのは合理的です。これは、ページ上の任意要素でmousemoveイベントを受け取る一方で、フォーム入力を行う既存の動作と同様です。
非規範的と明記されたセクションだけでなく、この仕様書のすべての執筆ガイドライン、図、例、注記も非規範的です。それ以外はすべて規範的です。
この仕様は、ひとつの製品、すなわち本仕様に含まれるインターフェースを実装するユーザーエージェントに適用される適合性基準を定義します。
このセクションは規範的ではありません。
この仕様の議論に貢献してくださった多くの方々に感謝します:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: