Copyright © 2025 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
この仕様の機能は Pointer Events(マウス・ペン・タッチスクリーンなどのデバイスからのハードウェア非依存なポインター入力を扱うイベントと関連インターフェイスを記述した W3C 勧告)に含まれる機能を拡張または変更する。既存のマウスベースのコンテンツとの互換性を確保するため、本仕様は他のポインターデバイス種別に対してマウスイベントを発火させるマッピングも記述する。
このセクションは本書が公開された時点でのステータスを記述する。現在の W3C の出版物一覧およびこの技術報告書の最新改訂版は W3C Standards and Drafts Index に掲載されている。
本仕様は [PointerEvents3] の更新版であり、編集上の明確化と、より多くのユースケースを容易にする新機能を含む。
この文書は Pointer Events Working Group により 勧告トラック を用いた作業草案 (Working Draft) として公開された。
Working Draft としての公開は W3C およびその会員による支持を意味しない。
これは草案文書であり、いつでも更新・置換・廃止される可能性がある。 進行中の作業以外として引用するのは不適切である。
この文書は W3C 特許ポリシー の下で活動するグループにより作成された。 W3C は 関連する特許開示の公開リスト を、グループの成果物に関連して維持している。そのページには特許開示の手続きも記載されている。特許の 必須クレーム (Essential Claim) を含むと考える特許について実際に知識を有する個人は、W3C 特許ポリシー第 6 節 に従って情報を開示しなければならない。
この文書は 2025年8月18日付 W3C プロセス文書 によって管理される。
このセクションは参考であり、規範的ではない。
現在、ほとんどの [HTML] コンテンツはマウス入力で利用されるか、マウス入力向けに設計されている。入力をカスタム処理するものは、典型的に [UIEVENTS] のマウスイベントへコードを書く。しかし近年のコンピューティングデバイスはタッチスクリーンやペン入力など他の形態の入力を取り込んでいる。これら各入力形態を個別に扱うイベント型が提案されてきたが、その手法は新しい入力タイプを追加する際に不要なロジック重複やイベント処理オーバーヘッドを招くことが多い。これは、コンテンツが単一のデバイスタイプのみを想定して書かれた場合に互換性問題を生じさせる。また既存のマウスベースコンテンツとの互換性のため、ほとんどの ユーザーエージェント はすべての入力タイプに対してマウスイベントを発火する。これにより、マウスイベントが実際のマウスデバイスなのか互換性のため他の入力タイプから生成されたものなのかが曖昧になり、両方のデバイスタイプへ同時にコードを書くことが難しくなる。
複数入力タイプへのコーディングコストを下げ、さらに上記のマウスイベントに関する曖昧さを解消するために、本仕様は ポインター と呼ばれるより抽象的な入力形態を定義する。ポインターはマウスカーソル、ペン、タッチ(マルチタッチ含む)その他のポイント入力デバイスによる画面上の任意の接触点であり得る。このモデルは、ユーザーがどのようなハードウェアを持っていても適切に機能するサイトやアプリケーションの作成を容易にする。デバイス固有の処理が望まれるシナリオでは、この仕様はイベントを生成したデバイスタイプを検査するためのプロパティも定義する。主な目的はクロスデバイスのポインター入力に対する記述を容易にする単一のイベントセットとインターフェイスを提供しつつ、拡張された体験が必要な場合にのみデバイス固有処理を可能にすることである。
追加の重要な目的は、マルチスレッドなユーザーエージェントが、スクリプト実行によってブロックされることなくパン/ズーム(例えばタッチスクリーンで指やスタイラスによる)用の 直接操作 アクションを処理できるようにすることである。
本仕様が多様なポインター入力に対して統一イベントモデルを定義している一方で、このモデルはキーボードやキーボードに類するインターフェイス(例:タッチスクリーンのみのデバイス上で動作し、フォーカス可能なコントロールや要素間を逐次的にナビゲート可能にするスクリーンリーダー等の支援技術)などの他の入力形態は対象としない。ユーザーエージェントがこれらインターフェイスへの応答としてポインターイベントを生成する選択を行う可能性はあるが、このシナリオは本仕様では扱わない。
第一に、著者は focus、blur、click
といった高レベルイベントに応答することで全ての入力形態に同等の機能を提供することが推奨される。しかし低レベルイベント(Pointer Events
など)を用いる際は、すべての入力タイプがサポートされることを確保するよう推奨される。キーボードおよびキーボード類似インターフェイスの場合、明示的なキーボードイベント処理を追加する必要があるかもしれない。詳細は
Keyboard Accessible [WCAG22] を参照。
汎用ポインター入力を扱うイベントはマウスのイベントに非常によく似ている: pointerdown、
pointermove、pointerup、pointerover、pointerout
など。このことはマウスイベントからポインターイベントへのコンテンツ移行を容易にする。ポインターイベントはマウスイベントに存在する通常のプロパティ(クライアント座標、ターゲット要素、ボタン状態など)に加え、圧力・接触ジオメトリ・傾きなど他の入力形態向けの新しいプロパティを提供する。著者は、妥当な箇所で異なる入力タイプ間でロジックを共有し、最良の体験のために必要な場合のみ特定入力タイプ向けにカスタマイズするコードを容易に記述できる。
ポインターイベントは多様な入力デバイスから供給されるが、他のデバイス固有イベント集合から生成されるものとして定義されているわけではない。互換性のために可能かつ推奨されるものの、この仕様は他のデバイス固有イベント(マウスイベントやタッチイベントなど)のサポートを要求しない。ユーザーエージェントは他のデバイスイベントを全くサポートせずにポインターイベントのみをサポートできる。マウス固有イベントに書かれたコンテンツとの互換性のために、この仕様は、マウス以外のデバイスからのポインター入力に基づき 互換マウスイベント を生成する方法を記述する任意セクションを提供する。
この仕様は、[TOUCH-EVENTS] で定義されるタッチイベントとポインターイベントの両方をサポートするユーザーエージェントに期待される挙動について助言を提供しない。これら 2 つの仕様の関係についての詳細は Touch Events Community Group を参照。
非規範的と記されたセクションに加え、この仕様書におけるすべての著者向けガイドライン、図、例、そして注記は非規範的である。その他の全ては規範的である。
この文書におけるキーワード MAY、MUST、MUST NOT、OPTIONAL、SHOULD は BCP 14 [RFC2119] [RFC8174] に従い、ここに示すようにすべて大文字で現れる場合のみ解釈される。
このセクションは参考であり、規範的ではない。
以下は著者が本仕様の API の一部をどのように使用し得るかを示す基本的な例である。さらに具体的な例は本書の該当セクションに示される。
/* Bind to either Pointer Events or traditional touch/mouse */
if (window.PointerEvent) {
// if Pointer Events are supported, only listen to pointer events
target.addEventListener("pointerdown", function(e) {
// if necessary, apply separate logic based on e.pointerType
// for different touch/pen/mouse behavior
...
});
...
} else {
// traditional touch/mouse event handlers
target.addEventListener('touchstart', function(e) {
// prevent compatibility mouse events and click
e.preventDefault();
...
});
...
target.addEventListener('mousedown', ...);
...
}
// additional event listeners for keyboard handling
...
window.addEventListener("pointerdown", detectInputType);
function detectInputType(event) {
switch(event.pointerType) {
case "mouse":
/* mouse input detected */
break;
case "pen":
/* pen/stylus input detected */
break;
case "touch":
/* touch input detected */
break;
default:
/* pointerType is empty (could not be detected)
or UA-specific custom type */
}
}
<div style="position:absolute; top:0px; left:0px; width:100px;height:100px;"></div>
<script>
window.addEventListener("pointerdown", checkPointerSize);
function checkPointerSize(event) {
event.target.style.width = event.width + "px";
event.target.style.height = event.height + "px";
}
</script>
const event1 = new PointerEvent("pointerover",
{ bubbles: true,
cancelable: true,
composed: true,
pointerId: 42,
pointerType: "pen",
clientX: 300,
clientY: 500
});
eventTarget.dispatchEvent(event1);
let pointerEventInitDict =
{
bubbles: true,
cancelable: true,
composed: true,
pointerId: 42,
pointerType: "pen",
clientX: 300,
clientY: 500,
};
const p1 = new PointerEvent("pointermove", pointerEventInitDict);
pointerEventInitDict.clientX += 10;
const p2 = new PointerEvent("pointermove", pointerEventInitDict);
pointerEventInitDict.coalescedEvents = [p1, p2];
const event2 = new PointerEvent("pointermove", pointerEventInitDict);
eventTarget.dispatchEvent(event2);
<div style="position:absolute; top:0px; left:0px; width:100px;height:100px;"></div>
<script>
window.addEventListener("pointerdown", assignPenColor);
window.addEventListener("pointermove", assignPenColor);
const colorMap = new Map();
function assignPenColor(event) {
const uniqueId = event.persistentDeviceId;
// Check if a unique Id exists.
if (uniqueId == 0) {
return;
}
// Check if a color has been assigned to the device.
if (map.has(uniqueId)) {
return;
}
// Assign a color to the device.
let newColor = getNewColor();
map.set(uniqueId, newColor);
return newColor;
}
function getNewColor() {
/* return some color value */
}
</script>
WebIDLdictionary PointerEventInit : MouseEventInit {
long pointerId = 0;
double width = 1;
double height = 1;
float pressure = 0;
float tangentialPressure = 0;
long tiltX;
long tiltY;
long twist = 0;
double altitudeAngle;
double azimuthAngle;
DOMString pointerType = "";
boolean isPrimary = false;
long persistentDeviceId = 0;
sequence<PointerEvent> coalescedEvents = [];
sequence<PointerEvent> predictedEvents = [];
};
[Exposed=Window]
interface PointerEvent : MouseEvent {
constructor(DOMString type, optional PointerEventInit eventInitDict = {});
readonly attribute long pointerId;
readonly attribute double width;
readonly attribute double height;
readonly attribute float pressure;
readonly attribute float tangentialPressure;
readonly attribute long tiltX;
readonly attribute long tiltY;
readonly attribute long twist;
readonly attribute double altitudeAngle;
readonly attribute double azimuthAngle;
readonly attribute DOMString pointerType;
readonly attribute boolean isPrimary;
readonly attribute long persistentDeviceId;
[SecureContext] sequence<PointerEvent> getCoalescedEvents();
sequence<PointerEvent> getPredictedEvents();
};
pointerIdイベントを発生させたポインターを一意に識別する ID。ユーザーエージェントはプライマリマウスポインター用に一般的な pointerId
値 0 もしくは 1 を予約しても MAY。値 -1
はポインティングデバイス以外から生成されたイベントを示すために予約され MUST。その他のポインターについては UA は任意の戦略で
pointerId
を割り当てられる。全ての アクティブポインター
はトップレベル閲覧コンテキスト内で一意であり、他のトップレベル閲覧コンテキストによって影響されては MUST
NOT(他コンテキストへ移動しても同一値を仮定できない)。
ユーザーエージェントは過去に失効した値を再利用する MAY、あるいは特定デバイス(例: 個別のペン/スタイラス)識別目的に常に同じ pointerId を再利用する MAY。ただし後者でも異なるページ/ドメイン間でのフィンガープリント・トラッキングを避けるため、その関連付けはページ/セッション存続期間に限り
MUST、新しいセッションでは新たにランダム化された pointerId を選択 MUST。
pointerId
の選択アルゴリズムは実装依存であり、著者は値に特別な意味があると仮定すべきでない。例として UA が単にアクティブ化順に 0
から付与しても単調増加は保証されない。特定デバイスに同一 pointerId
を再利用するかは実装次第であるため依存は避け、代わりに persistentDeviceId
を参照することが強く推奨される。
widthポインターの 接触ジオメトリ の X 軸方向の幅(CSS ピクセル、[CSS21])。値はイベント毎に更新される
MAY。接触ジオメトリを持たない入力(従来型マウス等)またはハードウェアが検出しない場合、UA は既定値 1
を返す MUST。
heightポインターの 接触ジオメトリ の Y 軸方向の高さ(CSS ピクセル)。値はイベント毎に更新される MAY。接触ジオメトリ非検出時、UA は 1 を返す MUST。
pressureポインター入力の正規化圧力(範囲 [0,1])。0 および 1
はハードウェアが検出可能な最小・最大圧力。圧力非対応ハード/プラットフォームでは active
buttons state 中は 0.5、それ以外は 0 とする MUST。
tangentialPressure追加コントロール(例: エアブラシスタイラスのフィンガーホイール)で設定される正規化接線圧(バレル圧)。範囲 [-1,1] で 0
が中立。ハードにより [0,1] のみの場合もある。非対応ハードでは値 0 MUST。
tiltXY-Z 平面とトランスデューサ(例: ペン/スタイラス)軸および Y 軸を含む平面との角度(度、範囲 [-90,90])。正の
tiltX は右方向(X 増加方向)。tiltY と組み合わせて傾きを表現可能。傾き未報告の場合値は 0
MUST。
tiltX。
tiltYX-Z 平面とトランスデューサ軸および X 軸を含む平面との角度(度、範囲 [-90,90])。正の tiltY は利用者側(Y
増加方向)。傾き未報告の場合値は 0 MUST。
tiltY。
twistトランスデューサ(例: ペン/スタイラス)主要軸周りの時計回り回転角(度、範囲 [0,359])。未報告時は 0 MUST。
altitudeAngleトランスデューサの高度(ラジアン、範囲 [0,π/2])。0 は表面(X-Y 平面)と平行、π/2
は垂直。傾き未報告時は π/2 MUST。
altitudeAngle = π/4(X-Y 平面から 45 度)。azimuthAngleトランスデューサの方位角(ラジアン、範囲 [0, 2π])。0 は X 増加方向(真上から見て 3
時方向)。時計回りに増加(π/2 が 6 時、π が 9 時、3π/2 が 12
時)。トランスデューサが完全に垂直(altitudeAngle = π/2)なら値は 0 MUST。未報告時も 0 MUST。
azimuthAngle = π/6(4 時方向)。pointerTypeイベントを発生させたデバイスタイプ(mouse, pen, touch)を示す。UA がマウス・ペン/スタイラス・タッチ入力のポインタイベントを 発火 する場合、pointerType の値は下表に従う
MUST。
| ポインターデバイスタイプ | pointerType 値 |
|---|---|
| Mouse | mouse |
| Pen / stylus | pen |
| Touch contact | touch |
デバイスタイプを検出できない場合は空文字列 MUST。上記以外のタイプをサポートする場合は衝突回避のためベンダープレフィックス化 SHOULD。今後の仕様で追加の標準値が定義される可能性がある MAY。
isPrimaryこのポインターが該当 ポインタータイプのプライマリポインター かどうか。
persistentDeviceIdポインティングデバイスの一意識別子。ハードウェアが複数ポインターをサポートし、それらがセッションを通じ一意識別可能な場合のみ
persistentDeviceId を割り当てる MUST。識別不能なイベントには値
0 を用いる MUST。pointerId
と同様、フィンガープリント回避のためセッション単位でのみ関連付け MUST、新セッションではランダム化された新しい値を選択 MUST。
pointerdown 時点では報告されず一時的に
0 で後に有効値へ変わる場合がある。
getCoalescedEvents()合成(coalesced)イベント のリストを返すメソッド。
getPredictedEvents()予測(predicted)イベント のリストを返すメソッド。
PointerEventInit 辞書は PointerEvent
コンストラクタによる信頼されない(合成)ポインタイベント生成のための仕組みを提供する。MouseEventInit
を継承。[UIEVENTS] 参照。例は examples を参照。
イベント構築手順 は PointerEvent に対して PointerEventInit の coalescedEvents を 合成イベントリスト に複製し、PointerEventInit の predictedEvents を 予測イベントリスト に複製する。
PointerEvent は MouseEvent を継承し UI
Events で定義される。CSSOM View Module における座標型を
long から double へ拡張する提案にも注意。PointerEvent のみ拡張し通常の MouseEvent を拡張していない UA では
click,
auxclick, contextmenu に追加要件が生じる。
マルチポインター(例: マルチタッチ)シナリオでは、各ポインタータイプの集合内で isPrimary によりアクティブポインターのマスターを識別する。
isPrimary=false となる MAY。ポインタイベントを発火するとは、名前 e のイベントを fire an event し、その属性を PointerEvent インターフェイスおよび Attributes and Default Actions
に従って設定することを意味する。
イベントが gotpointercapture、lostpointercapture、click、auxclick、contextmenu
でない場合、この PointerEvent について 保留中ポインターキャプチャ処理 手順を実行する。
ターゲット決定 手順:
ターゲットの node document を targetDocument とする [DOM]。
イベントが pointerdown、pointermove、pointerup のいずれかなら、そのイベントの active document を targetDocument に設定。
イベントが pointerdown で、関連デバイスが直接操作型かつターゲットが Element の場合、set pointer capture をそのターゲット要素へ適用(暗黙的ポインターキャプチャ参照)。
発火前に ユーザーエージェント は
previousTarget からターゲットへポインターが移動したかのように扱う SHOULD([UIEVENTS] の event ordering
参照)。needsOverEvent フラグが立っている場合、ターゲット要素が同一でも pointerover が必要。
決定されたターゲットにイベントを発火。
そのターゲットを当該ポインターの previousTarget として保存し、needsOverEvent を false
にリセット。previousTarget が非接続状態になった場合はイベントパスに沿い接続中の最近接の親へ更新しフラグを true に設定。
本仕様で定義されるイベント型の bubbles / cancelable と既定動作は下表の通り。各イベント型の詳細は Pointer Event types を参照。
| イベント型 | Bubbles | Cancelable | 既定動作 |
|---|---|---|---|
pointerover |
Yes | Yes | なし |
pointerenter |
No | No | なし |
pointerdown |
Yes | Yes | 変動(プライマリ時は mousedown の全既定動作)キャンセルすると後続の 互換マウスイベント 発火を阻止。 |
pointermove |
Yes | Yes | 変動(プライマリ時は mousemove の既定動作) |
pointerrawupdate |
Yes | No | なし |
pointerup |
Yes | Yes | 変動(プライマリ時は mouseup の既定動作) |
pointercancel |
Yes | No | なし |
pointerout |
Yes | Yes | なし |
pointerleave |
No | No | なし |
gotpointercapture |
Yes | No | なし |
lostpointercapture |
Yes | No | なし |
ビューポート操作(パン/ズーム)は一般に 直接操作 に起因するもので、意図的に pointer
イベントの既定動作ではない。つまりこれらの挙動(例: タッチ移動によるページパン)はイベントキャンセルで抑止できない。著者は代わりに touch-action
を用いて文書領域に対し 直接操作挙動
を明示的に宣言する必要がある。イベントキャンセル依存を除去することで UA は性能最適化を実施しやすくなる。
pointerenter および pointerleave では composed
[DOM] 属性は false とする SHOULD。その他のポインターイベントでは true とする SHOULD。
上記全ポインターイベントで detail [UIEVENTS] 属性は 0 とする SHOULD。
fromElement / toElement を
MouseEvents に公開する。PointerEvents ではこれら継承属性を null に設定し、標準属性(target と
relatedTarget)使用へ移行させることが望ましい。
pointerover/pointerenter では relatedTarget
を離脱元要素に、pointerout/pointerleave では進入先要素に初期化。それ以外は
null。要素がポインターキャプチャを取得した後のイベントはキャプチャ要素境界内とみなす。
gotpointercapture と lostpointercapture
イベントでは、上表で定義された属性以外はユーザーエージェントが 保留中ポインターキャプチャ処理 を実行しこれらイベントを発火させた元の
Pointer Event と同一であるべき。
ユーザーエージェント は 暗黙的キャプチャ解除 時および gotpointercapture/lostpointercapture 以外の Pointer Event
発火時に以下手順を実行 MUST。
lostpointercapture を発火。gotpointercapture を発火。click,
auxclick, contextmenu の節で定義されるとおり、lostpointercapture 発火後でも対応する
click/auxclick/contextmenu
があればキャプチャターゲットへディスパッチされる。
ユーザーエージェント は特定の pointerId
で今後イベント受信が見込まれないと判断した場合、ポインタイベントストリームを抑制 MUST。以下のシナリオはいずれも条件を満たす(追加シナリオが存在し得る MAY)。
touch-action 参照。
その他 UA が user agent として MAY 抑制 するシナリオ例:
これら検出方法は仕様の範囲外。
ユーザーエージェント は ストリーム抑制 のため以下手順を実行 MUST:
pointercancel を発火。pointerout を発火。pointerleave を発火。スクリーン表面に対して移動またはプロパティ変化を起こしたポインターデバイスは Pointer Event types
で定義される各種イベントを発火する。移動やプロパティ変化の無い静止ポインターについてはレイアウト変更によりそのポインターの ヒットテスト 対象が変化した場合、UA は
pointerover、pointerenter、pointerout、pointerleave を発火 MUST。性能上の理由(過度なヒットテストやレイアウト計算回避)で遅延 MAY。
pointermove を発火しない。
Pointer Events はトランスデューサ(ペン等)の X-Y 平面に対する姿勢を表現する 2 組の属性を提供する:初期仕様からの
tiltX/tiltY と、Touch Events -
Level 2 から採用された azimuthAngle/altitudeAngle。
具体的なハードやプラットフォームにより UA はしばしば片方のセットのみ(tiltX/tiltY か
altitudeAngle/azimuthAngle のどちらか)を受け取る。UA は以下の変換アルゴリズムを使用 MUST。
UA が azimuthAngle/altitudeAngle から tiltX/tiltY
を算出する際、最終的な整数値は Math.round [ECMASCRIPT] により丸める SHOULD。
/* Converting between tiltX/tiltY and altitudeAngle/azimuthAngle */
function spherical2tilt(altitudeAngle, azimuthAngle) {
const radToDeg = 180/Math.PI;
let tiltXrad = 0;
let tiltYrad = 0;
if (altitudeAngle == 0) {
// the pen is in the X-Y plane
if (azimuthAngle == 0 || azimuthAngle == 2*Math.PI) {
// pen is on positive X axis
tiltXrad = Math.PI/2;
}
if (azimuthAngle == Math.PI/2) {
// pen is on positive Y axis
tiltYrad = Math.PI/2;
}
if (azimuthAngle == Math.PI) {
// pen is on negative X axis
tiltXrad = -Math.PI/2;
}
if (azimuthAngle == 3*Math.PI/2) {
// pen is on negative Y axis
tiltYrad = -Math.PI/2;
}
if (azimuthAngle>0 && azimuthAngle<Math.PI/2) {
tiltXrad = Math.PI/2;
tiltYrad = Math.PI/2;
}
if (azimuthAngle>Math.PI/2 && azimuthAngle<Math.PI) {
tiltXrad = -Math.PI/2;
tiltYrad = Math.PI/2;
}
if (azimuthAngle>Math.PI && azimuthAngle<3*Math.PI/2) {
tiltXrad = -Math.PI/2;
tiltYrad = -Math.PI/2;
}
if (azimuthAngle>3*Math.PI/2 && azimuthAngle<2*Math.PI) {
tiltXrad = Math.PI/2;
tiltYrad = -Math.PI/2;
}
}
if (altitudeAngle != 0) {
const tanAlt = Math.tan(altitudeAngle);
tiltXrad = Math.atan(Math.cos(azimuthAngle) / tanAlt);
tiltYrad = Math.atan(Math.sin(azimuthAngle) / tanAlt);
}
return {"tiltX":tiltXrad*radToDeg, "tiltY":tiltYrad*radToDeg};
}
function tilt2spherical(tiltX, tiltY) {
const tiltXrad = tiltX * Math.PI/180;
const tiltYrad = tiltY * Math.PI/180;
// calculate azimuth angle
let azimuthAngle = 0;
if (tiltX == 0) {
if (tiltY > 0) {
azimuthAngle = Math.PI/2;
}
else if (tiltY < 0) {
azimuthAngle = 3*Math.PI/2;
}
} else if (tiltY == 0) {
if (tiltX < 0) {
azimuthAngle = Math.PI;
}
} else if (Math.abs(tiltX) == 90 || Math.abs(tiltY) == 90) {
// not enough information to calculate azimuth
azimuthAngle = 0;
} else {
// Non-boundary case: neither tiltX nor tiltY is equal to 0 or +-90
const tanX = Math.tan(tiltXrad);
const tanY = Math.tan(tiltYrad);
azimuthAngle = Math.atan2(tanY, tanX);
if (azimuthAngle < 0) {
azimuthAngle += 2*Math.PI;
}
}
// calculate altitude angle
let altitudeAngle = 0;
if (Math.abs(tiltX) == 90 || Math.abs(tiltY) == 90) {
altitudeAngle = 0
} else if (tiltX == 0) {
altitudeAngle = Math.PI/2 - Math.abs(tiltYrad);
} else if (tiltY == 0) {
altitudeAngle = Math.PI/2 - Math.abs(tiltXrad);
} else {
// Non-boundary case: neither tiltX nor tiltY is equal to 0 or +-90
altitudeAngle = Math.atan(1.0/Math.sqrt(Math.pow(Math.tan(tiltXrad),2) + Math.pow(Math.tan(tiltYrad),2)));
}
return {"altitudeAngle":altitudeAngle, "azimuthAngle":azimuthAngle};
}
以下は本仕様で定義されるイベント型です。
プライマリポインター の場合、これらのイベント(gotpointercapture と lostpointercapture を除く)は 互換マウスイベント も発火する場合があります。
ユーザーエージェント
は以下のいずれかが発生したとき MUST 名称 pointerover の ポインタイベントを発火 する:
pointerdown を発火する前。ユーザーエージェント
は以下のいずれかが発生したとき MUST 名称 pointerenter の ポインタイベントを発火 する:
pointerdown を発火する前。mouseenter イベントや、[CSS21]
の CSS 擬似クラス
:hover と類似点があります。pointerleave も参照してください。
ユーザーエージェント はポインターが active buttons state に入ったとき MUST 名称 pointerdown の ポインタイベントを発火 する。マウスでは「全ボタン非押下」から「少なくとも1つ押下」への遷移。タッチでは
デジタイザ への物理接触。ペンではボタン非押下での接触、またはホバー中に非押下から押下への遷移。
pointerdown / pointerup が常に mousedown /
mouseup と同じ条件で発火するわけではない。詳細は 連動ボタン (chorded buttons) を参照。
ホバーを サポートしないデバイス の入力について、ユーザーエージェント は MUST pointer イベントを発火 し、pointerover に続けて pointerenter を pointerdown のディスパッチ前に行う。
isPrimary が
true のとき pointerdown をキャンセルすることで防止できる。これはそのポインターに
PREVENT MOUSE EVENT フラグを設定する。ただし
mouseover, mouseenter, mouseout, mouseleave
の発火は妨げない。
ユーザーエージェント は、pointerdown や pointerup を発火しない任意のプロパティが変化したとき MUST 名称 pointermove の ポインタイベントを発火 する。これには座標、pressure、tangential pressure、
tilt、twist、接触ジオメトリ(width と height)、または 連動ボタン の変更が含まれる。
ユーザーエージェントは性能上の理由などで pointermove のディスパッチを遅延しても MAY。合成イベント 情報は単一のディスパッチ済み pointermove に対する getCoalescedEvents
メソッドで公開される。最終座標はイベントのターゲット決定に使用する。
ユーザーエージェント は MUST ポインターが pointerdown / pointerup
を発火しないプロパティを変更した際、名称 pointerrawupdate の ポインタイベントを発火 し、かつそれを セキュアコンテキスト
内のみで行う。該当プロパティ一覧は pointermove を参照。
pointermove と対照的に、ユーザーエージェントは SHOULD pointerrawupdate
を可能な限り速く、JavaScript が処理可能な頻度でディスパッチする。
pointerrawupdate の target は、pointermove
が遅延・合成され得ることから異なる場合があり、合成イベントの最終位置によるターゲット決定と異なる可能性がある。
同じ pointerId の未ディスパッチ pointerrawupdate が既にイベントループ内にある場合、ユーザーエージェント は新しい pointerrawupdate を合成して新規 task を作成しないことが
MAY。これにより合成された複数の pointerrawupdate
が単一イベントの 合成イベント としてイベントループ処理時に配送される。詳細は getCoalescedEvents を参照。
pointerrawupdate と pointermove
の順序について、プラットフォームからの更新が両イベントの発火要因となる場合、ユーザーエージェント は MUST
対応する pointermove より前に pointerrawupdate をディスパッチする。
target を除き、最後にディスパッチされた pointermove 以降に配送されたすべての pointerrawupdate の合成イベントリスト連結は、次の pointermove の合成イベントと他属性に関して同一となる。pointerrawupdate の属性は主に pointermove と同じだが、cancelable は pointerrawupdate では false としなければならない MUST。
ユーザーエージェントは SHOULD 互換マウスイベント を pointerrawupdate に対しては発火しない。
pointerrawupdate
リスナー追加がページ性能へ悪影響を与える可能性がある。多くのユースケースでは他の pointer イベント型で十分。高頻度かつ高速処理が必要な場合のみ pointerrawupdate
リスナーを追加すべきで、その状況では他のポインターイベント型を監視する必要は概ねない。ユーザーエージェント はポインターが active buttons state から離脱したとき MUST 名称 pointerup の ポインタイベントを発火
する。マウスでは「少なくとも1ボタン押下」から「全ボタン非押下」への遷移。タッチでは デジタイザ
から物理接触が離れたとき。ペンではボタン非押下状態で接触が終了した、またはホバー中に「少なくとも1ボタン押下」から「全ボタン非押下」へ遷移したとき。
ホバーを サポートしないデバイス の入力では、ユーザーエージェント は MUST ポインタイベントを発火 し、pointerup の後に pointerout、続いて pointerleave をディスパッチする。
すべての pointerup イベントは pressure 値
0 を持つ。
ユーザーエージェント はポインターがキャプチャ中であれば MUST 暗黙的にポインターキャプチャを解除 する。
pointerdown / pointerup が常に mousedown /
mouseup と同一条件で発火するわけではない。詳細は 連動ボタン を参照。
ユーザーエージェント は ポインタイベントストリームを抑制 すべきシナリオを検出したとき MUST 名称 pointercancel の ポインタイベントを発火 する。
pointercancel の以下プロパティ値は、同じ pointerId
を持つ最後にディスパッチされたポインタイベントの値と一致する MUST: width,
height, pressure, tangentialPressure, tiltX,
tiltY, twist, altitudeAngle, azimuthAngle,
pointerType, isPrimary および [UIEVENTS]
から継承する座標。pointercancel の coalescedEvents と
predictedEvents リストは空である MUST。イベントの cancelable 属性は false
とする MUST。
ユーザーエージェント
は以下のいずれかが発生したとき MUST 名称 pointerout の ポインタイベントを発火 する:
ユーザーエージェント
は以下のいずれかが発生したとき MUST 名称 pointerleave の ポインタイベントを発火 する:
pointerup を発火した後(pointerup 参照)。ユーザーエージェント
は要素がポインターキャプチャを取得したとき MUST 名称 gotpointercapture の ポインタイベントを発火
する。このイベントはキャプチャを受ける要素で発火し、以降そのポインターのイベントはこの要素へ送られる。ポインターキャプチャ設定
および 保留中ポインターキャプチャの処理 節を参照。
ユーザーエージェント
はポインターのキャプチャが解除された後 MUST 名称 lostpointercapture の ポインタイベントを発火 する。このイベントはキャプチャ解除後の最初の後続イベントより前に MUST 発火される。発火場所はキャプチャが解除された要素。以降(click,
auxclick, contextmenu を除く)イベントは通常のヒットテスト機構でターゲット決定される。ポインターキャプチャ解除、暗黙的解除、保留中ポインターキャプチャ処理 を参照。
以下の節では既存の Element
インターフェイスに対する、ポインターキャプチャの設定と解除を容易にする拡張について記述します。
WebIDLpartial interface Element {
undefined setPointerCapture (long pointerId);
undefined releasePointerCapture (long pointerId);
boolean hasPointerCapture (long pointerId);
};
setPointerCapture()引数 pointerId
で識別されるポインターに対し、このメソッドが呼び出された要素へ ポインターキャプチャを設定
します。以降そのポインターのイベントでは、キャプチャ要素が常にヒットテスト結果を置き換えるかのように扱われ、キャプチャ解除まで MUST
常にこの要素がターゲットになります。ポインターが active buttons state
にない場合は、このメソッドは効果なく静かに失敗します。引数がいずれの active pointers にも一致しない場合は "NotFoundError" の DOMException を throw します。
releasePointerCapture()引数 pointerId
で識別されるポインターに対し、このメソッドが呼び出された要素から ポインターキャプチャを解除
します。以降そのポインターのイベントは通常のヒットテスト機構(本仕様の範囲外)に従ってターゲット決定されます。引数がいずれの active
pointers にも一致しない場合は "NotFoundError" の DOMException を throw します。
hasPointerCaptureこのメソッドが呼び出された要素が、引数 pointerId
で識別されるポインターの ポインターキャプチャ を持つかどうかを示します。具体的には、pending pointer capture target
override がその要素に設定されていれば true、そうでなければ false を返します。
setPointerCapture()
呼び出し直後に true を返しますが、その要素はまだ gotpointercapture
イベントを受け取っていません。そのため 暗黙的ポインターキャプチャ を pointerdown イベントリスナー内で検出するのに有用です。以下の節では、既存の GlobalEventHandlers
ミックスインに対する拡張を記述し、イベントハンドラ登録を容易にします。
WebIDLpartial interface mixin GlobalEventHandlers {
attribute EventHandler onpointerover;
attribute EventHandler onpointerenter;
attribute EventHandler onpointerdown;
attribute EventHandler onpointermove;
[SecureContext] attribute EventHandler onpointerrawupdate;
attribute EventHandler onpointerup;
attribute EventHandler onpointercancel;
attribute EventHandler onpointerout;
attribute EventHandler onpointerleave;
attribute EventHandler ongotpointercapture;
attribute EventHandler onlostpointercapture;
};
onpointeroverpointerover イベント型に対応します。
onpointerenterpointerenter イベント型に対応します。
onpointerdownpointerdown イベント型に対応します。
onpointermovepointermove イベント型に対応します。
onpointerrawupdatepointerrawupdate イベント型に対応します。
onpointeruppointerup イベント型に対応します。
onpointercancelpointercancel イベント型に対応します。
onpointeroutpointerout イベント型に対応します。
onpointerleavepointerleave イベント型に対応します。
ongotpointercapturegotpointercapture
イベント型に対応します。
onlostpointercapturelostpointercapture
イベント型に対応します。
属性と既定動作
で述べたように、ビューポートの操作(パンおよびズーム)はポインタイベントのキャンセルによって抑止することはできません。代わりに、著者は許可したい挙動と抑止したい挙動を
touch-action CSS プロパティを用いて宣言的に定義しなければなりません。
touch-action CSS プロパティはタッチ入力のみを指すように見えますが、実際にはパンとズームのための直接操作を許容するあらゆるポインター入力に適用されます。
| 名前: | touch-action |
|---|---|
| 値: | auto | none | [ [ pan-x | pan-left |
pan-right ] || [ pan-y | pan-up |
pan-down ] ] | manipulation
|
| 初期値: | auto |
| 適用対象: | 以下を除くすべての要素: 置換要素でないインライン要素、表の行、行グループ、表の列、列グループ |
| 継承: | no |
| パーセンテージ: | N/A |
| メディア: | visual |
| 算出値: | 指定値と同じ |
| 正規順序: | 文法による |
| アニメーションの種類: | アニメーション不可 |
touch-action CSS プロパティは、(プロパティ名に反してタッチに限定されない)直接操作の相互作用がユーザーエージェントのパンおよびズーム挙動を引き起こしてもよいか MAY を決定します。「touch-action
の値」を参照してください。
パンまたはズームを開始する直前に、ユーザーエージェント は、以下のすべての条件が真であれば MUST ポインタイベントストリームを抑制 します:
pointerdown イベントが送出済みである。pointerdown に続く pointerup または pointercancel イベントが、そのポインターに対してまだ送出されていない。
touch-action は、埋め込み閲覧コンテキストには適用/継承されません。例えば、<iframe> に
touch-action を適用しても、当該 <iframe> 内のパン/ズームに関する直接操作挙動には影響しません。
ユーザーがタッチやタッチスクリーン上のスタイラスなどの 直接操作ポインターで要素と相互作用するとき、その入力の効果は、
touch-action プロパティの値と、要素およびその祖先の既定の直接操作挙動によって、次のように決定されます。
touch-action に適合する とみなされます。CSS
変形が適用されている場合、ここでの適合性に影響する形で要素の座標空間が画面座標と異なることがある点に注意してください。例えば、画面に対して 90 度回転された要素の X 軸は、画面座標の Y
軸と平行になります。touch-action に適合する場合にサポートされます。
document 要素までの各要素の
touch-action に適合する場合にサポートされます。
touch-action
の値に対する変更はその操作の間は無視されます。例えば、pointerdown ハンドラ内のスクリプトで要素の
touch-action を auto から none
に変更しても、そのポインターがアクティブである間は、ユーザーエージェントがパンやズームを中止または抑止することにはなりません。
touch-action の pan-*
値の場合、ユーザーエージェントがジェスチャーの開始時にそれを直接扱うかどうかを決定した後、同一ジェスチャーの進行中に方向が変化しても、ポインターがアクティブな間はユーザーエージェントはそれを無視する
SHOULD です。例えば、要素に
touch-action: pan-y(ユーザーエージェントは垂直パンのみを扱う)を設定し、タッチジェスチャーが水平方向に開始した場合、ユーザーが指を離さずに途中で垂直方向に変えても、垂直パンは発生すべきではありません。
touch-action 値の処理や関連付けの方法は本仕様の範囲外です。
touch-action
プロパティは、ビューポートのパンおよびズームに関する直接操作挙動を対象とします。テキスト選択/ハイライト、リンクやフォームコントロールのアクティベーションといった追加のユーザーエージェント挙動は、この CSS
プロパティによって影響を受けては MUST NOT なりません。
auto や none の値に対する挙動のトリガーの定義は本仕様の範囲外です。
pan-x や
pan-y)では、パンの最中に軸を変更することはできない。
touch-action 値 は [COMPAT] で定義されています。方向固有の pan 値は、いくつかのオーバースクロール挙動をカスタマイズするのに有用です。
例えば、シンプルなプル・トゥ・リフレッシュを実装するには、ドキュメントの
touch-action をスクロール位置が 0 のとき pan-x pan-down に、それ以外では
pan-x pan-y に設定できます。
これにより、ドキュメント先頭から開始する上方向のパン/スクロールの挙動をポインタイベントハンドラで定義できます。
方向固有の pan 値は、ネイティブにスクロールする要素内で、ポインタイベント処理を用いたカスタムパンを実装するコンポーネント(またはその逆)を合成する場合にも使用できます。
例えば、画像カルーセルは pan-y を用いて、ドキュメントの垂直パンを妨げることなく、水平方向のパン操作に対するポインタイベントを確実に受け取れます。
カルーセルが最も右端に到達したら、touch-action を pan-y pan-right
に変更して、範囲外のその後のスクロール操作が可能であればビューポート内のドキュメントをスクロールできるようにします。
実行中のパン/スクロール操作の挙動を、その最中に変更することはできません。
auto
では、ダブルタップジェスチャーを処理できるよう、ユーザーエージェントは通常 click の前に 300ms
の遅延を追加します。このような場合、touch-action: none または
touch-action: manipulation
を明示的に設定することで、この遅延を取り除けます。なお、タップやダブルタップのジェスチャーを判別する手法は本仕様の範囲外です。
<div style="touch-action: none;">
この要素は、通常であればパンやズームにつながるすべての直接操作の相互作用についてポインタイベントを受け取ります。
</div>
<div style="touch-action: pan-x;">
この要素は、水平方向にパンしていない場合にポインタイベントを受け取ります。
</div>
<div style="overflow: auto;">
<div style="touch-action: none;">
この要素は、通常であればパンやズームにつながるすべての直接操作の相互作用についてポインタイベントを受け取ります。
</div>
<div>
この要素上の直接操作の相互作用は、親の操作に消費される <MAY> があります。
</div>
</div>
<div style="overflow: auto;">
<div style="touch-action: pan-y;">
<div style="touch-action: pan-x;">
この要素は、すべての直接操作の相互作用についてポインタイベントを受け取ります。なぜなら、
この要素は水平方向のパンのみを許可する一方で、
(スクロール可能要素との間にある)中間の祖先は垂直方向のパンのみを許可するためです。
その結果、ユーザーエージェントによって処理されるパン/ズームの直接操作挙動は存在しません。
</div>
</div>
</div>
<div style="overflow: auto;">
<div style="touch-action: pan-y pan-left;">
<div style="touch-action: pan-x;">
この要素は、左方向にパンしていない場合にポインタイベントを受け取ります。
</div>
</div>
</div>
この節は規範的ではありません。
ポインターキャプチャを用いると、特定ポインターのイベント(互換マウスイベント を含む)を、その位置の通常の ヒットテスト
結果とは別の特定要素へ再ターゲットできます。これはカスタムスライダー(例: [HTML]
<input type="range">
コントロールに類似)などのシナリオで有用です。スライダーのつまみ要素にポインターキャプチャを設定しておけば、ポインターがつまみから外れても値を前後にスライドさせられます。
pointerdown
が発生した後、ポインターキャプチャを使うことでポインターがつまみから外れてもスライド操作を継続できる。ポインターキャプチャは element(型 Element)上で
element.setPointerCapture(pointerId) メソッドを呼び出すことで設定されます。
このメソッドが呼び出されたとき、ユーザーエージェント
は以下の手順を MUST 実行します:
pointerId がいずれの アクティブポインター にも一致しない場合、"NotFoundError" の DOMException を throw する。pointerId が指定する
アクティブポインター とする。
InvalidStateError" の
DOMException を throw する。
pointerLockElement)がある場合、"InvalidStateError" の
DOMException を throw する。
pointerId について、保留中ポインターキャプチャターゲットオーバーライド をこのメソッドが呼び出された Element に設定する。
pointerdown リスナーで解除しようとして失敗する場合にも当てはまります。ポインターキャプチャは
element.releasePointerCapture(pointerId) メソッドを呼ぶことで要素上で明示的に解除されます。このメソッドが呼び出されたとき、ユーザーエージェント は以下の手順を MUST 実行します:
pointerId がいずれの アクティブポインター にも一致せず、かつこれらの手順が 暗黙的ポインターキャプチャ解除
の結果として呼び出されていないなら、"NotFoundError" の DOMException を throw する。pointerId に対する hasPointerCapture が false
なら、これ以降の手順を終了する。
pointerId について、設定されている場合は 保留中ポインターキャプチャターゲットオーバーライド をクリアする。
パンやズームのための 直接操作 インタラクション(タッチやタッチスクリーン上のスタイラスなど)を実装する入力は、任意の pointerdown リスナー呼び出し直前にターゲット要素上で setPointerCapture が呼ばれたかのように振る舞うべき SHOULD です。これが起きたかどうかは(例えば pointerdown リスナー内で)hasPointerCapture API
を使って判断できます。次のポインタイベントが発火する前にそのポインターに対して releasePointerCapture
が呼ばれなければ、キャプチャが有効であることを示す gotpointercapture
イベントがターゲットへ(通常通り)ディスパッチされます。
pointerup または pointercancel が発火した直後に、
ユーザーエージェント は、ディスパッチされたその pointerup または pointercancel イベントの pointerId に対する 保留中ポインターキャプチャターゲットオーバーライド をクリアし MUST、続いて 保留中ポインターキャプチャの処理
手順を実行し必要なら lostpointercapture を発火する。
その後 保留中ポインターキャプチャの処理
手順の実行後、ポインターがホバーをサポートする場合、ユーザーエージェントはキャプチャなしの現在位置を反映するための境界イベントを対応して送信 MUST。
ポインターキャプチャターゲットオーバーライド が 接続 されなくなった場合 [DOM]、 ポインターキャプチャターゲットオーバーライド はドキュメントに設定されるべき SHOULD。
保留中ポインターキャプチャターゲットオーバーライド が 接続 されなくなった場合 [DOM]、 保留中ポインターキャプチャターゲットオーバーライド ノードはクリアされるべき SHOULD。
lostpointercapture
イベントが、キャプチャノードが削除された後の次回の 保留中ポインターキャプチャ処理
にてドキュメントで発火される。
要素上でポインターロック [PointerLock] が成功裏に適用された場合、ユーザーエージェントはキャプチャ済みまたはキャプチャ保留の要素が存在するなら
releasePointerCapture
メソッドが呼ばれたかのように手順を実行する MUST。
性能上の理由から、UA はポインターの pointermove イベントを、ポインターの 測定可能プロパティ
(座標・圧力・接線圧力・傾き・ねじれ・接触領域など)が更新される度に必ず送らないことがあります。代わりに複数の変化を一つの pointermove または pointerrawupdate イベントへ合成(結合・統合)する可能性があります。これは
UA が行うイベント処理量を減らす助けになりますが、高速かつ大きな移動において位置追跡の粒度と忠実度を下げる結果になります。getCoalescedEvents
メソッドを用いることで、アプリケーションは未合成の生の位置変化にアクセスでき、より正確な処理が可能となります。例えばお絵描きアプリでは未合成イベントによって実際のポインター移動により近い滑らかな曲線を描画できます。
pointermove
イベントの合成済み座標(灰色)だけでは角ばった線になるが、getCoalescedEvents()
が提供するより細かな点(赤丸)を使うとより滑らかな近似になる。PointerEvent は関連付けられた 合成イベントリスト(0 個以上の PointerEvent のリスト)を持ちます。信頼できる pointermove および pointerrawupdate イベントでは、このリストは当該イベントへ合成されたすべての
PointerEvent の列です。親となる信頼できる pointermove / pointerrawupdate
イベントはこれら合成イベントの累積を表しますが(表示リフレッシュレート調整など)追加処理を含む場合があります。このためそれらのイベントの合成イベントリストは常に少なくとも 1
つのイベントを含みます。他の信頼できるイベント型では空リストです。非信頼イベントではコンストラクタに渡された値で初期化されます。
信頼できるイベントの合成イベントリスト内の各イベントは以下を持ちます:
timeStamp 値 [DOM]
— すべての合成イベントの timeStamp は、getPredictedEvents
が呼ばれたディスパッチ済みポインタイベントのそれ以下である。合成イベントリストは MUST 時系列順(最初が最小値)。pointerId / pointerType
/ isPrimary。<style>
/* パンやズームなど UA の直接操作内蔵挙動を無効化し、
キャンバス要素上の全イベントをアプリへ渡す */
canvas { touch-action: none; }
</style>
<canvas id="drawSurface" width="500px" height="500px" style="border:1px solid black;"></canvas>
<script>
const canvas = document.getElementById("drawSurface"),
context = canvas.getContext("2d");
canvas.addEventListener("pointermove", (e)=> {
if (e.getCoalescedEvents) {
for (let coalesced_event of e.getCoalescedEvents()) {
paint(coalesced_event); // 未合成ポイントをすべて描画
}
} else {
paint(e); // 最終合成ポイントのみ描画
}
});
function paint(event) {
if (event.buttons>0) {
context.fillRect(event.clientX, event.clientY, 5, 5);
}
}
</script>
ディスパッチされるすべてのイベント順序は元のイベントの実際の順序と一致しなければなりません MUST。
例えば pointerdown が合成済み pointermove イベントのディスパッチを引き起こす場合、UA はまず当該 pointerId のすべての合成イベントを含む一つの pointermove をディスパッチし、その後 pointerdown をディスパッチ MUST。
以下は増加する timeStamp
を持つ実際のイベントと UA がディスパッチするイベントの例です:
| 実際のイベント | ディスパッチされたイベント |
|---|---|
pointer (pointerId=2)
座標変化 |
pointerrawupdate (pointerId=2) /
合成イベント 1 件 |
pointer (pointerId=1)
座標変化 |
pointerrawupdate (pointerId=1) /
合成イベント 1 件 |
pointer (pointerId=2)
座標変化 |
pointerrawupdate (pointerId=2) /
合成イベント 1 件 |
pointer (pointerId=2)
座標変化 |
pointerrawupdate (pointerId=2) /
合成イベント 1 件 |
pointer (pointerId=1)
座標変化 |
pointerrawupdate (pointerId=1) /
合成イベント 1 件 |
pointer (pointerId=2)
座標変化 |
pointerrawupdate (pointerId=2) /
合成イベント 1 件 |
pointer (pointerId=1) ボタン押下
|
pointermove (pointerId=1) /
合成イベント 2 件pointermove (pointerId=2) /
合成イベント 4 件pointerdown (pointerId=1) /
合成イベント 0 件 |
pointer (pointerId=2)
座標変化 |
pointerrawupdate (pointerId=2) /
合成イベント 1 件 |
pointer (pointerId=2)
座標変化 |
pointerrawupdate (pointerId=2) /
合成イベント 1 件 |
pointer (pointerId=1) ボタン解放
|
pointermove (pointerId=2) /
合成イベント 2 件pointerup (pointerId=1) /
合成イベント 0 件 |
一部 UA には一連の確認済みポインター移動後に、(直前のジェスチャーイベントや速度/軌跡に基づいて)将来のポインター移動位置を予測できる組み込みアルゴリズムがあります。アプリケーションは getPredictedEvents
メソッドでこの情報を使い、予測位置へ先行描画して認知遅延を減らし、実際の点が到着したら予測点を破棄できます。
pointermove の合成座標と、UA
が予測した未来ポイント(灰色)を表示。PointerEvent には関連付けられた 予測イベントリスト(0 個以上の PointerEvent のリスト)があり、信頼できる pointermove イベントでは UA が今後続くと予測する
PointerEvent の列です。他の信頼できるイベント型では空リストです。非信頼イベントではコンストラクタに渡された値で初期化されます。
リスト内のイベント数や現在のタイムスタンプからの距離は UA と使用する予測アルゴリズムにより決定されます。
信頼できるイベントの予測イベントリスト内の各イベントは以下を持ちます:
timeStamp 値 [DOM]
— すべての予測イベントの timeStamp は、getPredictedEvents
が呼ばれたディスパッチ済みポインタイベントのそれ以上。リストは MUST 時系列順(先頭が最小)。pointerId / pointerType
/ isPrimary。著者は予測イベントを次のポインターイベントがディスパッチされるまでのみ有効な予測と見なすべきです。UA がどれほど先を予測するかによっては、通常のポインターイベントが一部予測イベントのタイムスタンプより早くディスパッチされる可能性があります。
let predicted_points = [];
window.addEventListener("pointermove", function(event) {
// 以前に描画した予測ポイントをクリア
for (let e of predicted_points.reverse()) {
clearPoint(e.pageX, e.pageY);
}
// 最後のイベント以降に起きた実際の移動を描画
for (let e of event.getCoalescedEvents()) {
drawPoint(e.pageX, e.pageY);
}
// 認知的遅延を減らすため現在の予測ポイントを描画
predicted_points = event.getPredictedEvents();
for (let e of predicted_points) {
drawPoint(e.pageX, e.pageY);
}
});
信頼できる PointerEvent が生成される際、UA は各イベント(その 合成イベントリスト と 予測イベントリスト
中)に対し以下の手順を実行するべき SHOULD:
pointerId /
pointerType /
isPrimary および isTrusted
を親ポインタイベントに合わせる。
cancelable と bubbles を false
に設定(これらは単独ではディスパッチされないため)。PointerEvent 値で初期化。信頼できる PointerEvent の target が変更されたとき、UA は SHOULD、その 合成イベントリスト と 予測イベントリスト 内の各イベントについて:
現在存在する大多数の Web コンテンツはマウスイベントのみを前提にコーディングされています。以下では、ユーザー エージェント がこのコンテンツとの互換性のために汎用的なポインター入力をマウスイベントへ MAY マッピングするアルゴリズムを記述します。
マウスイベントとの互換マッピングは本仕様の OPTIONAL な機能です。ユーザーエージェントは既存のレガシーコンテンツとの最良の互換性のためにこの機能をサポートすることが推奨されます。
高いレベルでは、互換マウスイベントはそれぞれのポインタイベントと「インターリーブ」されることを意図しています。ただしこの順序は必須ではなく、互換マウスイベントを実装するユーザーエージェントは、相対的な順序を維持する限りマウスイベントのディスパッチを遅延またはグループ化しても MAY です。
特にタッチスクリーン入力の場合、ユーザーエージェントは追加のジェスチャ認識ヒューリスティックを適用しても MAY です(著者が により明示的に抑止しない限り)。touch-actionpointerdown イベントと pointerup イベントの間のイベント列では、ジェスチャ認識はジェスチャを検出/無視するため
pointerup
まで待つ必要がある場合があります。その結果、ユーザーエージェントが特定ジェスチャとして意図されていないと判断した場合、互換マウスイベントは全シーケンスの最後の pointerup
後にまとめてディスパッチされることがあります。ユーザーエージェントのジェスチャ認識に関するこれらの詳細は本仕様で定義されず、実装間で異なる可能性があります。
互換マウスイベントをサポートするかどうかに関わらず、ユーザーエージェントは click, auxclick, contextmenu
イベントを常に MUST サポートしなければなりません。これらのイベントは型が PointerEvent であり、従って 互換マウスイベント ではないためです。ポインタイベント中に
preventDefault を呼び出しても click, auxclick, contextmenu
が発火するかどうかに影響を与えては MUST NOT なりません。
contextmenu, focus, blur
といった高レベルイベントの一部の相対的順序はポインタイベントとの関係で未定義であり、ユーザーエージェント間で異なります。例えば、あるユーザーエージェントでは
contextmenu が pointerup の後に続く一方、別のユーザーエージェントでは pointerup や pointercancel
の前に来ることがあり、キーボード操作など対応するポインタイベントなしに発火する状況もあります。
さらに、ユーザーエージェントは click, auxclick, contextmenu
イベントを発火すべきかどうか独自のヒューリスティックを適用する場合があります。他の(非プライマリ)同種ポインター、または異なる種類の他のプライマリポインターが存在する場合、これらのイベントを発火しない選択をすることがあります。指の接触中に移動が大きすぎるなどして「クリーンな」タップ/クリック/ロングプレスでないと判断された場合、click,
auxclick, contextmenu イベントを発火しないこともあります。これらの挙動は本仕様で定義されず、実装間で異なる可能性があります。
特記なき限り、マッピングされた任意のマウスイベントのターゲットは、そのターゲットがもはや自身の ownerDocument
のツリーに参加していない場合を除き、対応するポインタイベントのターゲットと同じであるべき SHOULD
です。この場合、マウスイベントは削除時点での元のターゲットの最近接祖先ノード(依然ツリーに参加しているもの)で発火すべきであり、新しいターゲットノードに基づいてマウスイベント用の新しいイベントパスが構築されます。
著者は pointerdown イベントをキャンセルすることで特定の互換マウスイベントの生成を防止できます。
マウスイベントはポインターが押下状態にあるときのみ防止できます。ホバー中のポインター(例: ボタンが押されていないマウス)ではマウスイベントを防止できません。
mouseover, mouseout, mouseenter, mouseleave
イベントは(ポインターが押下されていても)防止されることはありません。
ポインタイベントの EventListener が passive
[DOM]
に設定されている場合、互換マウスイベントは防止できません。
プライマリポインター のみが互換マウスイベントを生成できますが、複数のプライマリポインター
が同時にアクティブとなり、それぞれが独自の互換マウスイベントを生成することがあります。MouseEvent
に依存するスクリプトとの互換性のため、マウス遷移イベント(mouseover, mouseout, mouseenter,
mouseleave)は 単一 のレガシーマウス入力の移動をシミュレートすべき SHOULD
です。これは各イベントターゲットの入出状態が [UIEVENTS] に従い有効であることを意味します。ユーザーエージェントは文書内で レガシーマウスポインターの有効位置 を以下のように維持することでこれを保証すべき SHOULD
です。
pointerdown, pointerup,
pointermove イベント、または window 上の pointerleave イベントを発火する直前に、ユーザーエージェントは以下の手順を SHOULD 実行します:
pointerdown, pointerup, pointermove イベントのターゲットとする。pointerleave イベントの場合は T を未設定にする。
mouseover, mouseout,
mouseenter, mouseleave をディスパッチする。現在の レガシーマウスポインターの有効位置 または
T の未設定値はウィンドウ外のマウス位置と見なす。
レガシーマウスポインターの有効位置
は、ポインター遷移イベント(pointerover, pointerout, pointerenter,
pointerleave)から対応するレガシーマウス遷移イベント(mouseover, mouseout,
mouseenter,
mouseleave)への直接マッピングが常に可能とは限らない事実をモデル化します。以下のアニメーションは、ユーザーエージェントが 2
つのプライマリポインターを単一のレガシーマウス入力で整合させるために、ポインター遷移イベントより多くのレガシーマウス遷移イベントをディスパッチする必要がある例を示します。
このアニメーションでは、マウスクリックとタッチタップの間の期間に注目してください。ボタン 1
は(「実際の」マウスポインターがこの期間中ボタン矩形を離れていないため)pointerout を受け取りませんが、タッチタップでボタン 2 へ レガシーマウスポインターの有効位置 が移動した際に
mouseout を受け取ります。同様に、タッチタップとマウスがボタン 1 を離れる直前の期間では、同じ理由でボタン 1 は
pointerover を受け取りませんが、レガシーマウスポインターの有効位置 が再度ボタン 1
内に戻ったとき mouseover を受け取ります。
ユーザーエージェントがホバーをサポートするデバイスのポインタイベントをディスパッチする際は、以下の手順を SHOULD 実行します:
isPrimary が false の場合、そのポインタイベントをディスパッチして手順終了。pointerdown, pointerup, pointermove イベント、または window 上の pointerleave イベントである場合、レガシーマウスポインターの有効位置の追跡
で述べる互換マウス遷移イベントをディスパッチ。pointerdown でイベントが キャンセル された場合、この pointerType に
PREVENT MOUSE EVENT フラグを設定。
PREVENT MOUSE EVENT フラグがこの pointerType
に設定されていない場合かつディスパッチされたポインタイベントが以下のいずれか:
pointerdown なら mousedown
を発火。pointermove なら mousemove
を発火。pointerup なら mouseup を発火。
pointercancel なら window
で mouseup を発火。pointerup または pointercancel であれば、当該
pointerType の PREVENT MOUSE EVENT フラグをクリア。
多くのタッチスクリーンなど一部デバイスはアクティブ状態でない間に座標(または座標集合)をホバーできません。マウスイベントを前提にした既存コンテンツではマウスがイベントを生成することを仮定し、次の性質が一般に成り立ちます:
mousemove を生成する可能性が高い。これによりユーザーエージェントはこれら入力デバイス向けに異なるマッピングを提供する必要があります。ユーザーエージェントが ホバーをサポートしない デバイスのポインタイベントをディスパッチする際は以下の手順を SHOULD 実行します:
isPrimary が false ならポインタイベントをディスパッチして終了。pointerover で、このポインターの pointerdown
がまだディスパッチされていないなら(レガシーなマウス専用コードとの互換のため)mousemove を発火。pointerdown, pointerup, pointermove イベント、または window 上の pointerleave なら、レガシーマウスポインターの有効位置の追跡
に従い互換マウス遷移イベントをディスパッチ。pointerdown でイベントが キャンセル された場合、この pointerType に
PREVENT MOUSE EVENT フラグを設定。
PREVENT MOUSE EVENT フラグが設定されていない場合かつディスパッチされたポインタイベントが以下のいずれかなら:
pointerdown なら mousedown。
pointermove なら mousemove。
pointerup なら mouseup。pointercancel なら window
で mouseup。pointerup または pointercancel なら、この pointerType
の PREVENT MOUSE EVENT フラグをクリア。ユーザーエージェントが [TOUCH-EVENTS] で定義される Touch Events と Pointer Events の両方をサポートする場合、ユーザー エージェント は本節で述べる互換マウスイベントと [TOUCH-EVENTS] に記載の フォールバックマウスイベント の 両方 を生成しては MUST NOT なりません。
ホバーをサポートしない プライマリポインター(例:
タッチスクリーン上の一本指)による要素のアクティベーション(click)は通常以下のイベントシーケンスを生成します:
mousemovepointeroverpointerentermouseovermouseenterpointerdownmousedownpointermove と mousemove
(ポインターの移動に依存)pointerupmouseuppointeroutpointerleavemouseoutmouseleaveclickただし、このインタラクション中に pointerdown イベントが キャンセル された場合、イベント列は次のようになります:
mousemovepointeroverpointerentermouseovermouseenterpointerdownpointermove (ポインターの移動に依存)pointeruppointeroutpointerleavemouseoutmouseleaveclickこの付録では Pointer Events 実装におけるセキュリティおよびプライバシー上の考慮事項を論じます。議論は本仕様で定義されるイベントモデル・API・イベントの実装から直接生じる問題に限定します。
本仕様で定義される多くのイベント型はユーザー操作に応じてディスパッチされます。これにより悪意あるイベントリスナーはユーザーが通常秘匿したいと考える情報(ページ操作時のマウス/スタイラス/指の正確な経路・動きなど)へアクセスできてしまう可能性があります。
ポインタイベントは(ユーザーのデバイスがサポートしている場合)ペン入力の角度や傾き、接触面のジオメトリ、スタイラスやタッチスクリーンに加えられた圧力など追加情報を含みます。角度・傾き・ジオメトリ・圧力に関する情報はユーザーのデバイス上のセンサーに直接関連しているため、本仕様はオリジンにこれらセンサーへのアクセスを許可することになります。
これらのセンサーデータや使用された入力機構(マウス・タッチ・ペン)を特定できる能力は、ユーザーまたはユーザーのデバイス/環境に関する特性を推測するために利用され得ます。推測された特性やデバイス/環境情報はそれ自体がセンシティブである可能性があり、悪意あるサイトがユーザーが支援技術を使用しているかを追加推測することを許す場合があります。またこの情報はユーザープロファイルの構築やユーザーの「フィンガープリンティング」および追跡の試みに潜在的に利用され得ます。
緩和策として、ユーザーエージェントは特定のセンサーデータ(角度・傾き・圧力など)へのアクセスをユーザーが無効化できる能力を含めたり、明示的なユーザーのオプトイン後のみ公開することを検討できます。
本仕様は著者が「予測イベント」にアクセスする方法を定義します。仕様自体はユーザーエージェントが予測に使用すべきアルゴリズムを定義しません。仕様策定者はアルゴリズムがユーザーが実行中の現在のジェスチャに関連する直前のポインタイベントのみを頼りにすることを想定しています。ユーザーエージェントは、具体的な予測アルゴリズム実装がユーザーについてセンシティブ情報を明らかにしたりフィンガープリンティング/追跡に利用され得る追加データ(複数サイトにまたがるユーザーの完全なインタラクション履歴など)に依存しないことを保証する責任があります。
これらの考慮事項以外では、ワーキンググループは本仕様が以下を満たすと考えます:
この節は規範的ではありません。
buttons プロパティに非ゼロ値を持つ状態。マウスでは少なくとも 1
つのボタンが押下されている状態。タッチではデジタイザとの物理的接触がある状態。ペンではペンがデジタイザに物理接触しているか、ホバー中に少なくとも 1 つのボタンが押下されている状態。pointerId
で識別)が文書内で追加イベントを生成し得る場合、そのポインターはアクティブと見なされる。例:
preventDefault() の呼び出し、イベントハンドラで false を返すこと、または [UIEVENTS] や
[HTML]
で定義される他の手段によって既定動作が防止されたイベント。Measurable properties は実数または広い領域の整数で表現される連続ポインターセンサーデータに関する値を表す。ポインタイベントでは width,
height, pressure,
tangentialPressure, tiltX, tiltY, twist,
altitudeAngle, azimuthAngle および [UIEVENTS]
のマウスイベントモデルプロパティ
screenX, screenY, clientX, clientY が measurable
properties。
対照的に pointerId, pointerType,
isPrimary および [UIEVENTS] のマウスイベントモデルプロパティ button,
buttons, ctrlKey, shiftKey, altKey,
metaKey はセンサーデータに関連しないため measurable properties とは見なされない。
本ドキュメントに統合されたものを含め、提案や推奨を示してくださった多くの方々に深く感謝します。議長は以下の過去および現在のグループメンバー並びに参加者の貢献をここに認めます: Mustaq Ahmed, Arthur Barstow, Ben Boyle, Matt Brubeck, Rick Byers, Marcos Cáceres, Cathy Chan, Bo Cupp, Domenic Denicola, Ted Dinklocker, Adam Ettenberger, Robert Flack, Dave Fleck, Mike Fraser, Ella Ge, Olga Gerchikov, Scott González, Kartikaya Gupta, Dominique Hazael-Massieux, Philippe Le Hégaret, Hayato Ito, Patrick Kettner, Patrick H. Lauke, Scott Low, Sangwhan Moon, Masayuki Nakano, Olli Pettay, Addison Phillips, Alan Pyne, Antoine Quint, Jacob Rossi, Kagami Sascha Rosylight, Doug Schepers, Ming-Chou Shih, Brenton Simpson, Dave Tapuska, Liviu Tinta, Asir Vedamuthu, Lan Wei, Jeffrey Yasskin, Navid Zolghadr.
初版モデルの開拓に尽力してくださった方々、特に次の方々に特別の謝意を表します: Charu Chandiram, Peter Freiling, Nathan Furtwangler, Thomas Olsen, Matt Rakow, Ramu Ramanathan, Justin Rogers, Jacob Rossi, Reed Townsend, Steve Wright。
この節は規範的ではありません。
以下は本仕様の版間における、[PointerEvents3] 仕様と比較した重要かつ主要な編集上の変更点の情報的要約です。 本仕様のエディタドラフト完全な改訂履歴 も参照してください。
WebIDLdictionary PointerEventInit : MouseEventInit {
long pointerId = 0;
double width = 1;
double height = 1;
float pressure = 0;
float tangentialPressure = 0;
long tiltX;
long tiltY;
long twist = 0;
double altitudeAngle;
double azimuthAngle;
DOMString pointerType = "";
boolean isPrimary = false;
long persistentDeviceId = 0;
sequence<PointerEvent> coalescedEvents = [];
sequence<PointerEvent> predictedEvents = [];
};
[Exposed=Window]
interface PointerEvent : MouseEvent {
constructor(DOMString type, optional PointerEventInit eventInitDict = {});
readonly attribute long pointerId;
readonly attribute double width;
readonly attribute double height;
readonly attribute float pressure;
readonly attribute float tangentialPressure;
readonly attribute long tiltX;
readonly attribute long tiltY;
readonly attribute long twist;
readonly attribute double altitudeAngle;
readonly attribute double azimuthAngle;
readonly attribute DOMString pointerType;
readonly attribute boolean isPrimary;
readonly attribute long persistentDeviceId;
[SecureContext] sequence<PointerEvent> getCoalescedEvents();
sequence<PointerEvent> getPredictedEvents();
};
partial interface Element {
undefined setPointerCapture (long pointerId);
undefined releasePointerCapture (long pointerId);
boolean hasPointerCapture (long pointerId);
};
partial interface mixin GlobalEventHandlers {
attribute EventHandler onpointerover;
attribute EventHandler onpointerenter;
attribute EventHandler onpointerdown;
attribute EventHandler onpointermove;
[SecureContext] attribute EventHandler onpointerrawupdate;
attribute EventHandler onpointerup;
attribute EventHandler onpointercancel;
attribute EventHandler onpointerout;
attribute EventHandler onpointerleave;
attribute EventHandler ongotpointercapture;
attribute EventHandler onlostpointercapture;
};
partial interface Navigator {
readonly attribute long maxTouchPoints;
};
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: