ポインターイベント

レベル 4

W3C 作業草案

この文書の詳細
この版:
https://www.w3.org/TR/2025/WD-pointerevents4-20251022/
最新の公開版:
https://www.w3.org/TR/pointerevents4/
最新の編集者ドラフト:
https://w3c.github.io/pointerevents/
履歴:
https://www.w3.org/standards/history/pointerevents4/
コミット履歴
テストスイート:
https://wpt.fyi/pointerevents/
最新の勧告:
https://www.w3.org/TR/pointerevents2
編集者:
Patrick H. Lauke (TetraLogical)
Robert Flack (Google)
以前の編集者:
Matt Brubeck (Mozilla)
Rick Byers (Google)
Navid Zolghadr (Google)
フィードバック:
GitHub w3c/pointerevents (プルリクエスト, 新規 Issue, オープンな Issue)
public-pointer-events@w3.org 件名行: [pointerevents4] … メッセージの件名 … (アーカイブ)
ブラウザ対応状況:
caniuse.com

要約

この仕様の機能は 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 プロセス文書 によって管理される。

1. 導入

このセクションは参考であり、規範的ではない。

現在、ほとんどの [HTML] コンテンツはマウス入力で利用されるか、マウス入力向けに設計されている。入力をカスタム処理するものは、典型的に [UIEVENTS] のマウスイベントへコードを書く。しかし近年のコンピューティングデバイスはタッチスクリーンやペン入力など他の形態の入力を取り込んでいる。これら各入力形態を個別に扱うイベント型が提案されてきたが、その手法は新しい入力タイプを追加する際に不要なロジック重複やイベント処理オーバーヘッドを招くことが多い。これは、コンテンツが単一のデバイスタイプのみを想定して書かれた場合に互換性問題を生じさせる。また既存のマウスベースコンテンツとの互換性のため、ほとんどの ユーザーエージェント はすべての入力タイプに対してマウスイベントを発火する。これにより、マウスイベントが実際のマウスデバイスなのか互換性のため他の入力タイプから生成されたものなのかが曖昧になり、両方のデバイスタイプへ同時にコードを書くことが難しくなる。

複数入力タイプへのコーディングコストを下げ、さらに上記のマウスイベントに関する曖昧さを解消するために、本仕様は ポインター と呼ばれるより抽象的な入力形態を定義する。ポインターはマウスカーソル、ペン、タッチ(マルチタッチ含む)その他のポイント入力デバイスによる画面上の任意の接触点であり得る。このモデルは、ユーザーがどのようなハードウェアを持っていても適切に機能するサイトやアプリケーションの作成を容易にする。デバイス固有の処理が望まれるシナリオでは、この仕様はイベントを生成したデバイスタイプを検査するためのプロパティも定義する。主な目的はクロスデバイスのポインター入力に対する記述を容易にする単一のイベントセットとインターフェイスを提供しつつ、拡張された体験が必要な場合にのみデバイス固有処理を可能にすることである。

追加の重要な目的は、マルチスレッドなユーザーエージェントが、スクリプト実行によってブロックされることなくパン/ズーム(例えばタッチスクリーンで指やスタイラスによる)用の 直接操作 アクションを処理できるようにすることである。

注記

本仕様が多様なポインター入力に対して統一イベントモデルを定義している一方で、このモデルはキーボードやキーボードに類するインターフェイス(例:タッチスクリーンのみのデバイス上で動作し、フォーカス可能なコントロールや要素間を逐次的にナビゲート可能にするスクリーンリーダー等の支援技術)などの他の入力形態は対象としない。ユーザーエージェントがこれらインターフェイスへの応答としてポインターイベントを生成する選択を行う可能性はあるが、このシナリオは本仕様では扱わない。

第一に、著者は focusblurclick といった高レベルイベントに応答することで全ての入力形態に同等の機能を提供することが推奨される。しかし低レベルイベント(Pointer Events など)を用いる際は、すべての入力タイプがサポートされることを確保するよう推奨される。キーボードおよびキーボード類似インターフェイスの場合、明示的なキーボードイベント処理を追加する必要があるかもしれない。詳細は Keyboard Accessible [WCAG22] を参照。

ポインター入力はマウス、ペン、タッチなど様々な入力ソースを統合する
Figure 1 ポインターは画面上の特定の座標(または座標集合)をターゲットにできる入力デバイスのハードウェア非依存な表現である。

汎用ポインター入力を扱うイベントはマウスのイベントに非常によく似ている: pointerdownpointermovepointeruppointeroverpointerout など。このことはマウスイベントからポインターイベントへのコンテンツ移行を容易にする。ポインターイベントはマウスイベントに存在する通常のプロパティ(クライアント座標、ターゲット要素、ボタン状態など)に加え、圧力・接触ジオメトリ・傾きなど他の入力形態向けの新しいプロパティを提供する。著者は、妥当な箇所で異なる入力タイプ間でロジックを共有し、最良の体験のために必要な場合のみ特定入力タイプ向けにカスタマイズするコードを容易に記述できる。

ポインターイベントは多様な入力デバイスから供給されるが、他のデバイス固有イベント集合から生成されるものとして定義されているわけではない。互換性のために可能かつ推奨されるものの、この仕様は他のデバイス固有イベント(マウスイベントやタッチイベントなど)のサポートを要求しない。ユーザーエージェントは他のデバイスイベントを全くサポートせずにポインターイベントのみをサポートできる。マウス固有イベントに書かれたコンテンツとの互換性のために、この仕様は、マウス以外のデバイスからのポインター入力に基づき 互換マウスイベント を生成する方法を記述する任意セクションを提供する。

注記

この仕様は、[TOUCH-EVENTS] で定義されるタッチイベントとポインターイベントの両方をサポートするユーザーエージェントに期待される挙動について助言を提供しない。これら 2 つの仕様の関係についての詳細は Touch Events Community Group を参照。

2. 適合性

非規範的と記されたセクションに加え、この仕様書におけるすべての著者向けガイドライン、図、例、そして注記は非規範的である。その他の全ては規範的である。

この文書におけるキーワード MAYMUSTMUST NOTOPTIONALSHOULDBCP 14 [RFC2119] [RFC8174] に従い、ここに示すようにすべて大文字で現れる場合のみ解釈される。

3.

このセクションは参考であり、規範的ではない。

以下は著者が本仕様の API の一部をどのように使用し得るかを示す基本的な例である。さらに具体的な例は本書の該当セクションに示される。

Example 1: 機能検出とイベントバインディング
/* 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
...
Example 2: ユーザーの入力タイプ検出
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 */
    }
}
Example 3: 接触ジオメトリに合わせて要素サイズを変更
<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>
Example 4: スクリプトから信頼されないポインターイベントを発火
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);
Example 5: PointerDown でペンカラーを割り当て
<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>

4. Pointer Events とインターフェイス

4.1 PointerEvent インターフェイス

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。ユーザーエージェントはプライマリマウスポインター用に一般的な pointerId0 もしくは 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

注記
名称に反して、この値を生成するハードウェアセンサーが必ずしも圧力感知式とは限らない。多くのエアブラシ/ペイント用スタイラスの指ホイールは押し続ける必要なく任意位置に設定可能。
tiltX

Y-Z 平面とトランスデューサ(例: ペン/スタイラス)軸および Y 軸を含む平面との角度(度、範囲 [-90,90])。正の tiltX は右方向(X 増加方向)。tiltY と組み合わせて傾きを表現可能。傾き未報告の場合値は 0 MUST

tiltX 説明図
Figure 2 正の tiltX
tiltY

X-Z 平面とトランスデューサ軸および X 軸を含む平面との角度(度、範囲 [-90,90])。正の tiltY は利用者側(Y 増加方向)。傾き未報告の場合値は 0 MUST

tiltY 説明図
Figure 3 正の tiltY
twist

トランスデューサ(例: ペン/スタイラス)主要軸周りの時計回り回転角(度、範囲 [0,359])。未報告時は 0 MUST

altitudeAngle

トランスデューサの高度(ラジアン、範囲 [0,π/2])。0 は表面(X-Y 平面)と平行、π/2 は垂直。傾き未報告時は π/2 MUST

注記
ここでの既定値 altitudeAngleπ/2(垂直)であり、Touch Events - Level 2 仕様の既定値 0 と異なる。
altitudeAngle 説明図
Figure 4 例: altitudeAngle = π/4(X-Y 平面から 45 度)。
azimuthAngle

トランスデューサの方位角(ラジアン、範囲 [0, 2π])。0 は X 増加方向(真上から見て 3 時方向)。時計回りに増加(π/2 が 6 時、π が 9 時、3π/2 が 12 時)。トランスデューサが完全に垂直(altitudeAngle = π/2)なら値は 0 MUST。未報告時も 0 MUST

azimuthAngle 説明図
Figure 5 例: azimuthAngle = π/6(4 時方向)。
pointerType

イベントを発生させたデバイスタイプ(mouse, pen, touch)を示す。UA がマウス・ペン/スタイラス・タッチ入力のポインタイベントを 発火 する場合、pointerType の値は下表に従う MUST

ポインターデバイスタイプ pointerType
Mouse mouse
Pen / stylus pen
Touch contact touch

デバイスタイプを検出できない場合は空文字列 MUST。上記以外のタイプをサポートする場合は衝突回避のためベンダープレフィックス化 SHOULD。今後の仕様で追加の標準値が定義される可能性がある MAY

注記
基本的な使用例は Example 2 を参照。空文字や独自値へのフォールバック処理を用意すべき。
isPrimary

このポインターが該当 ポインタータイプのプライマリポインター かどうか。

persistentDeviceId

ポインティングデバイスの一意識別子。ハードウェアが複数ポインターをサポートし、それらがセッションを通じ一意識別可能な場合のみ persistentDeviceId を割り当てる MUST。識別不能なイベントには値 0 を用いる MUSTpointerId と同様、フィンガープリント回避のためセッション単位でのみ関連付け MUST、新セッションではランダム化された新しい値を選択 MUST

注記
デジタイザ/デバイス制約により全イベントで常に利用できるとは限らない。例えば pointerdown 時点では報告されず一時的に 0 で後に有効値へ変わる場合がある。
getCoalescedEvents()

合成(coalesced)イベント のリストを返すメソッド。

getPredictedEvents()

予測(predicted)イベント のリストを返すメソッド。

PointerEventInit 辞書は PointerEvent コンストラクタによる信頼されない(合成)ポインタイベント生成のための仕組みを提供する。MouseEventInit を継承。[UIEVENTS] 参照。例は examples を参照。

イベント構築手順PointerEvent に対して PointerEventInitcoalescedEvents合成イベントリスト に複製し、PointerEventInitpredictedEvents予測イベントリスト に複製する。

注記
PointerEventMouseEvent を継承し UI Events で定義される。CSSOM View Module における座標型を long から double へ拡張する提案にも注意。PointerEvent のみ拡張し通常の MouseEvent を拡張していない UA では click, auxclick, contextmenu に追加要件が生じる。

4.1.1 ボタン状態

4.1.1.1 連動ボタン操作

マウスやペンなど複数ボタン対応のポインターデバイスが存在する。[UIEVENTS] の Mouse Event モデルでは各ボタン押下ごとに mousedown/mouseup が発生する。ハードウェア差異をより抽象化しクロスデバイス入力を簡素化するため、Pointer Events は既に同一デバイス上の他ボタン押下中に追加ボタンを押す「連動(chorded)」ボタン操作に対して重複する pointerdown および pointerup を発火しない。

代わりに buttonbuttons プロパティの変化を検査して連動押下を検出できる。これらプロパティは MouseEvent から継承されるが意味と値が後述の通り変更される。

この変更はポインターイベントにのみ適用される。ただし click, auxclick, contextmenu においては button/buttons の値は [UIEVENTS] に従う MUST互換マウスイベント と同様)。

4.1.1.2 button プロパティ

任意のポインターイベント(pointerdown / pointerup に限定されない)でボタン状態遷移を識別するため、button は状態変化を引き起こしたデバイスボタンを示す。

デバイスボタン変化 button
前回イベントからボタン/タッチ/ペン接触の変化なし -1
左マウス,
タッチ接触,
ペン接触
0
中ボタン(Middle Mouse) 1
右マウス,
ペンバレルボタン
2
X1(戻る)マウス 3
X2(進む)マウス 4
ペン消しゴムボタン 5
注記
マウスドラッグ中、pointermovebutton 値は mousemove イベントとは異なる。例: 右ボタン押下状態で移動中、pointermove の button は -1、mousemove の button は 2。
4.1.1.3 buttons プロパティ

buttons は現在のボタン状態をビットマスクで返す(MouseEvent と同様だが可能値拡張あり)。

現在のボタン状態 buttons
ボタン未押下でマウス移動,
ホバー中ペン移動(ボタンなし)
0
左マウス,
タッチ接触,
ペン接触
1
中ボタン 4
右マウス,
ペンバレルボタン
2
X1(戻る)マウス 8
X2(進む)マウス 16
ペン消しゴムボタン 32

4.1.2 プライマリポインター

マルチポインター(例: マルチタッチ)シナリオでは、各ポインタータイプの集合内で isPrimary によりアクティブポインターのマスターを識別する。

  • 任意時点で各ポインタータイプにつき最大 1 つのプライマリポインター。
  • 特定タイプで最初にアクティブとなったポインター(例: 最初に画面へ触れた指)がそのタイプのプライマリになる。
  • プライマリポインターのみが 互換マウスイベント を生成。複数の プライマリポインター が存在する場合、それぞれが互換マウスイベントを生成。
注記
単一ポインター操作のみ必要な著者は非プライマリポインターを無視すればよい(ただし multiple primary pointers 参照)。
注記
複数種類のポインターデバイスを同時使用すると、種類ごとにプライマリとして扱われる(例: タッチとマウスを同時使用で両方プライマリ)。
注記
特定タイプに複数アクティブポインターがありプライマリが取り除かれた場合、以降プライマリなしでイベントが発火する状況もある。またデバイス全体の同タイプポインターからプライマリを決めるプラットフォームでは、UA 外部にプライマリがあり UA 内部には非プライマリのみ存在する状況で isPrimary=false となる MAY
注記
多くの OS/UA は複数マウス入力を区別せず単一マウスとして統合する。ラップトップのトラックパッドと外部マウスなど複数機器でも 1 つのポインターとして扱われ、通常そのポインターがプライマリ。

4.1.3 PointerEvent インターフェイスを用いたイベント発火

ポインタイベントを発火するとは、名前 e のイベントを fire an event し、その属性を PointerEvent インターフェイスおよび Attributes and Default Actions に従って設定することを意味する。

イベントが gotpointercapturelostpointercaptureclickauxclickcontextmenu でない場合、この PointerEvent について 保留中ポインターキャプチャ処理 手順を実行する。

ターゲット決定 手順:

ターゲットの node documenttargetDocument とする [DOM]。

イベントが pointerdownpointermovepointerup のいずれかなら、そのイベントの active documenttargetDocument に設定。

イベントが pointerdown で、関連デバイスが直接操作型かつターゲットが Element の場合、set pointer capture をそのターゲット要素へ適用(暗黙的ポインターキャプチャ参照)。

発火前に ユーザーエージェントpreviousTarget からターゲットへポインターが移動したかのように扱う SHOULD([UIEVENTS] の event ordering 参照)。needsOverEvent フラグが立っている場合、ターゲット要素が同一でも pointerover が必要。

決定されたターゲットにイベントを発火。

そのターゲットを当該ポインターの previousTarget として保存し、needsOverEventfalse にリセット。previousTarget が非接続状態になった場合はイベントパスに沿い接続中の最近接の親へ更新しフラグを true に設定。

注記
通常のヒットテスト結果ではなく pointer capture target override をターゲットとして用いると境界イベントが発生する場合がある([UIEVENTS] 参照)。キャプチャ解除時も同様で、旧ターゲットからヒットテストターゲットへ移ったと見なされる。
4.1.3.1 属性と既定動作

本仕様で定義されるイベント型の 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

注記
多くの UA はレガシー互換のため非標準属性 fromElement / toElement を MouseEvents に公開する。PointerEvents ではこれら継承属性を null に設定し、標準属性(targetrelatedTarget)使用へ移行させることが望ましい。

pointerover/pointerenter では relatedTarget を離脱元要素に、pointerout/pointerleave では進入先要素に初期化。それ以外は null。要素がポインターキャプチャを取得した後のイベントはキャプチャ要素境界内とみなす。

gotpointercapturelostpointercapture イベントでは、上表で定義された属性以外はユーザーエージェントが 保留中ポインターキャプチャ処理 を実行しこれらイベントを発火させた元の Pointer Event と同一であるべき。

4.1.3.2 保留中ポインターキャプチャの処理

ユーザーエージェント暗黙的キャプチャ解除 時および gotpointercapture/lostpointercapture 以外の Pointer Event 発火時に以下手順を実行 MUST

  1. 当該ポインターの pointer capture target override が設定され、pending pointer capture target override と異なるなら、そのノードへ lostpointercapture を発火。
  2. 当該ポインターの pending pointer capture target override が設定され、pointer capture target override と異なるなら gotpointercapture を発火。
  3. pointer capture target override を設定済みなら pending pointer capture target override に更新。未設定ならクリア。
注記

click, auxclick, contextmenu の節で定義されるとおり、lostpointercapture 発火後でも対応する click/auxclick/contextmenu があればキャプチャターゲットへディスパッチされる。

4.1.3.3 ポインタイベントストリームの抑制

ユーザーエージェント は特定の pointerId で今後イベント受信が見込まれないと判断した場合、ポインタイベントストリームを抑制 MUST。以下のシナリオはいずれも条件を満たす(追加シナリオが存在し得る MAY)。

  • UA がモーダルダイアログまたはメニューを開いた。
  • ポインター入力デバイスが物理的に切断、またはホバー可能デバイス(例: ホバー可能スタイラス)がデジタイザのホバー範囲外へ離脱。
  • ポインターがページビューポート操作(パン/ズーム)に使用された。touch-action 参照。
    注記
    UA は複数ポインタータイプ(タッチ・ペン等)でパン/ズームを開始し得るため、異なる pointerType を含む複数ポインターが抑制対象となり得る。
  • ドラッグ&ドロップ処理モデル [HTML] のドラッグ操作開始アルゴリズムによりドラッグを開始したポインター。
注記

その他 UA が user agent として MAY 抑制 するシナリオ例:

  • ポインターアクティブ中に画面の向きが変更された。
  • デバイスがサポートする同時ポインター数をユーザーが超えて操作しようとした。
  • 入力が誤操作(パームリジェクションなど)と解釈された。

これら検出方法は仕様の範囲外。

ユーザーエージェントストリーム抑制 のため以下手順を実行 MUST:

4.1.4 レイアウト変更による境界イベント

スクリーン表面に対して移動またはプロパティ変化を起こしたポインターデバイスは Pointer Event types で定義される各種イベントを発火する。移動やプロパティ変化の無い静止ポインターについてはレイアウト変更によりそのポインターの ヒットテスト 対象が変化した場合、UA は pointeroverpointerenterpointeroutpointerleave を発火 MUST。性能上の理由(過度なヒットテストやレイアウト計算回避)で遅延 MAY

注記
静止ポインター(移動もプロパティ変化も無い)は pointermove を発火しない。

4.1.5 tiltX/tiltYaltitudeAngle/azimuthAngle の相互変換

Pointer Events はトランスデューサ(ペン等)の X-Y 平面に対する姿勢を表現する 2 組の属性を提供する:初期仕様からの tiltX/tiltY と、Touch Events - Level 2 から採用された azimuthAngle/altitudeAngle

具体的なハードやプラットフォームにより UA はしばしば片方のセットのみ(tiltX/tiltYaltitudeAngle/azimuthAngle のどちらか)を受け取る。UA は以下の変換アルゴリズムを使用 MUST

UA が azimuthAngle/altitudeAngle から tiltX/tiltY を算出する際、最終的な整数値は Math.round [ECMASCRIPT] により丸める SHOULD

Example 6: tiltX/tiltY と altitudeAngle/azimuthAngle の相互変換
/* 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};
}

4.2 Pointer Event 型

以下は本仕様で定義されるイベント型です。

プライマリポインター の場合、これらのイベント(gotpointercapturelostpointercapture を除く)は 互換マウスイベント も発火する場合があります。

4.2.1 pointerover イベント

ユーザーエージェント は以下のいずれかが発生したとき MUST 名称 pointeroverポインタイベントを発火 する:

4.2.2 pointerenter イベント

ユーザーエージェント は以下のいずれかが発生したとき MUST 名称 pointerenterポインタイベントを発火 する:

注記
このイベント型は pointerover に似ていますが 2 点異なります。pointerenter はバブルせず、子孫要素の ヒットテスト 境界も考慮する点です。
注記
このイベント型は [UIEVENTS] で記述される mouseenter イベントや、[CSS21] の CSS 擬似クラス :hover と類似点があります。pointerleave も参照してください。

4.2.3 pointerdown イベント

ユーザーエージェント はポインターが active buttons state に入ったとき MUST 名称 pointerdownポインタイベントを発火 する。マウスでは「全ボタン非押下」から「少なくとも1つ押下」への遷移。タッチでは デジタイザ への物理接触。ペンではボタン非押下での接触、またはホバー中に非押下から押下への遷移。

注記
マウス(他の複数ボタンデバイス含む)では pointerdown / pointerup が常に mousedown / mouseup と同じ条件で発火するわけではない。詳細は 連動ボタン (chorded buttons) を参照。

ホバーを サポートしないデバイス の入力について、ユーザーエージェントMUST pointer イベントを発火 し、pointerover に続けて pointerenterpointerdown のディスパッチ前に行う。

注記
著者は 互換マウスイベント の一部発火を、isPrimarytrue のとき pointerdown をキャンセルすることで防止できる。これはそのポインターに PREVENT MOUSE EVENT フラグを設定する。ただし mouseover, mouseenter, mouseout, mouseleave の発火は妨げない。

4.2.4 pointermove イベント

ユーザーエージェント は、pointerdownpointerup を発火しない任意のプロパティが変化したとき MUST 名称 pointermoveポインタイベントを発火 する。これには座標、pressure、tangential pressure、 tilt、twist、接触ジオメトリ(widthheight)、または 連動ボタン の変更が含まれる。

ユーザーエージェントは性能上の理由などで pointermove のディスパッチを遅延しても MAY合成イベント 情報は単一のディスパッチ済み pointermove に対する getCoalescedEvents メソッドで公開される。最終座標はイベントのターゲット決定に使用する。

4.2.5 pointerrawupdate イベント

ユーザーエージェントMUST ポインターが pointerdown / pointerup を発火しないプロパティを変更した際、名称 pointerrawupdateポインタイベントを発火 し、かつそれを セキュアコンテキスト 内のみで行う。該当プロパティ一覧は pointermove を参照。

pointermove と対照的に、ユーザーエージェントは SHOULD pointerrawupdate を可能な限り速く、JavaScript が処理可能な頻度でディスパッチする。

pointerrawupdatetarget は、pointermove が遅延・合成され得ることから異なる場合があり、合成イベントの最終位置によるターゲット決定と異なる可能性がある。

同じ pointerId の未ディスパッチ pointerrawupdate が既にイベントループ内にある場合、ユーザーエージェント は新しい pointerrawupdate を合成して新規 task を作成しないことが MAY。これにより合成された複数の pointerrawupdate が単一イベントの 合成イベント としてイベントループ処理時に配送される。詳細は getCoalescedEvents を参照。

pointerrawupdatepointermove の順序について、プラットフォームからの更新が両イベントの発火要因となる場合、ユーザーエージェントMUST 対応する pointermove より前に pointerrawupdate をディスパッチする。

target を除き、最後にディスパッチされた pointermove 以降に配送されたすべての pointerrawupdate の合成イベントリスト連結は、次の pointermove の合成イベントと他属性に関して同一となる。pointerrawupdate の属性は主に pointermove と同じだが、cancelablepointerrawupdate では false としなければならない MUST

ユーザーエージェントは SHOULD 互換マウスイベントpointerrawupdate に対しては発火しない。

注記
一部実装では pointerrawupdate リスナー追加がページ性能へ悪影響を与える可能性がある。多くのユースケースでは他の pointer イベント型で十分。高頻度かつ高速処理が必要な場合のみ pointerrawupdate リスナーを追加すべきで、その状況では他のポインターイベント型を監視する必要は概ねない。

4.2.6 pointerup イベント

ユーザーエージェント はポインターが active buttons state から離脱したとき MUST 名称 pointerupポインタイベントを発火 する。マウスでは「少なくとも1ボタン押下」から「全ボタン非押下」への遷移。タッチでは デジタイザ から物理接触が離れたとき。ペンではボタン非押下状態で接触が終了した、またはホバー中に「少なくとも1ボタン押下」から「全ボタン非押下」へ遷移したとき。

ホバーを サポートしないデバイス の入力では、ユーザーエージェントMUST ポインタイベントを発火 し、pointerup の後に pointerout、続いて pointerleave をディスパッチする。

すべての pointerup イベントは pressure0 を持つ。

ユーザーエージェント はポインターがキャプチャ中であれば MUST 暗黙的にポインターキャプチャを解除 する。

注記
マウス(他の複数ボタンデバイス含む)では pointerdown / pointerup が常に mousedown / mouseup と同一条件で発火するわけではない。詳細は 連動ボタン を参照。

4.2.7 pointercancel イベント

ユーザーエージェントポインタイベントストリームを抑制 すべきシナリオを検出したとき MUST 名称 pointercancelポインタイベントを発火 する。

pointercancel の以下プロパティ値は、同じ pointerId を持つ最後にディスパッチされたポインタイベントの値と一致する MUST: width, height, pressure, tangentialPressure, tiltX, tiltY, twist, altitudeAngle, azimuthAngle, pointerType, isPrimary および [UIEVENTS] から継承する座標。pointercancelcoalescedEventspredictedEvents リストは空である MUST。イベントの cancelable 属性は false とする MUST

4.2.8 pointerout イベント

ユーザーエージェント は以下のいずれかが発生したとき MUST 名称 pointeroutポインタイベントを発火 する:

4.2.9 pointerleave イベント

ユーザーエージェント は以下のいずれかが発生したとき MUST 名称 pointerleaveポインタイベントを発火 する:

注記
このイベント型は pointerout に似ていますが 2 点異なります。pointerleave はバブルせず、子孫要素の ヒットテスト 境界も考慮する点です。
注記
このイベント型は [UIEVENTS] の mouseleave イベントや [CSS21] の CSS 擬似クラス :hover と類似点がある。pointerenter も参照。

4.2.10 gotpointercapture イベント

ユーザーエージェント は要素がポインターキャプチャを取得したとき MUST 名称 gotpointercaptureポインタイベントを発火 する。このイベントはキャプチャを受ける要素で発火し、以降そのポインターのイベントはこの要素へ送られる。ポインターキャプチャ設定 および 保留中ポインターキャプチャの処理 節を参照。

4.2.11 lostpointercapture イベント

ユーザーエージェント はポインターのキャプチャが解除された後 MUST 名称 lostpointercaptureポインタイベントを発火 する。このイベントはキャプチャ解除後の最初の後続イベントより前に MUST 発火される。発火場所はキャプチャが解除された要素。以降(click, auxclick, contextmenu を除く)イベントは通常のヒットテスト機構でターゲット決定される。ポインターキャプチャ解除暗黙的解除保留中ポインターキャプチャ処理 を参照。

4.2.12 click, auxclick, contextmenu イベント

この節は [UIEVENTS] で定義される click, auxclick, contextmenu イベントへの追加事項です。これらは典型的に UI アクティベーションに結びつき、キーボードなどポインター以外の入力デバイスからも発火します。

これらのイベントは型が PointerEvent である MUST であり、本節で述べる追加要件の対象となります。

4.2.12.1 イベント属性

これらのイベントでは、pointerIdpointerType を除く本仕様で定義されるすべての PointerEvent 固有属性は既定値を持つ MUST。加えて:

  • イベントがポインティングデバイスによって生成された場合、その pointerIdpointerType はそれらのイベントを引き起こした PointerEvent と同一である MUST
  • イベントが非ポインティングデバイス(音声認識やキーボードなど)によって生成された場合、pointerId-1pointerType は空文字列である MUST
4.2.12.2 イベント座標

PointerEvent で述べた通り、CSSOM View Module は各種座標プロパティ(screenX, screenY, pageX, pageY, clientX, clientY, x, y, offsetX, offsetY)を double に再定義し小数座標を許可する提案をしている。しかしこの変更を PointerEvent のみに適用し通常の MouseEvent へ適用しない場合、click, auxclick, contextmenu でレガシーコードとの互換性問題が発生する。従ってこの提案を PointerEvent のみに実装した UA はこれらイベントの座標プロパティを元の UI Events 定義どおり long 値へ Math.floor [ECMASCRIPT] で変換する MUST

4.2.12.3 イベントディスパッチ

click, auxclick, contextmenu イベントは [UIEVENTS] 仕様のディスパッチ手順に従う MUST だが、イベントターゲットは以下アルゴリズムで上書きする:

  1. event をディスパッチ対象の click, auxclick, contextmenu イベント、userEventevent 発火を引き起こしたユーザー操作イベントとする。

    注記

    userEvent は非 PointerEvent の可能性がある。例: チェックボックス上でスペースキー押下による clickKeyboardEvent

    userEventPointerEvent の場合、userEventclick / auxclick では pointerupcontextmenu ではネイティブプラットフォーム慣習により pointerdown または pointerup

  2. userEventPointerEvent でない場合、[UIEVENTS] に従い event のターゲットを上書きせずディスパッチし以下の手順をスキップ。
  3. target を以下のように定義:

    eventcontextmenu である、または対応するポインターがキャプチャ中に userEvent がディスパッチされた場合、targetuserEvent のターゲットとする。

    それ以外(eventclick または auxclick で、userEvent がキャプチャされずにディスパッチされた pointerup)の場合、target を DOM 内での対応する pointerdownpointerup ターゲットの最近接共通包含祖先とする(event ディスパッチ時点)。

  4. [UIEVENTS] に従い eventtarget へディスパッチする。

    注記
    userEvent がキャプチャされていた場合、同じ lostpointercapture が既にディスパッチ済みでも eventuserEvent のキャプチャターゲットへディスパッチされる。

5. Element インターフェイスの拡張

以下の節では既存の 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" の DOMExceptionthrow します。

releasePointerCapture()

引数 pointerId で識別されるポインターに対し、このメソッドが呼び出された要素から ポインターキャプチャを解除 します。以降そのポインターのイベントは通常のヒットテスト機構(本仕様の範囲外)に従ってターゲット決定されます。引数がいずれの active pointers にも一致しない場合は "NotFoundError" の DOMExceptionthrow します。

hasPointerCapture

このメソッドが呼び出された要素が、引数 pointerId で識別されるポインターの ポインターキャプチャ を持つかどうかを示します。具体的には、pending pointer capture target override がその要素に設定されていれば true、そうでなければ false を返します。

Note
このメソッドは setPointerCapture() 呼び出し直後に true を返しますが、その要素はまだ gotpointercapture イベントを受け取っていません。そのため 暗黙的ポインターキャプチャpointerdown イベントリスナー内で検出するのに有用です。

6. GlobalEventHandlers ミックスインの拡張

以下の節では、既存の 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;
};
onpointerover
イベントハンドラ IDL 属性pointerover イベント型に対応します。
onpointerenter
イベントハンドラ IDL 属性pointerenter イベント型に対応します。
onpointerdown
イベントハンドラ IDL 属性pointerdown イベント型に対応します。
onpointermove
イベントハンドラ IDL 属性pointermove イベント型に対応します。
onpointerrawupdate
イベントハンドラ IDL 属性pointerrawupdate イベント型に対応します。
onpointerup
イベントハンドラ IDL 属性pointerup イベント型に対応します。
onpointercancel
イベントハンドラ IDL 属性pointercancel イベント型に対応します。
onpointerout
イベントハンドラ IDL 属性pointerout イベント型に対応します。
onpointerleave
イベントハンドラ IDL 属性pointerleave イベント型に対応します。
ongotpointercapture
イベントハンドラ IDL 属性gotpointercapture イベント型に対応します。
onlostpointercapture
イベントハンドラ IDL 属性lostpointercapture イベント型に対応します。

7. Navigator インターフェイスの拡張

Navigator インターフェイスは [HTML] に定義されています。本仕様は Navigator インターフェイスを拡張し、デバイス検出のサポートを提供します。

WebIDLpartial interface Navigator {
    readonly  attribute long maxTouchPoints;
};
maxTouchPoints

デバイスがサポートする同時タッチ接点の最大数。複数のデジタイザ(例: 複数のタッチスクリーン)を持つデバイスの場合、値は各デジタイザの最大サポート接点数の集合のうちの最大値である MUST

例えば、3 つのタッチスクリーンを持つデバイスで、それぞれ 2、5、10 の同時タッチ接点をサポートする場合、maxTouchPoints の値は 10 となるべきです。

注記
maxTouchPoints の値が 0 より大きいことは、ユーザーのデバイスがタッチ入力をサポートできることを示しますが、必ずしもユーザーがタッチ入力を使用することを意味しません。著者は、マウス、ペン、スクリーンリーダーなど、システムに存在し得る他の入力モダリティも考慮すべきです。
注記
maxTouchPoints は、コンテンツのインタラクションモデルが現在のハードウェアで認識可能か確認するために用いられることが多いです。性能の低いハードウェアのユーザーには UI の手掛かりを提供できます。正確なタッチポイント数が不明なプラットフォームでは、認識が保証される最小数が提供されます。従って、実際に認識されるタッチポイント数が maxTouchPoints の値を上回る可能性があります。

8. 直接操作挙動の宣言

属性と既定動作 で述べたように、ビューポートの操作(パンおよびズーム)はポインタイベントのキャンセルによって抑止することはできません。代わりに、著者は許可したい挙動と抑止したい挙動を touch-action CSS プロパティを用いて宣言的に定義しなければなりません。

注記
ビューポート操作に用いられるポインターの問題は一般にタッチ入力(ユーザーの指がコンテンツと相互作用しつつページをパン/ズームできる)に限定されますが、ユーザーエージェントによっては他のポインタータイプでも同種の(直接または間接の)操作を許可する場合があります。例えば、モバイル/タブレット端末ではスタイラスでのスクロールが可能な場合があります。歴史的な理由から本仕様で定義される touch-action CSS プロパティはタッチ入力のみを指すように見えますが、実際にはパンとズームのための直接操作を許容するあらゆるポインター入力に適用されます。

8.1 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 ポインタイベントストリームを抑制 します:

注記
一部のユーザーエージェントは、一連の離散的なジェスチャーから成る複合的な挙動を、単一の連続ジェスチャーとして扱う複雑なジェスチャーを実装します。例えばタッチスクリーンでの「フリックしてスクロール」では、ユーザーが素早く指を動かしてパンを開始し、指を離しても慣性によりパンが継続します。ドキュメントが動いている間に、ユーザーが再度指を置いて別の「フリック」を行いパンに慣性を加えたり、現在のパンに逆らって減速・停止・方向反転させることもあります。本仕様はジェスチャーや挙動の実装を規定しないため、二度目のタッチが(第二の「フリック」や現在のパンの打ち消しと解釈される前に)ポインタイベントを発火するかどうかはユーザーエージェントに委ねられます。
注記
touch-action は、埋め込み閲覧コンテキストには適用/継承されません。例えば、<iframe>touch-action を適用しても、当該 <iframe> 内のパン/ズームに関する直接操作挙動には影響しません。

8.2 サポートされる直接操作挙動の判定

ユーザーがタッチやタッチスクリーン上のスタイラスなどの 直接操作ポインターで要素と相互作用するとき、その入力の効果は、 touch-action プロパティの値と、要素およびその祖先の既定の直接操作挙動によって、次のように決定されます。

注記
一部のユーザーエージェントは、複数の同時ポインター(例: マルチタッチ)を伴うパンやズームの相互作用をサポートします。複数の同時ポインターに対する touch-action 値の処理や関連付けの方法は本仕様の範囲外です。

8.3 touch-action の値の詳細

touch-action プロパティは、ビューポートのパンおよびズームに関する直接操作挙動を対象とします。テキスト選択/ハイライト、リンクやフォームコントロールのアクティベーションといった追加のユーザーエージェント挙動は、この CSS プロパティによって影響を受けては MUST NOT なりません。

注記
「panning(パン)」と「scrolling(スクロール)」は同義(より正確には、直接操作入力を用いた「スクロール」が「パン」)と見なします。パン/スクロールをトリガーする相互作用やジェスチャー、または autonone の値に対する挙動のトリガーの定義は本仕様の範囲外です。
auto
ユーザーエージェント は、要素上で開始するビューポートのパンおよびズームに関する許可された直接操作挙動を考慮しても MAY よい。
none
要素上で開始する直接操作の相互作用は、ビューポートのパンおよびズームに関する挙動をトリガーしては MUST NOT ならない。
pan-x
pan-left
pan-right
pan-y
pan-up
pan-down
ユーザーエージェント は、要素上で開始する直接操作の相互作用を、列挙されたすべての値で指定された方向で開始するパンに限って考慮しても MAY よい。パンが開始された後は、開始方向が不許可であってもユーザーは方向を反転できる。一方、単一軸に制限されたパン(例: pan-xpan-y)では、パンの最中に軸を変更することはできない。
manipulation
ユーザーエージェント は、要素上で開始する直接操作の相互作用を、パンおよび連続的なズーム(ピンチズームなど)の目的に限って考慮しても MAY よいが、一定時間内に複数のアクティベーションを必要とする他の関連挙動(ダブルタップでズーム、ダブルタップしてホールドで片手ズームなど)をトリガーしては MUST NOT ならない。
注記
実装で一般的な追加の touch-action は [COMPAT] で定義されています。
注記
touch-action プロパティは、CSS の width および height プロパティの両方をサポートする要素([CSS21] 参照)にのみ適用されます。この制約は、低遅延直接操作によるパンおよびズームのために、ユーザーエージェントの最適化を容易にするためのものです。デフォルトでサポートされない要素(例: 非置換インライン要素である <span>)については、著者は CSS の displayblock のような widthheight をサポートする値に設定できます。将来の仕様で、この API がすべての要素に拡張される可能性があります。
注記

方向固有の pan 値は、いくつかのオーバースクロール挙動をカスタマイズするのに有用です。 例えば、シンプルなプル・トゥ・リフレッシュを実装するには、ドキュメントの touch-action をスクロール位置が 0 のとき pan-x pan-down に、それ以外では pan-x pan-y に設定できます。 これにより、ドキュメント先頭から開始する上方向のパン/スクロールの挙動をポインタイベントハンドラで定義できます。

方向固有の pan 値は、ネイティブにスクロールする要素内で、ポインタイベント処理を用いたカスタムパンを実装するコンポーネント(またはその逆)を合成する場合にも使用できます。 例えば、画像カルーセルは pan-y を用いて、ドキュメントの垂直パンを妨げることなく、水平方向のパン操作に対するポインタイベントを確実に受け取れます。 カルーセルが最も右端に到達したら、touch-actionpan-y pan-right に変更して、範囲外のその後のスクロール操作が可能であればビューポート内のドキュメントをスクロールできるようにします。 実行中のパン/スクロール操作の挙動を、その最中に変更することはできません。

注記
パンやズームに関する一部の既定の直接操作挙動を無効にすると、ユーザーエージェントが他の挙動により素早く反応できる場合があります。例えば、auto では、ダブルタップジェスチャーを処理できるよう、ユーザーエージェントは通常 click の前に 300ms の遅延を追加します。このような場合、touch-action: none または touch-action: manipulation を明示的に設定することで、この遅延を取り除けます。なお、タップやダブルタップのジェスチャーを判別する手法は本仕様の範囲外です。
Example 7: すべての直接操作挙動を不許可にする
<div style="touch-action: none;">
    この要素は、通常であればパンやズームにつながるすべての直接操作の相互作用についてポインタイベントを受け取ります。
</div>
Example 8: 水平パンのみを許可する
<div style="touch-action: pan-x;">
    この要素は、水平方向にパンしていない場合にポインタイベントを受け取ります。
</div>
Example 9: 子領域でパン/ズームの直接操作挙動を不許可にする
<div style="overflow: auto;">
    <div style="touch-action: none;">
        この要素は、通常であればパンやズームにつながるすべての直接操作の相互作用についてポインタイベントを受け取ります。
    </div>
    <div>
        この要素上の直接操作の相互作用は、親の操作に消費される <MAY> があります。
    </div>
</div>
Example 10: パン/ズームの直接操作挙動を不許可にする中間の親要素
<div style="overflow: auto;">
    <div style="touch-action: pan-y;">
        <div style="touch-action: pan-x;">
            この要素は、すべての直接操作の相互作用についてポインタイベントを受け取ります。なぜなら、
            この要素は水平方向のパンのみを許可する一方で、
            (スクロール可能要素との間にある)中間の祖先は垂直方向のパンのみを許可するためです。
            その結果、ユーザーエージェントによって処理されるパン/ズームの直接操作挙動は存在しません。
        </div>
    </div>
</div>
Example 11: パン/ズームの直接操作挙動を制限する中間の親要素
<div style="overflow: auto;">
    <div style="touch-action: pan-y pan-left;">
        <div style="touch-action: pan-x;">
            この要素は、左方向にパンしていない場合にポインタイベントを受け取ります。
        </div>
    </div>
</div>

9. ポインターキャプチャ

9.1 導入

この節は規範的ではありません。

ポインターキャプチャを用いると、特定ポインターのイベント(互換マウスイベント を含む)を、その位置の通常の ヒットテスト 結果とは別の特定要素へ再ターゲットできます。これはカスタムスライダー(例: [HTML] <input type="range"> コントロールに類似)などのシナリオで有用です。スライダーのつまみ要素にポインターキャプチャを設定しておけば、ポインターがつまみから外れても値を前後にスライドさせられます。

カスタム音量スライダー
Figure 6 カスタムスライダーコントロールの例。つまみ要素を前後にスライドして値を選択する。つまみで pointerdown が発生した後、ポインターキャプチャを使うことでポインターがつまみから外れてもスライド操作を継続できる。

9.2 ポインターキャプチャの設定

ポインターキャプチャは element(型 Element)上で element.setPointerCapture(pointerId) メソッドを呼び出すことで設定されます。 このメソッドが呼び出されたとき、ユーザーエージェント は以下の手順を MUST 実行します:

  1. メソッド引数として与えられた pointerId がいずれの アクティブポインター にも一致しない場合、"NotFoundError" の DOMExceptionthrow する。
  2. pointer を、与えられた pointerId が指定する アクティブポインター とする。
  3. element接続 されていない場合 [DOM]、"InvalidStateError" の DOMExceptionthrow する。
  4. このメソッドが呼び出された時点で、elementノードドキュメント [DOM] にロックされた要素([PointerLock] の pointerLockElement)がある場合、"InvalidStateError" の DOMExceptionthrow する。
  5. pointeractive buttons state にない、または elementノードドキュメントpointerアクティブドキュメント でないなら、これ以降の手順を終了する。
  6. 指定された pointerId について、保留中ポインターキャプチャターゲットオーバーライド をこのメソッドが呼び出された Element に設定する。
Note
以前の設定/解除呼び出しが保留状態(保留中ポインターキャプチャの処理 参照)にある間に、別の設定または解除呼び出しが行われると、後の呼び出しが成功した場合はそれが前の呼び出しを上書きし、失敗した場合は前の呼び出しが有効なまま残ります。これは 暗黙的ポインターキャプチャpointerdown リスナーで解除しようとして失敗する場合にも当てはまります。

9.3 ポインターキャプチャの解除

ポインターキャプチャは element.releasePointerCapture(pointerId) メソッドを呼ぶことで要素上で明示的に解除されます。このメソッドが呼び出されたとき、ユーザーエージェント は以下の手順を MUST 実行します:

  1. メソッド引数の pointerId がいずれの アクティブポインター にも一致せず、かつこれらの手順が 暗黙的ポインターキャプチャ解除 の結果として呼び出されていないなら、"NotFoundError" の DOMExceptionthrow する。
  2. 指定された pointerId に対する hasPointerCapture が false なら、これ以降の手順を終了する。
  3. 指定された pointerId について、設定されている場合は 保留中ポインターキャプチャターゲットオーバーライド をクリアする。
Note
詳細は ポインターキャプチャの設定 節の注記を参照。

9.4 暗黙的ポインターキャプチャ

パンやズームのための 直接操作 インタラクション(タッチやタッチスクリーン上のスタイラスなど)を実装する入力は、任意の pointerdown リスナー呼び出し直前にターゲット要素上で setPointerCapture が呼ばれたかのように振る舞うべき SHOULD です。これが起きたかどうかは(例えば pointerdown リスナー内で)hasPointerCapture API を使って判断できます。次のポインタイベントが発火する前にそのポインターに対して releasePointerCapture が呼ばれなければ、キャプチャが有効であることを示す gotpointercapture イベントがターゲットへ(通常通り)ディスパッチされます。

Note
これは [PointerEvents] からの破壊的変更ですが、既存コンテンツの大多数には影響しません。一般的なプラットフォーム UX 慣習に一致するだけでなく、暗黙的キャプチャのこの設計は、開発者による明示的オプトインなしにタッチ移動イベントで毎回ヒットテストを行う必要を回避するパフォーマンス最適化を UA に可能にします(既存の主要なネイティブおよび Web のタッチ入力 API の性能特性と整合)。
Note
さらに、ユーザーエージェントは input range コントロールなど特定 UI ウィジェット上のすべての入力デバイスに対し暗黙的ポインターキャプチャ挙動を実装する場合があります(インタラクション中に多少指がフォームコントロール外へ逸脱できるようにする)。

9.5 暗黙的ポインターキャプチャ解除

pointerup または pointercancel が発火した直後に、 ユーザーエージェント は、ディスパッチされたその pointerup または pointercancel イベントの pointerId に対する 保留中ポインターキャプチャターゲットオーバーライド をクリアし MUST、続いて 保留中ポインターキャプチャの処理 手順を実行し必要なら lostpointercapture を発火する。 その後 保留中ポインターキャプチャの処理 手順の実行後、ポインターがホバーをサポートする場合、ユーザーエージェントはキャプチャなしの現在位置を反映するための境界イベントを対応して送信 MUST

ポインターキャプチャターゲットオーバーライド接続 されなくなった場合 [DOM]、 ポインターキャプチャターゲットオーバーライド はドキュメントに設定されるべき SHOULD

保留中ポインターキャプチャターゲットオーバーライド接続 されなくなった場合 [DOM]、 保留中ポインターキャプチャターゲットオーバーライド ノードはクリアされるべき SHOULD

Note
直前の 2 つの段落の結果として、キャプチャされたポインターに対応する lostpointercapture イベントが、キャプチャノードが削除された後の次回の 保留中ポインターキャプチャ処理 にてドキュメントで発火される。

要素上でポインターロック [PointerLock] が成功裏に適用された場合、ユーザーエージェントはキャプチャ済みまたはキャプチャ保留の要素が存在するなら releasePointerCapture メソッドが呼ばれたかのように手順を実行する MUST

10. 合成イベントと予測イベント

Note
本仕様は UA がポインター移動データをどのように合成または予測すべきかは定義しません。ここではその情報へアクセスする API のみを規定します。

10.1 合成イベント

性能上の理由から、UA はポインターの pointermove イベントを、ポインターの 測定可能プロパティ (座標・圧力・接線圧力・傾き・ねじれ・接触領域など)が更新される度に必ず送らないことがあります。代わりに複数の変化を一つの pointermove または pointerrawupdate イベントへ合成(結合・統合)する可能性があります。これは UA が行うイベント処理量を減らす助けになりますが、高速かつ大きな移動において位置追跡の粒度と忠実度を下げる結果になります。getCoalescedEvents メソッドを用いることで、アプリケーションは未合成の生の位置変化にアクセスでき、より正確な処理が可能となります。例えばお絵描きアプリでは未合成イベントによって実際のポインター移動により近い滑らかな曲線を描画できます。

曲線の拡大表示。合成済みと未合成のポイントを表示。
Figure 7 お絵描きアプリの曲線例 — pointermove イベントの合成済み座標(灰色)だけでは角ばった線になるが、getCoalescedEvents() が提供するより細かな点(赤丸)を使うとより滑らかな近似になる。

PointerEvent は関連付けられた 合成イベントリスト(0 個以上の PointerEvent のリスト)を持ちます。信頼できる pointermove および pointerrawupdate イベントでは、このリストは当該イベントへ合成されたすべての PointerEvent の列です。親となる信頼できる pointermove / pointerrawupdate イベントはこれら合成イベントの累積を表しますが(表示リフレッシュレート調整など)追加処理を含む場合があります。このためそれらのイベントの合成イベントリストは常に少なくとも 1 つのイベントを含みます。他の信頼できるイベント型では空リストです。非信頼イベントではコンストラクタに渡された値で初期化されます。

Note
親イベントは合成イベントの要約・集約なので、開発者は親イベントか合成イベントすべてかのいずれかだけを処理すればよく、両方を処理する必要は通常ありません。
Note
信頼できるイベントが 合成イベントリスト を含んだ状態で JavaScript から再ディスパッチされると、イベントディスパッチアルゴリズムはイベント本体の isTrustedfalse に設定しますが、リスト内のイベントの同ビットは元の true のまま変更されません。

信頼できるイベントの合成イベントリスト内の各イベントは以下を持ちます:

Example 12: 合成イベントリストを使ったシンプルなキャンバス描画アプリ
<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>
Note
PointerEvent の属性は合成イベントリスト内のイベントを最もよく表現する形で初期化されます。具体的な初期化手順は本仕様では規定しません。

ディスパッチされるすべてのイベント順序は元のイベントの実際の順序と一致しなければなりません MUST。 例えば pointerdown が合成済み pointermove イベントのディスパッチを引き起こす場合、UA はまず当該 pointerId のすべての合成イベントを含む一つの pointermove をディスパッチし、その後 pointerdown をディスパッチ MUST

Note

以下は増加する 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 件

10.2 予測イベント

一部 UA には一連の確認済みポインター移動後に、(直前のジェスチャーイベントや速度/軌跡に基づいて)将来のポインター移動位置を予測できる組み込みアルゴリズムがあります。アプリケーションは getPredictedEvents メソッドでこの情報を使い、予測位置へ先行描画して認知遅延を減らし、実際の点が到着したら予測点を破棄できます。

合成ポイントで描いた線とその先の予測ポイント
Figure 8 左下から右上への描画ジェスチャ結果の線を例示。pointermove の合成座標と、UA が予測した未来ポイント(灰色)を表示。

PointerEvent には関連付けられた 予測イベントリスト(0 個以上の PointerEvent のリスト)があり、信頼できる pointermove イベントでは UA が今後続くと予測する PointerEvent の列です。他の信頼できるイベント型では空リストです。非信頼イベントではコンストラクタに渡された値で初期化されます。

Note

pointerrawupdate イベントは非空の 合成イベントリスト を持つ場合がありますが、性能上の理由からその 予測イベントリスト は通常空です。

Note
信頼できるイベントが 予測イベントリスト を含んだ状態で再ディスパッチされると、ディスパッチアルゴリズムはイベント本体の isTrustedfalse に設定しますがリスト内の同ビットは元の true のままです。

リスト内のイベント数や現在のタイムスタンプからの距離は UA と使用する予測アルゴリズムにより決定されます。

信頼できるイベントの予測イベントリスト内の各イベントは以下を持ちます:

Note

著者は予測イベントを次のポインターイベントがディスパッチされるまでのみ有効な予測と見なすべきです。UA がどれほど先を予測するかによっては、通常のポインターイベントが一部予測イベントのタイムスタンプより早くディスパッチされる可能性があります。

Example 13: 合成イベントと予測イベントを用いた描画の概念的アプローチ

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);
    }
});

10.3 合成イベント/予測イベントリストの構築と維持

信頼できる PointerEvent が生成される際、UA は各イベント(その 合成イベントリスト予測イベントリスト 中)に対し以下の手順を実行するべき SHOULD:

  1. イベントの pointerId / pointerType / isPrimary および isTrusted を親ポインタイベントに合わせる。
  2. イベントの cancelablebubbles を false に設定(これらは単独ではディスパッチされないため)。
  3. イベント自身の 合成イベントリスト予測イベントリスト を空リストに設定。
  4. その他すべての属性を既定の PointerEvent 値で初期化。

信頼できる PointerEventtarget が変更されたとき、UA は SHOULD、その 合成イベントリスト予測イベントリスト 内の各イベントについて:

  1. イベントの target を親ポインタイベントの target と一致させる。

11. マウスイベントとの互換マッピング

現在存在する大多数の Web コンテンツはマウスイベントのみを前提にコーディングされています。以下では、ユーザー エージェント がこのコンテンツとの互換性のために汎用的なポインター入力をマウスイベントへ MAY マッピングするアルゴリズムを記述します。

マウスイベントとの互換マッピングは本仕様の OPTIONAL な機能です。ユーザーエージェントは既存のレガシーコンテンツとの最良の互換性のためにこの機能をサポートすることが推奨されます。

Note

高いレベルでは、互換マウスイベントはそれぞれのポインタイベントと「インターリーブ」されることを意図しています。ただしこの順序は必須ではなく、互換マウスイベントを実装するユーザーエージェントは、相対的な順序を維持する限りマウスイベントのディスパッチを遅延またはグループ化しても MAY です。

特にタッチスクリーン入力の場合、ユーザーエージェントは追加のジェスチャ認識ヒューリスティックを適用しても MAY です(著者が touch-action により明示的に抑止しない限り)。pointerdown イベントと pointerup イベントの間のイベント列では、ジェスチャ認識はジェスチャを検出/無視するため pointerup まで待つ必要がある場合があります。その結果、ユーザーエージェントが特定ジェスチャとして意図されていないと判断した場合、互換マウスイベントは全シーケンスの最後の pointerup 後にまとめてディスパッチされることがあります。ユーザーエージェントのジェスチャ認識に関するこれらの詳細は本仕様で定義されず、実装間で異なる可能性があります。

互換マウスイベントをサポートするかどうかに関わらず、ユーザーエージェントは click, auxclick, contextmenu イベントを常に MUST サポートしなければなりません。これらのイベントは型が PointerEvent であり、従って 互換マウスイベント ではないためです。ポインタイベント中に preventDefault を呼び出しても click, auxclick, contextmenu が発火するかどうかに影響を与えては MUST NOT なりません。

Note

contextmenu, focus, blur といった高レベルイベントの一部の相対的順序はポインタイベントとの関係で未定義であり、ユーザーエージェント間で異なります。例えば、あるユーザーエージェントでは contextmenupointerup の後に続く一方、別のユーザーエージェントでは pointeruppointercancel の前に来ることがあり、キーボード操作など対応するポインタイベントなしに発火する状況もあります。

さらに、ユーザーエージェントは click, auxclick, contextmenu イベントを発火すべきかどうか独自のヒューリスティックを適用する場合があります。他の(非プライマリ)同種ポインター、または異なる種類の他のプライマリポインターが存在する場合、これらのイベントを発火しない選択をすることがあります。指の接触中に移動が大きすぎるなどして「クリーンな」タップ/クリック/ロングプレスでないと判断された場合、click, auxclick, contextmenu イベントを発火しないこともあります。これらの挙動は本仕様で定義されず、実装間で異なる可能性があります。

特記なき限り、マッピングされた任意のマウスイベントのターゲットは、そのターゲットがもはや自身の ownerDocument のツリーに参加していない場合を除き、対応するポインタイベントのターゲットと同じであるべき SHOULD です。この場合、マウスイベントは削除時点での元のターゲットの最近接祖先ノード(依然ツリーに参加しているもの)で発火すべきであり、新しいターゲットノードに基づいてマウスイベント用の新しいイベントパスが構築されます。

著者は pointerdown イベントをキャンセルすることで特定の互換マウスイベントの生成を防止できます。

マウスイベントはポインターが押下状態にあるときのみ防止できます。ホバー中のポインター(例: ボタンが押されていないマウス)ではマウスイベントを防止できません。

mouseover, mouseout, mouseenter, mouseleave イベントは(ポインターが押下されていても)防止されることはありません。

ポインタイベントの EventListenerpassive [DOM] に設定されている場合、互換マウスイベントは防止できません。

11.1 レガシーマウスポインターの有効位置の追跡

プライマリポインター のみが互換マウスイベントを生成できますが、複数のプライマリポインター が同時にアクティブとなり、それぞれが独自の互換マウスイベントを生成することがあります。MouseEvent に依存するスクリプトとの互換性のため、マウス遷移イベント(mouseover, mouseout, mouseenter, mouseleave)は 単一 のレガシーマウス入力の移動をシミュレートすべき SHOULD です。これは各イベントターゲットの入出状態が [UIEVENTS] に従い有効であることを意味します。ユーザーエージェントは文書内で レガシーマウスポインターの有効位置 を以下のように維持することでこれを保証すべき SHOULD です。

pointerdown, pointerup, pointermove イベント、または window 上の pointerleave イベントを発火する直前に、ユーザーエージェントは以下の手順を SHOULD 実行します:

  1. T をディスパッチされる pointerdown, pointerup, pointermove イベントのターゲットとする。pointerleave イベントの場合は T を未設定にする。
  2. T と現在の レガシーマウスポインターの有効位置 が両方未設定、または等しい場合、これ以降の手順を終了する。
  3. 現在の レガシーマウスポインターの有効位置 から T へマウスが移動するものとして [UIEVENTS] に従い mouseover, mouseout, mouseenter, mouseleave をディスパッチする。現在の レガシーマウスポインターの有効位置 または T の未設定値はウィンドウ外のマウス位置と見なす。
  4. レガシーマウスポインターの有効位置T に設定する。
Note

レガシーマウスポインターの有効位置 は、ポインター遷移イベント(pointerover, pointerout, pointerenter, pointerleave)から対応するレガシーマウス遷移イベント(mouseover, mouseout, mouseenter, mouseleave)への直接マッピングが常に可能とは限らない事実をモデル化します。以下のアニメーションは、ユーザーエージェントが 2 つのプライマリポインターを単一のレガシーマウス入力で整合させるために、ポインター遷移イベントより多くのレガシーマウス遷移イベントをディスパッチする必要がある例を示します。

Figure 9 同時に存在するマウスポインター(白いカーソル)とタッチポインター(白い「手」カーソル)が単一のレガシーマウス入力(オレンジのカーソル)を 2 つのポインター間で移動させている例。

このアニメーションでは、マウスクリックとタッチタップの間の期間に注目してください。ボタン 1 は(「実際の」マウスポインターがこの期間中ボタン矩形を離れていないため)pointerout を受け取りませんが、タッチタップでボタン 2 へ レガシーマウスポインターの有効位置 が移動した際に mouseout を受け取ります。同様に、タッチタップとマウスがボタン 1 を離れる直前の期間では、同じ理由でボタン 1 は pointerover を受け取りませんが、レガシーマウスポインターの有効位置 が再度ボタン 1 内に戻ったとき mouseover を受け取ります。

11.2 ホバーをサポートするデバイス向けのマッピング

ユーザーエージェントがホバーをサポートするデバイスのポインタイベントをディスパッチする際は、以下の手順を SHOULD 実行します:

  1. ディスパッチ対象のポインタイベントの isPrimaryfalse の場合、そのポインタイベントをディスパッチして手順終了。
  2. ディスパッチ対象が pointerdown, pointerup, pointermove イベント、または window 上の pointerleave イベントである場合、レガシーマウスポインターの有効位置の追跡 で述べる互換マウス遷移イベントをディスパッチ。
  3. ポインタイベントをディスパッチ。
  4. ディスパッチされたポインタイベントが pointerdown でイベントが キャンセル された場合、この pointerTypePREVENT MOUSE EVENT フラグを設定。
  5. PREVENT MOUSE EVENT フラグがこの pointerType に設定されていない場合かつディスパッチされたポインタイベントが以下のいずれか:
  6. ディスパッチされたポインタイベントが pointerup または pointercancel であれば、当該 pointerTypePREVENT MOUSE EVENT フラグをクリア。

11.3 ホバーをサポートしないデバイス向けのマッピング

多くのタッチスクリーンなど一部デバイスはアクティブ状態でない間に座標(または座標集合)をホバーできません。マウスイベントを前提にした既存コンテンツではマウスがイベントを生成することを仮定し、次の性質が一般に成り立ちます:

Note
ホバーはマウス向けに設計されたコンテンツで UI 要素の可視性切り替え(例: 「ホバーメニュー」)に使われることがあります。このようなコンテンツは ホバーをサポートしないデバイス と非互換なことが多く、本仕様はこのシナリオへの互換マッピングや挙動を定義しません。将来の版で検討されます。

これによりユーザーエージェントはこれら入力デバイス向けに異なるマッピングを提供する必要があります。ユーザーエージェントが ホバーをサポートしない デバイスのポインタイベントをディスパッチする際は以下の手順を SHOULD 実行します:

  1. ディスパッチ対象のポインタイベントの isPrimaryfalse ならポインタイベントをディスパッチして終了。
  2. ディスパッチ対象が pointerover で、このポインターの pointerdown がまだディスパッチされていないなら(レガシーなマウス専用コードとの互換のため)mousemove を発火。
  3. ディスパッチ対象が pointerdown, pointerup, pointermove イベント、または window 上の pointerleave なら、レガシーマウスポインターの有効位置の追跡 に従い互換マウス遷移イベントをディスパッチ。
  4. ポインタイベントをディスパッチ。
  5. ディスパッチされたポインタイベントが pointerdown でイベントが キャンセル された場合、この pointerTypePREVENT MOUSE EVENT フラグを設定。
  6. PREVENT MOUSE EVENT フラグが設定されていない場合かつディスパッチされたポインタイベントが以下のいずれかなら:
  7. ディスパッチされたポインタイベントが pointerup または pointercancel なら、この pointerTypePREVENT MOUSE EVENT フラグをクリア。

ユーザーエージェントが [TOUCH-EVENTS] で定義される Touch Events と Pointer Events の両方をサポートする場合、ユーザー エージェント は本節で述べる互換マウスイベントと [TOUCH-EVENTS] に記載の フォールバックマウスイベント両方 を生成しては MUST NOT なりません。

Note

ホバーをサポートしない プライマリポインター(例: タッチスクリーン上の一本指)による要素のアクティベーション(click)は通常以下のイベントシーケンスを生成します:

  1. mousemove
  2. pointerover
  3. pointerenter
  4. mouseover
  5. mouseenter
  6. pointerdown
  7. mousedown
  8. 0 個以上の pointermovemousemove (ポインターの移動に依存)
  9. pointerup
  10. mouseup
  11. pointerout
  12. pointerleave
  13. mouseout
  14. mouseleave
  15. click

ただし、このインタラクション中に pointerdown イベントが キャンセル された場合、イベント列は次のようになります:

  1. mousemove
  2. pointerover
  3. pointerenter
  4. mouseover
  5. mouseenter
  6. pointerdown
  7. 0 個以上の pointermove (ポインターの移動に依存)
  8. pointerup
  9. pointerout
  10. pointerleave
  11. mouseout
  12. mouseleave
  13. click

12. セキュリティとプライバシーの考慮事項

この付録では Pointer Events 実装におけるセキュリティおよびプライバシー上の考慮事項を論じます。議論は本仕様で定義されるイベントモデル・API・イベントの実装から直接生じる問題に限定します。

本仕様で定義される多くのイベント型はユーザー操作に応じてディスパッチされます。これにより悪意あるイベントリスナーはユーザーが通常秘匿したいと考える情報(ページ操作時のマウス/スタイラス/指の正確な経路・動きなど)へアクセスできてしまう可能性があります。

ポインタイベントは(ユーザーのデバイスがサポートしている場合)ペン入力の角度や傾き、接触面のジオメトリ、スタイラスやタッチスクリーンに加えられた圧力など追加情報を含みます。角度・傾き・ジオメトリ・圧力に関する情報はユーザーのデバイス上のセンサーに直接関連しているため、本仕様はオリジンにこれらセンサーへのアクセスを許可することになります。

これらのセンサーデータや使用された入力機構(マウス・タッチ・ペン)を特定できる能力は、ユーザーまたはユーザーのデバイス/環境に関する特性を推測するために利用され得ます。推測された特性やデバイス/環境情報はそれ自体がセンシティブである可能性があり、悪意あるサイトがユーザーが支援技術を使用しているかを追加推測することを許す場合があります。またこの情報はユーザープロファイルの構築やユーザーの「フィンガープリンティング」および追跡の試みに潜在的に利用され得ます。

緩和策として、ユーザーエージェントは特定のセンサーデータ(角度・傾き・圧力など)へのアクセスをユーザーが無効化できる能力を含めたり、明示的なユーザーのオプトイン後のみ公開することを検討できます。

本仕様は著者が「予測イベント」にアクセスする方法を定義します。仕様自体はユーザーエージェントが予測に使用すべきアルゴリズムを定義しません。仕様策定者はアルゴリズムがユーザーが実行中の現在のジェスチャに関連する直前のポインタイベントのみを頼りにすることを想定しています。ユーザーエージェントは、具体的な予測アルゴリズム実装がユーザーについてセンシティブ情報を明らかにしたりフィンガープリンティング/追跡に利用され得る追加データ(複数サイトにまたがるユーザーの完全なインタラクション履歴など)に依存しないことを保証する責任があります。

これらの考慮事項以外では、ワーキンググループは本仕様が以下を満たすと考えます:

13. 用語集

この節は規範的ではありません。

active buttons state
ポインターが buttons プロパティに非ゼロ値を持つ状態。マウスでは少なくとも 1 つのボタンが押下されている状態。タッチではデジタイザとの物理的接触がある状態。ペンではペンがデジタイザに物理接触しているか、ホバー中に少なくとも 1 つのボタンが押下されている状態。
active document
アクティブポインター に対し、そのポインターから最後のイベントを受け取った文書。
active pointer
イベントを生成できる任意のタッチ接触、ペン/スタイラス、マウスカーソルその他のポインター。特定ポインター(固有の pointerId で識別)が文書内で追加イベントを生成し得る場合、そのポインターはアクティブと見なされる。例:
  • 接続されたマウスは常にアクティブ。
  • 画面上のタッチ接触はアクティブと見なされる。
  • タッチ接触またはペン/スタイラスがデジタイザの検出範囲外に持ち上げられた場合、それはアクティブではなくなる。
Note
一部プラットフォームでは、アクティブポインターの集合にユーザーエージェントへターゲットされていない入力(他アプリケーションにターゲットされたものなど)を含むすべてのポインター入力が含まれます。
canceled event
preventDefault() の呼び出し、イベントハンドラで false を返すこと、または [UIEVENTS] や [HTML] で定義される他の手段によって既定動作が防止されたイベント。
contact geometry
デジタイザ上の入力(もっとも一般的にはタッチ)のバウンディングボックス。これは通常 1 ピクセルより粗いポインター入力解像度を持つデバイスを指す。報告しないデバイスもある。
digitizer
接触および/または近接状態にある入力を検知できる表面を備えた入力検知装置のタイプ。もっとも一般的にはタッチ接触またはペン/スタイラスからの入力を検知する表面。
direct manipulation
一部ユーザーエージェント(タッチスクリーンデバイス上のブラウザなど)は「直接操作」メタファーを実装し、ポインターがコントロールと相互作用するだけでなく現在のページを直接パン/ズームして直接的な物理接触の錯覚を与える。例えば、タッチスクリーンデバイスのユーザーは指やスタイラスでページを「つかんで」ポインターを動かすことでパンでき、ページを直接操作する。これはスクロールバーを使ってパンする通常のデスクトップ/ラップトップ上のマウスポインターとは対照的。
Note
一部の場合、タッチパッド(ラップトップなどにある)で「ドラッグ」することでスクロールできる。しかしこれは一般にタッチパッドが「偽の」マウスホイールイベントを生成することで達成され、直接操作には該当しない。
hit test
ユーザーエージェントがポインタイベントのターゲット要素を決定する過程。通常、ポインター位置と文書内の要素の視覚的レイアウト(画面メディア上)を考慮して決定される。
measurable properties

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 とは見なされない。

pointer
マウス・ペン・タッチ接触など、画面上の特定座標(または座標集合)をターゲットできる入力デバイスのハードウェア非依存表現。

A. 謝辞

本ドキュメントに統合されたものを含め、提案や推奨を示してくださった多くの方々に深く感謝します。議長は以下の過去および現在のグループメンバー並びに参加者の貢献をここに認めます: 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。

B. 改訂履歴

この節は規範的ではありません。

以下は本仕様の版間における、[PointerEvents3] 仕様と比較した重要かつ主要な編集上の変更点の情報的要約です。 本仕様のエディタドラフト完全な改訂履歴 も参照してください。

C. IDL インデックス

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;
};

D. 参考文献

D.1 規範参照

[CSS-OVERFLOW-3]
CSS Overflow Module Level 3. Elika Etemad; Florian Rivoal. W3C. 7 October 2025. W3C 作業草案. URL: https://www.w3.org/TR/css-overflow-3/
[CSS21]
Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification. Bert Bos; Tantek Çelik; Ian Hickson; Håkon Wium Lie. W3C. 7 June 2011. W3C 勧告. URL: https://www.w3.org/TR/CSS2/
[CSSOM-VIEW]
CSSOM View Module. Simon Fraser; Emilio Cobos Álvarez. W3C. 16 September 2025. W3C 作業草案. URL: https://www.w3.org/TR/cssom-view-1/
[DOM]
DOM Standard. Anne van Kesteren. WHATWG. Living Standard. URL: https://dom.spec.whatwg.org/
[ECMASCRIPT]
ECMAScript Language Specification. Ecma International. URL: https://tc39.es/ecma262/multipage/
[HTML]
HTML Standard. Anne van Kesteren; Domenic Denicola; Dominic Farolino; Ian Hickson; Philip Jägenstedt; Simon Pieters. WHATWG. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[infra]
Infra Standard. Anne van Kesteren; Domenic Denicola. WHATWG. Living Standard. URL: https://infra.spec.whatwg.org/
[PointerLock]
Pointer Lock. Vincent Scheib. W3C. 27 October 2016. W3C 勧告. URL: https://www.w3.org/TR/pointerlock/
[RFC2119]
Key words for use in RFCs to Indicate Requirement Levels. S. Bradner. IETF. March 1997. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc2119
[RFC8174]
Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words. B. Leiba. IETF. May 2017. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc8174
[TOUCH-EVENTS]
Touch Events. Doug Schepers; Sangwhan Moon; Matt Brubeck; Arthur Barstow. W3C. 10 October 2013. W3C 勧告. URL: https://www.w3.org/TR/touch-events/
[UIEVENTS]
UI Events. Gary Kacmarcik; Travis Leithead. W3C. 7 September 2024. W3C 作業草案. URL: https://www.w3.org/TR/uievents/
[WEBIDL]
Web IDL Standard. Edgar Chen; Timothy Gu. WHATWG. Living Standard. URL: https://webidl.spec.whatwg.org/

D.2 参考参照

[COMPAT]
Compatibility Standard. Mike Taylor. WHATWG. Living Standard. URL: https://compat.spec.whatwg.org/
[PointerEvents]
Pointer Events. Jacob Rossi; Matt Brubeck. W3C. 4 April 2019. W3C 勧告. URL: https://www.w3.org/TR/pointerevents/
[PointerEvents3]
Pointer Events. Patrick Lauke; Robert Flack. W3C. 1 May 2025. CRD. URL: https://www.w3.org/TR/pointerevents3/
[WCAG22]
Web Content Accessibility Guidelines (WCAG) 2.2. Michael Cooper; Andrew Kirkpatrick; Alastair Campbell; Rachael Bradley Montgomery; Charles Adams. W3C. 12 December 2024. W3C 勧告. URL: https://www.w3.org/TR/WCAG22/