포인터 이벤트

레벨 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 (풀 리퀘스트, 새 이슈, 열린 이슈)
public-pointer-events@w3.org 제목 줄은 [pointerevents4] … 메시지 주제 … (보관함)
브라우저 지원:
caniuse.com

개요

이 명세의 기능들은 마우스, 펜, 터치스크린 등 장치로부터 하드웨어에 구애받지 않는 포인터 입력을 처리하기 위한 이벤트와 관련 인터페이스를 설명하는 W3C 권고안인 Pointer Events에 정의된 내용을 확장하거나 수정합니다. 기존 마우스 기반 콘텐츠와의 호환성을 위해, 이 명세는 다른 포인터 장치 타입에 대해 Mouse Events를 발생시키는 매핑도 설명합니다.

이 문서의 상태

이 섹션은 해당 문서가 발행된 시점의 상태를 설명합니다. 현재 W3C 발행물 목록 및 이 기술 보고서의 최신 개정은 W3C 표준 및 초안 색인에서 찾을 수 있습니다.

이 명세는 [PointerEvents3]의 업데이트입니다. 더 많은 사용 사례를 지원하는 편집상 명확화와 새로운 기능을 포함합니다.

이 문서는 Pointer Events Working Group권고안 절차(Recommendation track)를 사용하여 Working Draft로 발행한 것입니다.

Working Draft로의 발행은 W3C 및 그 회원의 보증을 의미하지 않습니다.

이는 초안 문서로서 언제든지 다른 문서에 의해 업데이트, 대체, 혹은 폐기될 수 있습니다. 진행 중인 작업으로서가 아닌 방식으로 이 문서를 인용하는 것은 부적절합니다.

이 문서는 W3C 특허 정책 하에서 활동하는 그룹이 제작했습니다. W3C이 그룹 산출물과 관련해 공개된 특허 공지의 공개 목록을 유지합니다. 해당 페이지에는 특허 공개 방법에 대한 지침도 포함되어 있습니다. 개인이 Essential Claim(s)을 포함한다고 믿는 특허를 실제로 알고 있는 경우 W3C 특허 정책 6절에 따라 정보를 공개해야 합니다.

이 문서는 2025년 8월 18일 W3C 프로세스 문서에 의해 관리됩니다.

1. 소개

이 섹션은 비규범적입니다.

오늘날 대부분의 [HTML] 콘텐츠는 마우스 입력을 사용하거나 이를 위해 설계되었습니다. 입력을 사용자 정의 방식으로 처리하는 경우 일반적으로 [UIEVENTS] 마우스 이벤트에 맞춰 코드를 작성합니다. 그러나 최신 컴퓨팅 기기들은 터치스크린 및 펜 입력을 포함한 다른 형태의 입력을 통합하고 있습니다. 이러한 각 입력 형태를 개별적으로 처리하기 위한 이벤트 타입들이 제안되었습니다. 하지만 이 접근 방식은 새 입력 타입을 지원할 때 종종 불필요한 로직 및 이벤트 처리 오버헤드 중복을 야기합니다. 이는 콘텐츠가 한 가지 기기 타입만을 염두에 두고 작성될 때 호환성 문제를 자주 발생시킵니다. 또한 기존 마우스 기반 콘텐츠와의 호환성을 위해 대부분의 user agents는 모든 입력 타입에 대해 마우스 이벤트를 발생시킵니다. 이로 인해 특정 마우스 이벤트가 실제 마우스 장치를 나타내는 것인지, 호환성을 위해 다른 입력 타입으로부터 생성된 것인지 모호해져 두 기기 타입을 동시에 대상으로 코딩하기 어려워집니다.

다중 입력 타입에 대한 코딩 비용을 줄이고 위에서 설명한 마우스 이벤트의 모호성을 해결하기 위해 이 명세는 보다 추상화된 입력 형태인 포인터(pointer)를 정의합니다. 포인터는 마우스 커서, 펜, 터치(멀티터치 포함) 또는 기타 포인팅 입력 장치에 의해 화면에 만들어지는 임의의 접촉 지점일 수 있습니다. 이 모델은 사용자가 어떤 하드웨어를 가지고 있든 잘 동작하는 사이트 및 애플리케이션을 더 쉽게 작성할 수 있게 해 줍니다. 기기별 처리가 필요한 시나리오를 위해 이 명세는 이벤트를 생성한 기기 타입을 검사할 수 있는 속성도 정의합니다. 주된 목표는 다양한 기기에서의 포인터 입력을 교차 지원하는 단일 이벤트/인터페이스 집합을 제공하면서도 향상된 경험을 위해 필요한 경우에만 기기별 처리를 허용하는 것입니다.

추가적인 핵심 목표는 멀티 스레드 사용자 에이전트가 스크립트 실행에 블로킹되지 않고 패닝 및 줌(예: 터치스크린에서 손가락이나 스타일러스)과 같은 직접 조작 동작을 처리할 수 있도록 하는 것입니다.

Note

이 명세는 다양한 포인터 입력에 대한 통합 이벤트 모델을 정의하지만, 키보드나 키보드와 유사한 인터페이스(예: 터치스크린 전용 기기에서 실행되는 화면 낭독기나 유사한 보조 기술로, 포커스 가능한 컨트롤 및 요소를 순차적으로 탐색하도록 하는 인터페이스)와 같은 다른 형태의 입력은 다루지 않습니다. 사용자 에이전트가 이러한 인터페이스에 대한 응답으로 포인터 이벤트를 추가로 생성하도록 선택할 수는 있지만, 이 시나리오는 본 명세에서 다루지 않습니다.

첫 단계로 작성자들은 focus, blur, click과 같은 고수준 이벤트에 응답함으로써 모든 형태의 입력에 대해 동등한 기능을 제공하도록 권장됩니다. 그러나 저수준 이벤트(예: Pointer Events)를 사용할 때에는 모든 입력 타입이 지원되도록 하는 것이 바람직합니다. 키보드 및 키보드 유사 인터페이스의 경우 명시적인 키보드 이벤트 처리가 추가로 필요할 수 있습니다. 자세한 내용은 Keyboard Accessible [WCAG22]를 참조하십시오.

포인터 입력은 마우스, 펜, 터치 등 다양한 입력 소스를 결합합니다
Figure 1 포인터는 화면의 특정 좌표(또는 좌표 집합)를 대상으로 할 수 있는 입력 장치를 하드웨어에 구애받지 않고 표현한 것입니다.

범용 포인터 입력을 처리하는 이벤트는 마우스 이벤트와 매우 유사합니다: pointerdown, pointermove, pointerup, pointerover, pointerout, 등등. 이는 마우스 이벤트에서 포인터 이벤트로 콘텐츠를 쉽게 마이그레이션할 수 있게 합니다. 포인터 이벤트는 (클라이언트 좌표, 대상 요소, 버튼 상태 포함) 마우스 이벤트에 존재하는 일반적인 모든 속성에 더해 압력, 접촉 기하, 기울기와 같은 다른 입력 형태를 위한 새 속성도 제공합니다. 작성자는 의미 있는 곳에서는 서로 다른 입력 타입 사이에서 로직을 공유하고, 최상의 경험을 위해 필요한 경우에만 특정 입력 타입에 맞춰 커스터마이징할 수 있습니다.

포인터 이벤트가 다양한 입력 장치로부터 발생하더라도, 다른 기기별 이벤트 집합으로부터 생성된 것으로 정의되지는 않습니다. 호환성을 위해 가능하며 권장되지만, 이 명세는 (마우스 이벤트나 터치 이벤트와 같은) 다른 기기별 이벤트 지원을 요구하지 않습니다. 사용자 에이전트는 어떤 다른 기기 이벤트도 지원하지 않고 포인터 이벤트만 지원할 수도 있습니다. 마우스 전용 이벤트에 맞춰 작성된 콘텐츠와의 호환성을 위해 이 명세는 마우스가 아닌 장치의 포인터 입력을 기반으로 호환성 마우스 이벤트를 생성하는 방법을 설명하는 선택적 섹션을 제공합니다.

Note

이 명세는 [TOUCH-EVENTS]에 정의된 터치 이벤트와 포인터 이벤트를 모두 지원하는 사용자 에이전트의 예상 동작에 대한 어떠한 조언도 제공하지 않습니다. 두 명세 간 관계에 대한 추가 정보는 Touch Events 커뮤니티 그룹을 참조하십시오.

2. 적합성

비규범적이라고 표시된 섹션뿐 아니라, 이 명세의 모든 작성 지침, 다이어그램, 예시, 그리고 노트는 비규범적입니다. 이 명세의 나머지 모든 것은 규범적입니다.

이 문서에서 MAY, MUST, MUST NOT, OPTIONAL, SHOULD라는 키워드는 BCP 14 [RFC2119] [RFC8174]에 따라, 여기에서처럼 모두 대문자로 나타나는 경우에 한하여 해석되어야 합니다.

3. 예시

이 섹션은 비규범적입니다.

아래는 이 명세의 일부 API가 작성자에 의해 어떻게 사용될 수 있는지 보여주는 기본적인 예시들입니다. 더 구체적인 추가 예시는 이 문서의 관련 섹션들에 제공됩니다.

Example 1: 기능 감지 및 이벤트 바인딩
/* Pointer Events 또는 기존 touch/mouse 중 하나에 바인딩 */

if (window.PointerEvent) {
    // Pointer Events가 지원되면 포인터 이벤트만 리슨
    target.addEventListener("pointerdown", function(e) {
        // 필요하다면 e.pointerType에 따라 별도 로직 적용
        // 서로 다른 touch/pen/mouse 동작 구분
        ...
    });
    ...
} else {
    // 기존 touch/mouse 이벤트 핸들러
    target.addEventListener('touchstart', function(e) {
        // 호환성 마우스 이벤트 및 click 방지
        e.preventDefault();
        ...
    });
    ...
    target.addEventListener('mousedown', ...);
    ...
}

// 키보드 처리를 위한 추가 이벤트 리스너
...
Example 2: 사용자 입력 타입 감지
window.addEventListener("pointerdown", detectInputType);

function detectInputType(event) {
    switch(event.pointerType) {
        case "mouse":
            /* 마우스 입력 감지됨 */
            break;
        case "pen":
            /* 펜/스타일러스 입력 감지됨 */
            break;
        case "touch":
            /* 터치 입력 감지됨 */
            break;
        default:
            /* pointerType이 비어 있음(감지 불가) 또는 UA 고유 커스텀 타입 */
    }
}
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: 스크립트에서 신뢰할 수 없는(untrusted) 포인터 이벤트 발생
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;
    // 고유 ID 존재 여부 확인
    if (uniqueId == 0) {
        return;
    }
    // 기기에 색상이 이미 할당되었는지 확인
    if (map.has(uniqueId)) {
        return;
    }
    // 기기에 색상 할당
    let newColor = getNewColor();
    map.set(uniqueId, newColor);
    return newColor;
}

function getNewColor() {
    /* 어떤 색상 값 반환 */
}
</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

이 이벤트를 발생시키는 포인터에 대한 고유 식별자입니다. user agents는 기본 마우스 포인터용으로 일반적인 pointerId0 또는 1을 예약할 수 MAY 있습니다. pointerId-1은 포인팅 장치 이외에 의해 생성된 이벤트를 나타내기 위해 예약되고 사용되어야 MUST 합니다. 기타 포인터에 대해서는 user agent가 pointerId 값을 할당하는 전략을 자유롭게 구현할 수 있습니다. 그러나 모든 active pointers는 최상위 탑 레벨 브라우징 컨텍스트 내에서 유일해야 하며 다른 탑 레벨 브라우징 컨텍스트에 의해 영향을 받아서는 MUST NOT 합니다(즉 한 브라우징 컨텍스트 밖으로 이동한다고 동일 값일 것이라 가정할 수 없음).

user agent는 이전에 사용 종료된(active에서 벗어난) pointerId 값을 재활용할 수 MAY 있고 특정 포인팅 장치에 대해 항상 동일 pointerId를 재사용할 수도 MAY 있습니다(예: 다중 사용자 협업 앱에서 특정 펜/스타일러스 입력을 고유하게 식별). 그러나 후자의 경우 다른 페이지/도메인 간 핑거프린팅 및 추적 가능성을 최소화하기 위해 그 pointerId는 페이지/세션 수명 동안에만 명시적으로 연관되어야 MUST 하며 새 세션에서 다시 사용될 때는 새로운 무작위 pointerId를 선택해야 MUST 합니다.

Note

pointerId 선택 알고리즘은 구현별입니다. 작성자는 값이 고유 식별자 이상의 의미를 가진다고 가정해서는 안 됩니다. 예를 들어 user agent가 단순히 활성화 순서대로 0부터 번호를 붙일 수 있지만 반드시 단조 증가를 보장하지는 않습니다. 특정 장치에 대해 동일 pointerId를 재사용할지 여부는 개별 구현에 달려 있으므로 이에 의존하지 않는 것이 좋고 대신 persistentDeviceId를 참조하는 것이 권장됩니다.

width

포인터의 contact geometry X축 크기(폭)를 CSS 픽셀 단위( [CSS21] 참조)로 나타냅니다. 이 값은 주어진 포인터에 대해 각 이벤트마다 갱신될 수 MAY 있습니다. 접촉 기하가 일반적으로 없는 입력(전통적인 마우스 등)이나 하드웨어가 실제 기하를 감지하지 못하는 경우 user agent는 기본값 1을 반환해야 MUST 합니다.

height

포인터의 contact geometry Y축 크기(높이)를 CSS 픽셀 단위로 나타냅니다. 갱신 가능성과 기본값 처리 방식은 width와 동일합니다. 접촉 기하가 없거나 감지되지 않으면 1을 반환해야 MUST 합니다.

pressure

포인터 입력의 정규화된 압력으로 범위는 [0,1]이며 각각 하드웨어가 감지 가능한 최소/최대 압력을 의미합니다. 압력을 지원하지 않는 하드웨어/플랫폼에서는 active buttons state일 때 0.5, 그 외에는 0이어야 MUST 합니다.

tangentialPressure

추가 컨트롤(예: 에어브러시 스타일러스의 손가락 휠)에 의해 설정되는 정규화된 접선 압력(배럴 압력)으로 범위는 [-1,1], 0은 중립 위치입니다. 일부 하드웨어는 [0,1] 양수 범위만 지원할 수 있습니다. 지원하지 않는 경우 값은 0이어야 MUST 합니다.

Note
속성 이름과 달리 실제 값을 생성하는 하드웨어 센서가 반드시 압력 민감형일 필요는 없습니다. 예를 들어 대부분의 에어브러시 스타일러스 손가락 휠은 지속적 압력 없이 임의 위치로 설정 가능합니다.
tiltX

Y-Z 평면과 변환기(펜/스타일러스) 축 및 Y축을 포함하는 평면 사이의 평면 각(도 단위, [-90,90] 범위)입니다. 양의 tiltX는 X 증가 방향(오른쪽)입니다. tiltXtiltY를 함께 사용하여 디지타이저에 대한 변환기의 기울기를 나타냅니다. 기울기/각도를 보고하지 않는 하드웨어/플랫폼에서는 0이어야 MUST 합니다.

tiltX 설명 다이어그램
Figure 2 양(+)의 tiltX 예.
tiltY

X-Z 평면과 변환기 축 및 X축을 포함하는 평면 사이의 평면 각(도 단위, [-90,90] 범위)입니다. 양의 tiltY는 사용자 방향(Y 증가)입니다. 나머지 의미와 사용은 tiltX 설명과 동일하며 보고되지 않는 경우 0이어야 MUST 합니다.

tiltY 설명 다이어그램
Figure 3 양(+)의 tiltY 예.
twist

변환기(펜/스타일러스)의 주축을 기준으로 한 시계 방향 회전 각도(도 단위, [0,359] 범위)입니다. twist를 보고하지 않는 경우 값은 0이어야 MUST 합니다.

altitudeAngle

변환기(펜/스타일러스)의 고도(라디안)로 범위는 [0,π/2]입니다. 0은 표면(X-Y 평면)과 평행, π/2는 표면에 수직입니다. 기울기/각도를 보고하지 않는 하드웨어/플랫폼에서는 π/2이어야 MUST 합니다.

Note
여기 정의된 altitudeAngle 기본값은 π/2로 변환기를 표면에 수직 위치로 둡니다. 이는 Touch Events - Level 2 명세에서 altitudeAngle 기본값이 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)을 나타냅니다. user agent가 마우스, 펜/스타일러스 또는 터치 입력 장치에 대해 pointer event를 발생시키는 경우 pointerType 값은 아래 표에 따라 설정되어야 MUST 합니다:

포인터 장치 유형 pointerType
Mouse mouse
Pen / stylus pen
Touch contact touch

장치 유형을 user agent가 감지하지 못하면 값은 빈 문자열이어야 MUST 합니다. 위 목록 외 추가 포인터 장치 유형을 지원하는 경우 pointerType 값은 충돌을 피하기 위해 벤더 프리픽스를 붙이는 것이 SHOULD 입니다. 이후 명세에서 다른 장치 유형에 대한 추가 규범적 값이 제공될 수 MAY 있습니다.

Note
예제 2에서 pointerType 기본 사용을 확인할 수 있습니다. 또한 user agent가 자체 커스텀 pointerType 값을 구현했거나 빈 문자열인 경우를 처리할 기본 로직을 포함해야 합니다.
isPrimary

이 포인터가 해당 포인터 유형의 primary pointer인지 여부를 나타냅니다.

persistentDeviceId

포인팅 장치 자체의 고유 식별자입니다. 하드웨어가 다중 포인터를 지원하는 경우, 포인터들이 세션 전체에서 고유하게 식별 가능한 경우에만 persistentDeviceId를 부여해야 MUST 합니다. 고유하게 식별 가능한 경우 해당 포인팅 장치에 할당된 persistentDeviceId는 세션 종료까지 유지됩니다. 값 0은 생성 장치를 식별할 수 없음을 나타내기 위해 예약되고 사용되어야 MUST 합니다. pointerId와 마찬가지로 핑거프린팅/추적 위험을 줄이기 위해 페이지/세션 수명 동안에만 명시적으로 연관되어야 MUST 하며 새 세션에서는 새 무작위 persistentDeviceId를 선택해야 MUST 합니다.

Note
디지타이저 및 포인팅 장치 하드웨어 제약으로 모든 포인터 이벤트에 대해 persistentDeviceId가 항상 제공된다고 보장할 수 없습니다. 예: 디바이스가 pointerdown 시점까지 하드웨어 id를 보고하지 못해 초기에는 0이었다가 이후 유효한 값으로 변경될 수 있습니다.
getCoalescedEvents()

coalesced events 목록을 반환하는 메서드입니다.

getPredictedEvents()

predicted events 목록을 반환하는 메서드입니다.

PointerEventInit 딕셔너리는 PointerEvent 인터페이스 생성자가 신뢰되지 않는(합성된) 포인터 이벤트를 구성하는 메커니즘을 제공합니다. 이는 [UIEVENTS]에 정의된 MouseEventInit 딕셔너리를 상속합니다. 합성 포인터 이벤트를 발생시키는 예시는 examples 섹션을 참조하세요.

event constructing stepsPointerEvent 생성 시 PointerEventInitcoalescedEventscoalesced events list로 복제하고, PointerEventInitpredictedEventspredicted events list로 복제합니다.

Note
PointerEvent 인터페이스는 UI Events에 정의된 MouseEvent를 상속합니다. 또한 CSSOM View Module에서 제안된 확장(좌표 속성을 long에서 double로 변경)을 PointerEvent에는 구현했지만 일반 MouseEvent에는 적용하지 않은 user agent라면 click, auxclick, contextmenu 이벤트 처리 시 추가 요구사항이 있습니다.

4.1.1 버튼 상태

4.1.1.1 Chorded(복합) 버튼 상호작용

마우스나 펜과 같이 다중 버튼을 지원하는 포인터 장치가 있습니다. [UIEVENTS] Mouse Event 모델에서는 각 버튼 눌림이 mousedownmouseup 이벤트를 생성합니다. 하드웨어 차이를 더 잘 추상화하고 교차 장치 입력 작성 단순화를 위해 Pointer Events는 동시에 다른 버튼이 이미 눌린 상태에서 추가 버튼을 누르는 chorded 버튼 동작에 대해 겹치는 pointerdown / pointerup 이벤트를 발생시키지 않습니다.

대신 chorded 버튼 눌림은 buttonbuttons 속성의 변화로 감지할 수 있습니다. 이 두 속성은 MouseEvent 인터페이스에서 상속되지만 의미와 값이 이후 섹션에서 재정의됩니다.

buttonbuttons 속성 수정은 포인터 이벤트에만 적용됩니다. 그러나 click, auxclick, contextmenu에서는 button, buttons 값이 [UIEVENTS]를 따라야 MUST 하며 이는 compatibility mouse events에도 동일하게 적용됩니다.

4.1.1.2 button 속성

pointerdown / pointerup에 국한되지 않고 모든 포인터 이벤트에서 버튼 상태 전환을 식별하기 위해 button 속성은 상태 변화로 이벤트를 발생시킨 장치 버튼을 나타냅니다.

장치 버튼 변화 button
이전 이벤트 이후 버튼/터치/펜 접촉 변화 없음 -1
왼쪽 마우스,
터치 접촉,
펜 접촉
0
가운데 마우스 1
오른쪽 마우스,
펜 배럴 버튼
2
X1 (뒤로) 마우스 3
X2 (앞으로) 마우스 4
펜 지우개 버튼 5
Note
마우스 드래그 중 pointermove 이벤트의 button 값은 mousemove 이벤트 값과 다를 수 있습니다. 예를 들어 오른쪽 버튼을 누른 채 이동 시 pointermove-1, mousemove2 값을 갖습니다.
4.1.1.3 buttons 속성

buttons 속성은 장치 버튼의 현재 상태를 비트마스크로 제공합니다(MouseEvent와 동일하지만 가능한 값 범위가 확장됨).

장치 버튼 현재 상태 buttons
버튼 없이 마우스 이동,
버튼 없이 호버 중인 펜 이동
0
왼쪽 마우스,
터치 접촉,
펜 접촉
1
가운데 마우스 4
오른쪽 마우스,
펜 배럴 버튼
2
X1 (뒤로) 마우스 8
X2 (앞으로) 마우스 16
펜 지우개 버튼 32

4.1.2 primary pointer

다중 포인터(예: 멀티터치) 시나리오에서 isPrimary 속성은 각 포인터 유형의 active pointers 집합 중 대표(master) 포인터를 식별하는 데 사용됩니다.

  • 특정 시점에 각 포인터 유형마다 primary pointer는 최대 하나만 존재합니다.
  • 특정 포인터 유형에서 가장 먼저 활성화된 포인터(예: 멀티터치 상호작용에서 첫 번째로 화면을 터치한 손가락)가 그 유형의 primary pointer가 됩니다.
  • primary 포인터만 compatibility mouse events를 생성합니다. 다수의 primary pointers가 있을 경우 모두 compatibility mouse events를 생성합니다.
Note
단일 포인터 상호작용을 원하는 작성자는 primary가 아닌 포인터를 무시하는 방식으로 달성할 수 있습니다(단 다중 primary pointers 관련 노트 참고).
Note
둘 이상의 포인터 장치 유형이 동시에 사용되면 각 pointerType별 포인터가 primary로 간주됩니다. 예: 터치 접촉과 마우스 커서를 동시에 이동하면 두 포인터 모두 primary입니다.
Note
일부 장치·OS·user agent는 실수로 인한 상호작용을 피하기 위해 서로 다른 포인터 유형의 동시 사용을 무시할 수 있습니다. 예를 들어 터치와 펜을 모두 지원하는 장치는 펜 사용 중 터치 입력을 무시하여(이른바 Palm Rejection) 손을 화면에 올려둘 수 있게 합니다. 현재 작성자가 이 동작을 억제할 방법은 없습니다.
Note
경우에 따라 user agent가 어떤 포인터도 primary로 표시되지 않은 상태에서 포인터 이벤트를 발생시킬 수 있습니다. 예: 특정 유형의 다중 활성 포인터 중 primary 포인터가 제거(화면을 떠남)되면 primary 포인터가 없을 수 있습니다. 또한 플랫폼이 장치 내 모든 동일 유형 active 포인터(다른 앱 대상 포함)를 고려하여 primary를 결정하는 경우, 첫(primary) 포인터가 user agent 외부에 있고 다른(non-primary) 포인터가 user agent 내부를 대상으로 하면 user agent는 isPrimary값이 false인 이벤트를 발생시킬 수 MAY 있습니다.
Note
현재 운영체제와 user agent는 일반적으로 다중 마우스 개념을 갖지 않습니다. 트랙패드와 외부 마우스가 모두 있을 때 보통 단일 장치로 취급되어 어느 장치에서든 이동은 하나의 마우스 포인터 이동으로 합쳐지고 버튼 구분도 없습니다. 따라서 일반적으로 하나의 마우스 포인터만 있으며 그것이 primary입니다.

4.1.3 PointerEvent 인터페이스를 사용한 이벤트 발행

e라는 이름의 포인터 이벤트를 fire a pointer event 한다는 것은 fire an event 알고리즘을 사용하여 PointerEvent 인터페이스 및 PointerEvent Interface와 Attributes and Default Actions에 정의된 대로 속성이 설정된 이벤트를 발행하는 것을 의미합니다.

이벤트가 gotpointercapture, lostpointercapture, click, auxclick, contextmenu가 아니라면 해당 PointerEvent에 대해 process pending pointer capture 단계를 수행합니다.

Determine the target 단계는 다음과 같이 이벤트가 발행될 대상(target)을 결정합니다:

targetDocument를 target의 node document [DOM]으로 둡니다.

이벤트가 pointerdown, pointermove, 또는 pointerup이면 해당 이벤트의 pointerId에 대한 active documenttargetDocument로 설정합니다.

이벤트가 pointerdown이고 관련 장치가 직접 조작(direct manipulation) 장치이며 target이 Element인 경우 set pointer capture를 수행하여 pointerId를 해당 요소에 캡처합니다(implicit pointer capture 참고).

이 이벤트를 발행하기 전에 user agent는 이벤트 순서를 보장하기 위해 (event ordering [UIEVENTS]) 포인터가 previousTarget에서 target으로 이동한 것처럼 처리해야 SHOULD 하며 needsOverEvent 플래그가 설정된 경우 동일 요소라도 pointerover 이벤트가 필요합니다.

결정된 target에 이벤트를 발행(Fire)합니다.

결정된 target을 해당 포인터의 previousTarget으로 저장하고 needsOverEvent 플래그를 false로 재설정합니다. 이후 previousTarget이 더 이상 connected [DOM] 상태가 아니게 되면 이벤트 경로를 따라 디스패치 시 가장 가까운 연결된 부모로 previousTarget을 갱신하고 needsOverEventtrue로 설정합니다.

Note
정상 hit-test 결과 대신 pointer capture target override를 target으로 사용하면 [UIEVENTS]에 정의된 경계 이벤트가 발생할 수 있습니다. 이는 포인터가 이전 target을 떠나 새로운 캡처 target으로 들어가는 것과 같으며 캡처 해제 시 역순 상황이 다시 발생할 수 있습니다.
4.1.3.1 속성과 기본 동작

이 명세에서 정의된 이벤트 타입에 대한 bubbles, cancelable 속성과 기본 동작은 아래 표에 나타납니다. 각 이벤트 타입 상세는 Pointer Event types를 참고하세요.

Event Type Bubbles Cancelable Default Action
pointerover Yes Yes None
pointerenter No No None
pointerdown Yes Yes 변동: 포인터가 primary일 때 mousedown의 모든 기본 동작
이 이벤트를 취소하면 이후 compatibility mouse events 발생을 방지합니다.
pointermove Yes Yes 변동: 포인터가 primary일 때 mousemove 기본 동작
pointerrawupdate Yes No None
pointerup Yes Yes 변동: 포인터가 primary일 때 mouseup 기본 동작
pointercancel Yes No None
pointerout Yes Yes None
pointerleave No No None
gotpointercapture Yes No None
lostpointercapture Yes No None

뷰포트 조작(패닝·줌)은 일반적으로 direct manipulation 상호작용 결과이지만 포인터 이벤트의 기본 동작이 아니므로(일부 예: 손가락 이동에 따른 페이지 패닝) 해당 포인터 이벤트를 취소해도 억제되지 않습니다. 대신 문서 영역에 대해 touch-action을 사용하여 직접 조작 동작을 선언해야 합니다. 이벤트 취소 의존성을 제거하면 user agent가 성능 최적화를 수행하기 용이합니다.

pointerenter, pointerleave 이벤트의 composed [DOM] 속성은 false이어야 SHOULD 하며, 위 표의 다른 모든 포인터 이벤트는 true이어야 SHOULD 합니다.

위 표의 모든 포인터 이벤트에서 detail [UIEVENTS] 속성은 0이어야 SHOULD 합니다.

Note
많은 user agent가 레거시 콘텐츠 지원을 위해 MouseEvents에 비표준 속성 fromElement, toElement를 노출합니다. PointerEvents에서는 이러한 (상속된) 속성을 null로 설정하여 표준 대안(target, relatedTarget) 사용으로 전환하는 것을 권장합니다.

MouseEventrelatedTarget과 유사하게 relatedTargetpointerover / pointerenter에서는 포인터가 막 떠난 요소, pointerout / pointerleave에서는 포인터가 들어가는 요소로 초기화됩니다. 다른 포인터 이벤트에서는 기본값이 null입니다. 요소가 포인터 캡처를 획득하면 이후 해당 포인터의 모든 이벤트는 캡처 요소 경계 내부로 간주됩니다.

gotpointercapturelostpointercapture 이벤트는 표에 정의된 것 제외 모든 속성이 user agent가 process pending pointer capture 단계를 실행하고 gotpointercapture/lostpointercapture 이벤트를 발행하게 한 그 포인터 이벤트와 동일해야 합니다.

4.1.3.2 보류 중인 포인터 캡처 처리

user agentimplicitly releasing pointer capture 시점과 gotpointercapture 또는 lostpointercapture가 아닌 포인터 이벤트를 발행할 때 아래 단계를 수행해야 MUST 합니다:

  1. 해당 포인터의 pointer capture target override가 설정되어 있고 pending pointer capture target override와 다르면 lostpointercapture 이벤트를 해당 pointer capture target override 노드에 발행합니다.
  2. pending pointer capture target override가 설정되어 있고 pointer capture target override와 다르면 gotpointercapture 이벤트를 pending pointer capture target override에 발행합니다.
  3. pointer capture target override를 (설정되어 있다면) pending pointer capture target override로 설정하고, 아니면 제거합니다.
Note

click, auxclick, contextmenu 이벤트 정의에 따라 lostpointercapture가 디스패치된 후에도 해당 click / auxclick / contextmenu 이벤트가 존재한다면 캡처 대상에 계속 디스패치될 수 있습니다.

4.1.3.3 포인터 이벤트 스트림 억제

user agent는 특정 pointerId에 대한 포인터 이벤트를 웹 페이지가 더 이상 계속 수신하지 않을 것으로 판단하면 suppress a pointer event stream을 수행해야 MUST 합니다. 다음 시나리오 중 하나가 조건을 만족합니다(추가 시나리오가 있을 수 MAY 있음):

  • user agent가 모달 다이얼로그 또는 메뉴를 연 경우.
  • 포인터 입력 장치가 물리적으로 연결 해제되었거나 호버 가능한 포인터 장치(예: 호버 가능한 펜/스타일러스)가 디지타이저가 감지 가능한 호버 범위를 벗어난 경우.
  • 포인터가 이후 user agent에 의해 페이지 뷰포트를 조작(예: 패닝 또는 줌)하는 데 사용되는 경우. 자세한 내용은 touch-action CSS 속성 섹션을 참조하세요.
    Note
    user agent는 다중 포인터 유형(터치·펜 등)을 통해 패닝 또는 줌을 트리거할 수 있으므로 패닝/줌 시작 시 다양한 포인터(서로 다른 pointerType 포함)가 억제될 수 있습니다.
  • drag and drop processing model [HTML]에 정의된 드래그 작업 시작 알고리즘의 일부로 해당 드래그 작업을 유발한 포인터 스트림이 억제됩니다.
Note

user agent가 추가로 포인터 이벤트 스트림을 억제할 수 있는 다른 상황:

  • 포인터가 활성인 동안 장치 화면 방향(orientation)이 변경됨.
  • 사용자가 장치가 지원하는 동시 포인터 수보다 많은 포인터 입력을 시도함.
  • user agent가 입력을 실수(예: palm rejection 지원)로 해석함.

이러한 시나리오를 감지하는 방법은 명세 범위를 벗어납니다.

user agent는 포인터 이벤트 스트림을 억제하기 위해 다음 단계를 수행해야 MUST 합니다:

4.1.4 레이아웃 변경으로 인한 경계 이벤트

포인팅 장치가 화면 표면 대비 이동하거나 속성 변화가 발생하면 Pointer Event types에 정의된 다양한 이벤트가 발생합니다. 위치·속성 변화가 전혀 없는 정지 포인팅 장치에서 레이아웃 변경이 포인터의 hit test 대상에 영향을 주면 user agent는 pointerover, pointerenter, pointerout, pointerleave 이벤트를 발생시켜야 MUST 합니다. 성능상의 이유로 이러한 경계 이벤트 발행을 지연시킬 수 MAY 있습니다(예: hit-test 과다 또는 경계 이벤트 리스너로 인한 레이아웃 변화 방지).

Note
정지 포인팅 장치는 pointermove 이벤트를 발생시키지 않습니다.

4.1.5 tiltX / tiltYaltitudeAngle / azimuthAngle 간 변환

Pointer Events는 변환기의 X-Y 평면 대비 방향을 표현하기 위해 두 세트(tiltX/tiltY: 원래 명세 도입, azimuthAngle/altitudeAngle: Touch Events - Level 2에서 채택)를 제공합니다.

특정 하드웨어·플랫폼에 따라 user agent는 변환기 방향에 대해 두 세트 중 하나만 수신하는 경우가 많으며(tiltX/tiltY 또는 altitudeAngle/azimuthAngle) user agent는 아래 변환 알고리즘을 사용해야 MUST 합니다.

user agent가 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 타입

아래는 이 명세에서 정의된 이벤트 타입입니다.

primary pointer의 경우, 다음 이벤트들은(gotpointercapturelostpointercapture는 예외) compatibility mouse events도 발생시킬 수 있습니다.

4.2.1 pointerover 이벤트

user agent는 다음 상황 중 하나가 발생하면 MUST이름이 pointerover인 포인터 이벤트를 발행해야 합니다:

4.2.2 pointerenter 이벤트

user agent는 다음 상황 중 하나가 발생하면 MUST이름이 pointerenter인 포인터 이벤트를 발행해야 합니다:

  • 포인터의 대상을 결정하는 단계에서 포인터가 어떤 요소 또는 그 하위 요소 안으로 들어왔음을 감지한 경우.
  • 레이아웃 변경으로 인해, 정지한 포인팅 장치의 캡처되지 않은 포인터 아래로 요소 또는 그 하위 요소의 히트 테스트 경계가 이동하는 경우.
  • user agent가 pointerdown 이벤트를 (아래의 does not support hover 장치에 대해) 발행하기 전에.
Note
이 이벤트 타입은 pointerover와 유사하지만 두 가지 차이가 있습니다. pointerenter는 버블링하지 않으며, 디스패치 시 하위 요소들의 히트 테스트 경계까지 고려합니다.
Note
이 이벤트 타입은 [UIEVENTS]에 설명된 mouseenter 이벤트 및 [CSS21]에 설명된 CSS :hover 의사 클래스와 유사점이 있습니다. pointerleave 이벤트도 참고하세요.

4.2.3 pointerdown 이벤트

user agent는 포인터가 active buttons state에 들어갈 때 MUST이름이 pointerdown인 포인터 이벤트를 발행해야 합니다. 마우스의 경우 버튼이 없음에서 하나 이상 눌림으로 전이될 때, 터치의 경우 digitizer에 물리적 접촉이 이루어질 때, 펜의 경우 버튼을 누르지 않은 채 디지타이저에 닿거나 호버 중 버튼 없음에서 하나 이상 눌림으로 전이될 때입니다.

Note
마우스(또는 다른 다중 버튼 포인터 장치)의 경우, 이는 pointerdownpointerupmousedownmouseup과 동일한 모든 상황에서 발생하지 않음을 의미합니다. 자세한 내용은 chorded buttons를 참조하세요.

devices that do not support hover 입력의 경우, user agentMUST이름이 pointerover인 포인터 이벤트를 먼저 발행하고, 이어서 pointerenter 이벤트를 발행한 후 pointerdown 이벤트를 디스패치해야 합니다.

Note
작성자는(isPrimary 속성이 true인 경우) compatibility mouse events 중 일부의 발생을 pointerdown 이벤트를 취소하여 방지할 수 있습니다. 이렇게 하면 해당 포인터에 PREVENT MOUSE EVENT 플래그가 설정됩니다. 단, 이는 mouseover, mouseenter, mouseout, mouseleave 이벤트의 발생은 막지 못합니다.

4.2.4 pointermove 이벤트

user agentpointerdown 또는 pointerup 이벤트를 발생시키지 않는 속성들에 변화가 있을 때 MUST이름이 pointermove인 포인터 이벤트를 발행해야 합니다. 여기에는 좌표, pressure, tangential pressure, tilt, twist, 접촉 기하(width, height) 또는 chorded buttons의 변경이 포함됩니다.

user agent는 (예: 성능상의 이유로) pointermove 이벤트의 디스패치를 MAY로 지연할 수 있습니다. 이러한 경우 coalesced events 정보는 단일로 디스패치된 pointermove 이벤트의 getCoalescedEvents 메서드를 통해 제공됩니다. 이때 이벤트의 최종 좌표를 이벤트 대상 결정을 위한 좌표로 사용해야 합니다.

4.2.5 pointerrawupdate 이벤트

user agentMUST이름이 pointerrawupdate인 포인터 이벤트를 발행해야 하며, 이는 반드시 secure context 내에서만 이루어져야 합니다. 이 이벤트는 pointerdown 또는 pointerup을 발생시키지 않는 속성들에 변화가 있을 때 발생합니다. 해당 속성 목록은 pointermove를 참고하세요.

pointermove와 달리, user agent는 SHOULDpointerrawupdate 이벤트를 가능한 한 빨리, 그리고 자바스크립트가 처리할 수 있는 빈도만큼 자주 디스패치해야 합니다.

pointerrawupdate 이벤트의 targetpointermove 이벤트의 target과 다를 수 있습니다. 이는 pointermove 이벤트가 지연되거나 병합(coalesce)될 수 있으며, 이벤트 대상 결정을 위한 최종 위치가 병합된 이벤트들의 위치와 다를 수 있기 때문입니다.

이미 동일한 pointerId를 가진, 아직 event loop에서 디스패치되지 않은 또 다른 pointerrawupdate가 있는 경우, user agent는 새로운 pointerrawupdate를 생성하는 대신 해당 이벤트와 병합할 수 MAY 있습니다. 이는 새로운 task 생성을 피하기 위함입니다. 이로 인해 pointerrawupdate가 coalesced events를 가지게 될 수 있으며, 이러한 이벤트들은 coalesced events로 하나의 pointerrawupdate 이벤트에 묶여, 해당 이벤트가 event loop에서 처리되는 즉시 전달됩니다. 자세한 내용은 getCoalescedEvents를 참고하세요.

pointerrawupdatepointermove의 순서와 관련하여, 플랫폼으로부터의 업데이트가 두 이벤트(pointerrawupdate, pointermove) 모두를 유발하는 경우, user agentMUST로 해당 pointerrawupdate를 대응하는 pointermove보다 먼저 디스패치해야 합니다.

target을 제외하면, 마지막 pointermove 이벤트 이후에 디스패치된 모든 pointerrawupdate의 coalesced events 리스트들을 연결(concatenate)한 결과는 다음 pointermove 이벤트의 coalesced events와 (다른 이벤트 속성 측면에서) 동일합니다. pointerrawupdate의 속성은 pointermove와 대부분 동일하나, cancelablepointerrawupdate의 경우 MUST로 false여야 합니다.

user agent는 SHOULDcompatibility mouse eventspointerrawupdate에 대해 발생시키지 않아야 합니다.

Note
pointerrawupdate 이벤트 리스너를 추가하면 user agent 구현에 따라 웹 페이지 성능에 부정적 영향을 줄 수 있습니다. 대부분의 사용 사례에서는 다른 pointer 이벤트 타입들로 충분합니다. 자바스크립트가 매우 높은 빈도의 이벤트를 필요로 하고 그만큼 빠르게 처리할 수 있을 때에만 pointerrawupdate 리스너를 추가하세요. 이러한 경우에는 다른 포인터 이벤트 타입을 들을 필요가 없을 수 있습니다.

4.2.6 pointerup 이벤트

user agent는 포인터가 active buttons state를 벗어날 때 MUST이름이 pointerup인 포인터 이벤트를 발행해야 합니다. 마우스의 경우 하나 이상 눌림에서 버튼이 없음으로 전이, 터치의 경우 digitizer로부터 물리적 접촉이 제거될 때, 펜의 경우 버튼이 눌리지 않은 상태에서 디지타이저와의 접촉이 제거되거나, 호버 중 하나 이상 눌림에서 버튼이 없음으로 전이될 때입니다.

devices that do not support hover 입력의 경우, user agentMUST이름이 pointerout인 포인터 이벤트를 발행하고, 이어서 pointerleave 이벤트를 pointerup 이벤트를 디스패치한 후에 발행해야 합니다.

모든 pointerup 이벤트의 pressure 값은 0입니다.

user agent는 포인터가 현재 캡처된 상태라면 MUSTimplicitly release the pointer capture를 수행해야 합니다.

Note
마우스(또는 다른 다중 버튼 포인터 장치)의 경우, 이는 pointerdownpointerupmousedownmouseup과 동일한 모든 상황에서 발생하지 않음을 의미합니다. 자세한 내용은 chorded buttons를 참조하세요.

4.2.7 pointercancel 이벤트

user agentsuppress a pointer event stream 상황을 감지하면 MUST이름이 pointercancel인 포인터 이벤트를 발행해야 합니다.

다음 속성들의 값은 pointercancel 이벤트에서 동일한 pointerId를 가진 마지막으로 디스패치된 포인터 이벤트의 값과 MUST로 일치해야 합니다: width, height, pressure, tangentialPressure, tiltX, tiltY, twist, altitudeAngle, azimuthAngle, pointerType, isPrimary, 그리고 [UIEVENTS]에서 상속된 좌표들. 또한 pointercancel 이벤트의 coalescedEventspredictedEvents 리스트는 MUST로 비어 있어야 하며, 이벤트의 cancelable 속성은 MUST로 false여야 합니다.

4.2.8 pointerout 이벤트

user agent는 다음 상황 중 하나가 발생하면 MUST이름이 pointerout인 포인터 이벤트를 발행해야 합니다:

4.2.9 pointerleave 이벤트

user agent는 다음 상황 중 하나가 발생하면 MUST이름이 pointerleave인 포인터 이벤트를 발행해야 합니다:

Note
이 이벤트 타입은 pointerout와 유사하지만 두 가지 차이가 있습니다. pointerleave는 버블링하지 않으며, 디스패치 시 하위 요소들의 히트 테스트 경계까지 고려합니다.
Note
이 이벤트 타입은 [UIEVENTS]에 설명된 mouseleave 이벤트 및 [CSS21]에 설명된 CSS :hover 의사 클래스와 유사점이 있습니다. pointerenter 이벤트도 참고하세요.

4.2.10 gotpointercapture 이벤트

user agent는 어떤 요소가 포인터 캡처를 받으면 MUST이름이 gotpointercapture인 포인터 이벤트를 발행해야 합니다. 이 이벤트는 포인터 캡처를 받는 그 요소에서 발생합니다. 이후 해당 포인터에 대한 이벤트들은 이 요소에서 발생합니다. setting pointer captureprocess pending pointer capture 섹션을 참고하세요.

4.2.11 lostpointercapture 이벤트

user agent는 포인터 캡처가 포인터에 대해 해제된 후 MUST이름이 lostpointercapture인 포인터 이벤트를 발행해야 합니다. 이 이벤트는 캡처가 제거된 그 요소에서 발생합니다. 캡처 해제 후 해당 포인터에 대한 이후의 모든 이벤트는 click, auxclick, contextmenu 이벤트를 제외하고, 이벤트 대상 결정을 위해 정상적인 히트 테스트 메커니즘(본 명세 범위 밖)을 따릅니다. releasing pointer capture, implicit release of pointer capture, process pending pointer capture 섹션을 참고하세요.

4.2.12 click, auxclick, 그리고 contextmenu 이벤트

이 절은 [UIEVENTS]에 정의된 click, auxclick, contextmenu 이벤트에 대한 추가 사항입니다. 이러한 이벤트는 일반적으로 사용자 인터페이스 활성화에 연관되며, 키보드와 같은 포인터가 아닌 입력 장치로부터도 발생합니다.

이러한 이벤트는 MUSTPointerEvent 타입이어야 하며, 본 절의 나머지에서 언급되는 추가 요구사항의 적용을 받습니다.

4.2.12.1 이벤트 속성

이러한 이벤트에 대해서는, 이 명세에서 정의된 PointerEvent 고유 속성들 중 pointerIdpointerType을 제외한 모든 속성은 기본값을 가져야 MUST 합니다. 추가로:

  • 이벤트가 포인팅 장치에 의해 생성된 경우, 해당 이벤트의 pointerIdpointerType은 이 이벤트들을 유발한 PointerEvents와 동일해야 MUST 합니다.
  • 이벤트가 포인팅 장치가 아닌(예: 음성 인식 소프트웨어나 키보드 상호작용) 입력에 의해 생성된 경우, pointerId-1, pointerType은 빈 문자열이어야 MUST 합니다.
4.2.12.2 이벤트 좌표

PointerEvent에서 언급했듯이, CSSOM View Module은 다양한 좌표 속성(screenX, screenY, pageX, pageY, clientX, clientY, x, y, offsetX, offsetY)을 double로 재정의하여 소수 좌표를 허용할 것을 제안합니다. 그러나 이 변경을 일반 MouseEvent가 아닌 PointerEvent에만 적용할 경우, click, auxclick, contextmenu에서 레거시 코드와의 웹 호환성 문제가 발생할 수 있음이 드러났습니다. 이 이유로, CSSOM View Module의 제안을 PointerEvent에만 구현한 user agent는 MUSTclick, auxclick, contextmenu의 다양한 좌표 속성을(원래의 UI Events에서 정의된 대로) long 값으로 변환해야 하며, 이때 Math.floor [ECMASCRIPT]를 사용해야 합니다.

4.2.12.3 이벤트 디스패치

click, auxclick, contextmenu 이벤트는 [UIEVENTS] 명세에 정의된 디스패치 과정을 MUST로 따라야 하나, 아래 알고리즘을 사용해 이벤트 대상을 재정의한다는 점이 예외입니다:

  1. event를 디스패치 중인 click, auxclick 또는 contextmenu 이벤트로, userEventevent의 발생을 유발한 사용자 상호작용 이벤트로 둡니다.

    Note

    userEventPointerEvent가 아닐 수 있습니다. 예: 체크박스 요소에서 스페이스바를 눌러 click 디스패치를 유발한 경우 KeyboardEvent입니다.

    userEventPointerEvent인 경우, userEventclick 또는 auxclick 이벤트에 대해서는 pointerup이며, contextmenu 이벤트에 대해서는 네이티브 플랫폼 규칙에 따라 pointerdown 또는 pointerup일 수 있습니다.

  2. userEventPointerEvent가 아닌 경우, [UIEVENTS] 명세를 따라 event 대상을 재정의하지 않고 디스패치하고, 이후 단계는 건너뜁니다.
  3. target을 다음과 같이 정의합니다:

    eventcontextmenu 이벤트이거나, userEvent가 디스패치될 당시 해당 포인터가 캡처된 상태였다면, targetuserEvent의 대상(target)으로 둡니다.

    그 외의 경우(eventclick 또는 auxclick이고, userEvent가 캡처되지 않은 상태에서 디스패치된 pointerup인 경우)에는, target을 디스패치 시점의 DOM에서 해당되는 pointerdownpointerup 대상의 최근접 공통 포함 조상으로 둡니다.

  4. [UIEVENTS] 명세를 따라 eventtarget에 디스패치합니다.

    Note
    userEvent가 캡처된 상태였다면, 동일한 lostpointercapture 이벤트가 동일 pointerId로 이미 디스패치되었더라도, eventuserEvent의 캡처 대상에 디스패치됩니다.

5. Element 인터페이스에 대한 확장

다음 절은 포인터 캡처의 설정과 해제를 용이하게 하기 위해 기존 Element 인터페이스에 대한 확장을 설명합니다.

WebIDLpartial interface Element {
  undefined setPointerCapture (long pointerId);
  undefined releasePointerCapture (long pointerId);
  boolean hasPointerCapture (long pointerId);
};
setPointerCapture()

이 메서드가 호출된 요소에 대해, 인수 pointerId로 식별되는 포인터의 포인터 캡처를 설정합니다. 이후 해당 포인터의 이벤트는 포인터가 항상 캡처 대상 위에 있는 것처럼 정상 히트 테스트 결과 대신 캡처 대상을 사용하며, 캡처가 해제될 때까지 MUST 항상 이 요소를 대상으로 해야 합니다. 이 메서드가 효과를 가지려면 포인터는 active buttons stateMUST 있어야 하며, 그렇지 않으면 조용히 실패합니다. 제공된 메서드 인수가 어떤 active pointers와도 일치하지 않으면, throw "NotFoundError" DOMException을 발생시킵니다.

releasePointerCapture()

이 메서드가 호출된 요소로부터, 인수 pointerId로 식별되는 포인터의 포인터 캡처를 해제합니다. 이후 해당 포인터의 이벤트는 이벤트 대상 결정을 위해 정상적인 히트 테스트 메커니즘(본 명세 범위 밖)을 따릅니다. 제공된 메서드 인수가 어떤 active pointers와도 일치하지 않으면, throw "NotFoundError" DOMException을 발생시킵니다.

hasPointerCapture

이 메서드가 호출된 요소가 인수 pointerId로 식별되는 포인터에 대해 pointer capture를 가지고 있는지를 나타냅니다. 특히, pending pointer capture target overridepointerId에 대해 이 메서드가 호출된 요소로 설정되어 있으면 true를, 그렇지 않으면 false를 반환합니다.

Note
이 메서드는 setPointerCapture() 호출 직후 즉시 true를 반환하지만, 그 요소는 아직 gotpointercapture 이벤트를 받지 않았을 수 있습니다. 따라서 implicit pointer capturepointerdown 이벤트 리스너 내부에서 감지하는 데 유용할 수 있습니다.

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이어야 합니다.

Note
장치가 maxTouchPoints 값이 0보다 크면 터치 입력을 지원할 수 있음을 나타내지만, 사용자가 실제로 터치 입력을 사용할 것이라는 의미는 아닙니다. 작성자는 마우스, 펜, 스크린 리더 등 시스템에 존재할 수 있는 다른 입력 양식도 고려해야 합니다.
Note
maxTouchPoints는 콘텐츠의 상호작용 모델을 현재 하드웨어가 인식할 수 있는지 확인하기 위해 자주 사용됩니다. UI적 도구(affordances)는 덜 강력한 하드웨어를 가진 사용자에게 제공할 수 있습니다. 정확한 터치 포인트 수를 알 수 없는 플랫폼에서는 인식이 보장되는 최소 수를 제공합니다. 따라서 실제 인식된 터치 포인트 수가 maxTouchPoints 값을 초과할 가능성이 있습니다.

8. 직접 조작 동작 선언

Attributes and Default Actions에서 언급했듯이, 뷰포트 조작(패닝 및 줌)은 포인터 이벤트를 취소하여 억제할 수 없습니다. 대신 작성자는 touch-action CSS 속성을 사용해 허용할 동작과 억제할 동작을 선언적으로 정의해야 합니다.

Note
뷰포트를 조작하는 데 사용되는 포인터 문제는 일반적으로 터치 입력(사용자의 손가락이 콘텐츠와 상호작용하면서 동시에 페이지를 패닝/줌할 수 있음)에 국한되지만, 일부 user agent는 다른 포인터 유형에도 동일한 (직접 또는 간접) 조작을 허용할 수 있습니다. 예를 들어 모바일/태블릿 장치에서 사용자는 스타일러스를 사용해 스크롤할 수도 있습니다. 역사적 이유로 본 명세에서 정의된 touch-action CSS 속성 이름은 터치 입력만을 가리키는 것처럼 보이지만, 실제로는 패닝과 줌을 위한 direct manipulation을 허용하는 모든 형태의 포인터 입력에 적용됩니다.

8.1 touch-action CSS 속성

Name: touch-action
Value: auto | none | [ [ pan-x | pan-left | pan-right ] || [ pan-y | pan-up | pan-down ] ] | manipulation
Initial: auto
Applies to: 다음 제외 모든 요소: non-replaced inline 요소, table 행, 행 그룹, table 열, 열 그룹
Inherited: no
Percentages: N/A
Media: visual
Computed value: 지정된 값과 동일
Canonical order: 문법 순서
Animation type: animatable 아님

touch-action CSS 속성은 이름과 달리 터치에만 국한되지 않는 direct manipulation 상호작용이 user agent의 패닝 및 줌 동작을 트리거할 수 있는지 여부를 결정합니다. touch-action 섹션을 참고하세요.

패닝 또는 줌을 시작하기 직전에, user agent는 다음 모든 조건이 참이면 MUST포인터 이벤트 스트림을 억제해야 합니다:

Note
일부 user agent는 분리된 제스처들의 연속을 단일 연속 제스처로 처리하는 복잡한 동작을 구현합니다. 예: 터치스크린에서 “플링 스크롤” 제스처—사용자가 빠르게 손가락을 움직여 문서를 패닝 시작 후 손가락을 들어 올리면 문서는 관성으로 계속 패닝됩니다. 문서가 이동 중일 때 사용자는 다시 손가락을 놓고 또 다른 “플링”을 실행하여 추가 관성을 부여하거나, 현재 패닝을 상쇄(속도 감소, 중지, 방향 반전)할 수 있습니다. 이 명세는 제스처와 동작 구현을 규범적으로 정의하지 않으므로 두 번째 터치가 (두 번째 “플링” 또는 상쇄로 해석되기 전) 포인터 이벤트를 발생시킬지 여부는 user agent 재량입니다.
Note
touch-action은 임베디드 브라우징 컨텍스트로 적용/상속되지 않습니다. 예를 들어 <iframe>touch-action을 적용해도 해당 <iframe> 내부의 패닝 및 줌 직접 조작 동작에는 영향이 없습니다.

8.2 지원되는 직접 조작 동작 결정

사용자가 터치 또는 스타일러스 같은 direct manipulation 포인터로 요소를 상호작용할 때, 해당 입력의 효과는 다음과 같이 touch-action 속성 값과 요소 및 조상들의 기본 직접 조작 동작에 의해 결정됩니다:

Note
일부 user agent는 다중 동시 포인터(예: 멀티터치)를 포함하는 패닝/줌 상호작용을 지원합니다. 여러 동시 포인터의 touch-action 값을 처리/연계하는 방법은 명세 범위를 벗어납니다.

8.3 touch-action 값 상세

touch-action 속성은 뷰포트 패닝 및 줌과 관련된 직접 조작 동작을 다룹니다. 텍스트 선택/강조, 링크 및 폼 컨트롤 활성화 같은 추가 user agent 동작은 이 CSS 속성에 의해 영향을 받아서는 MUST NOT 합니다.

Note
“panning”과 “scrolling”은 동의어로 간주되며(보다 정확히는 “panning”이 직접 조작 입력을 사용한 “scrolling”), 패닝/스크롤을 트리거하는 제스처 정의나 auto, none 값에 대한 행동 정의는 명세 범위 밖입니다.
auto
user agent는 요소에서 시작하는 뷰포트 패닝 및 줌 관련 허용된 직접 조작 동작을 고려할 수 MAY 있습니다.
none
요소에서 시작하는 직접 조작 상호작용은 뷰포트 패닝 및 줌 관련 동작을 트리거해서는 MUST NOT 합니다.
pan-x
pan-left
pan-right
pan-y
pan-up
pan-down
user agent는 요소에서 시작하는 직접 조작 상호작용을 나열된 모든 값이 지정한 방향에서 시작하는 패닝 목적에 대해서만 고려할 수 MAY 있습니다. 패닝이 시작된 후에는 시작 방향이 허용되지 않는 방향이라도 사용자가 방향을 반대로 바꿀 수 있습니다. 반면 단일 축으로 제한된 경우(예: pan-x 또는 pan-y) 패닝 중 축은 변경할 수 없습니다.
manipulation
user agent는 요소에서 시작하는 직접 조작 상호작용을 패닝 및 연속적인 줌(핀치 줌 등) 목적에 대해서만 고려할 수 MAY 있으며, 시간 제한 내 다중 활성화에 의존하는 다른 관련 동작(더블 탭 줌, 더블 탭 후 홀드로 단일 손가락 줌 등)을 트리거해서는 MUST NOT 합니다.
Note
구현에서 흔한 추가 touch-action은 [COMPAT]에 정의되어 있습니다.
Note
touch-action 속성은 CSS widthheight 속성을 모두 지원하는 요소에만 적용됩니다([CSS21] 참고). 이 제한은 저지연 direct manipulation 패닝 및 줌을 위한 user agent 최적화를 촉진하기 위해 설계되었습니다. 기본적으로 지원되지 않는 요소(예: non-replaced inline element<span>)는 작성자가 displayblock처럼 widthheight를 지원하는 값으로 설정하여 사용할 수 있습니다. 향후 명세는 이 API를 모든 요소로 확장할 수 있습니다.
Note

방향별 pan 값은 일부 overscroll 동작을 커스터마이징하는 데 유용합니다. 예를 들어 단순한 pull-to-refresh 효과를 구현하려면 문서의 touch-action을 스크롤 위치가 0일 때 pan-x pan-down으로, 그렇지 않을 때 pan-x pan-y로 설정할 수 있습니다. 이렇게 하면 문서 최상단에서 시작하는 위쪽 패닝/스크롤에 대해 포인터 이벤트 핸들러가 동작을 정의할 수 있습니다.

방향별 pan 값은 네이티브로 스크롤되는 요소 내부에서 포인터 이벤트 처리로 커스텀 패닝을 구현하는 컴포넌트를 구성(또는 그 반대)하는 데도 사용할 수 있습니다. 예를 들어 이미지 캐러셀은 pan-y를 사용해 수평 패닝 작업에 대한 포인터 이벤트를 수신하면서 문서의 수직 패닝을 방해하지 않을 수 있습니다. 캐러셀이 가장 오른쪽 끝에 도달하면 이후 범위를 넘어선 스크롤 작업이 가능할 경우 뷰포트 내 문서를 스크롤할 수 있도록 touch-actionpan-y pan-right로 변경할 수 있습니다. 진행 중인 패닝/스크롤 작업의 동작은 수행 중에 변경할 수 없습니다.

Note
패닝 및 줌을 위한 일부 기본 직접 조작 동작을 비활성화하면 user agent가 다른 동작에 더 빠르게 응답할 수 있습니다. 예: auto에서는 user agent가 더블 탭 제스처 처리를 허용하기 위해 일반적으로 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>
        이 요소에 대한 직접 조작 상호작용은 부모 조작에 사용될 수 </div>
    </div>
</div>
Example 10: 패닝/줌 직접 조작 동작을 불허하는 중간 부모
<div style="overflow: auto;">
    <div style="touch-action: pan-y;">
        <div style="touch-action: pan-x;">
            이 요소는 모든 직접 조작 상호작용에 대해 포인터 이벤트를 수신합니다. 
            수평 패닝만 허용하지만 그 사이의 중간 조상
            (스크롤 가능한 요소 사이) 은 수직 패닝만 허용하기 때문입니다.
            따라서 패닝/줌을 위한 직접 조작 동작은
            user agent에 의해 처리되지 않습니다.
        </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"> 컨트롤과 유사) 같은 시나리오에서 유용합니다. 슬라이더 썸 요소에서 포인터 캡처를 설정하면, 포인터가 썸에서 벗어나더라도 사용자가 컨트롤을 앞뒤로 슬라이드할 수 있습니다.

사용자 지정 볼륨 슬라이더
그림 6 썸 요소를 앞뒤로 슬라이드하여 값을 선택하는 사용자 지정 슬라이더 컨트롤의 예. 썸에서 pointerdown 후, 포인터 캡처를 사용하면 포인터가 썸에서 벗어나더라도 사용자가 썸을 슬라이드할 수 있습니다.

9.2 포인터 캡처 설정

포인터 캡처는 Element 타입의 element에 대해 element.setPointerCapture(pointerId) 메서드를 호출하여 설정합니다. 이 메서드가 호출되면, user agent는 다음 단계를 MUST로 수행해야 합니다:

  1. 메서드 인수로 제공된 pointerId가 어떤 활성 포인터와도 일치하지 않으면, "NotFoundError" DOMExceptionthrow 합니다.
  2. 주어진 pointerId로 지정된 활성 포인터pointer로 둡니다.
  3. element가 [DOM]에서 정의한 connected 상태가 아니라면, "InvalidStateError" DOMExceptionthrow 합니다.
  4. 이 메서드가 호출될 때 element의 [DOM] 노드 문서에 잠금 요소([PointerLock]의 pointerLockElement)가 있는 경우, "InvalidStateError" DOMExceptionthrow 합니다.
  5. pointeractive buttons state에 있지 않거나 element노드 문서pointeractive document가 아니면, 이 단계를 종료합니다.
  6. 지정된 pointerId에 대해, pending pointer capture target override를 이 메서드가 호출된 Element로 설정합니다.
Note
이전의 설정 또는 해제 호출이 보류 중인 상태( process pending pointer capture 참조)에서 포인터 캡처 설정 또는 해제 호출이 이루어지면, 두 번째 호출이 성공한 경우 두 번째 호출이 첫 번째 호출을 덮어쓰고, 그렇지 않으면 첫 번째 호출이 유효하게 유지됩니다. 이는 암시적 포인터 캡처pointerdown 리스너에서 해제하려다 실패한 경우에도 마찬가지입니다.

9.3 포인터 캡처 해제

포인터 캡처는 element.releasePointerCapture(pointerId) 메서드를 호출하여 요소에서 명시적으로 해제합니다. 이 메서드가 호출되면, user agent는 다음 단계를 MUST로 수행해야 합니다:

  1. 메서드 인수로 제공된 pointerId가 어떤 활성 포인터와도 일치하지 않고, 이 단계가 포인터 캡처의 암시적 해제의 결과로 호출된 것이 아니라면, "NotFoundError" DOMExceptionthrow 합니다.
  2. 지정된 pointerId에 대한 hasPointerCapture가 false이면, 이 단계를 종료합니다.
  3. 지정된 pointerId에 대해, 설정되어 있다면 pending pointer capture target override를 제거합니다.
Note
포인터 캡처 설정 섹션의 노트를 참고하세요.

9.4 암시적 포인터 캡처

패닝과 줌을 위한 직접 조작 상호작용(예: 터치스크린의 터치나 스타일러스)을 구현하는 입력은, 어떤 pointerdown 리스너가 호출되기 직전에 대상 요소에서 setPointerCapture가 호출된 것처럼 정확히 동작해야 SHOULD 합니다. 이 동작이 발생했는지 확인하기 위해(예: pointerdown 리스너에서), hasPointerCapture API를 사용할 수 있습니다. 다음 포인터 이벤트가 발생하기 전에 해당 포인터에 대해 releasePointerCapture가 호출되지 않으면, 캡처가 활성화되었음을 나타내는 gotpointercapture 이벤트가(일반적으로) 대상에 디스패치됩니다.

Note
이는 [PointerEvents]로부터의 변경 사항이지만, 기존 콘텐츠의 대다수에는 영향을 주지 않습니다. 일반적인 플랫폼 UX 규칙과도 일치할 뿐만 아니라, 이런 암시적 캡처 설계는 명시적인 개발자 옵트인 없이도(기존의 지배적인 네이티브 및 웹 API의 터치 입력 성능 특성과 일관되게) 터치 이동 이벤트에 대해 히트 테스트 호출을 피하는 성능 최적화를 user agent가 수행할 수 있게 합니다.
Note
추가로, 일부 user agent는 입력 범위 컨트롤 같은 특정 UI 위젯에서 모든 입력 장치에 대해 암시적 포인터 캡처 동작을 구현할 수 있습니다(상호작용 중 손가락 일부 움직임이 폼 컨트롤 밖으로 벗어나는 것을 허용).

9.5 포인터 캡처의 암시적 해제

pointerup 또는 pointercancel 이벤트를 발생시킨 직후, user agent는 해당 방금 디스패치된 pointerup 또는 pointercancel 이벤트의 pointerId에 대해 pending pointer capture target overrideMUST로 지우고, 이어서 필요하면 lostpointercapture를 발생시키도록 process pending pointer capture 단계를 수행해야 합니다. process pending pointer capture 단계를 수행한 후, 포인터가 hover를 지원한다면, user agent는 캡처 없는 현재 포인터 위치를 반영하기 위해 필요한 경계(boundary) 이벤트도 MUST로 전송해야 합니다.

pointer capture target override가 더 이상 [DOM]의 connected 상태가 아니게 되면, pointer capture target override는 문서(document)로 설정되어야 SHOULD 합니다.

pending pointer capture target override가 더 이상 [DOM]의 connected 상태가 아니게 되면, pending pointer capture target override 노드는 SHOULD로 제거되어야 합니다.

Note
위 두 단락의 결과로, 캡처 노드가 제거된 후 다음 Process pending pointer capture 동안 문서에서 해당 포인터에 대응하는 lostpointercapture 이벤트가 발생하게 됩니다.

요소에 포인터 잠금 [PointerLock]이 성공적으로 적용되면, 어떤 요소가 캡처되었거나 캡처 대기 중인 경우, user agentreleasePointerCapture 메서드가 호출된 것처럼 단계를 MUST로 수행해야 합니다.

10. 병합(coalesced) 및 예측(predicted) 이벤트

Note
이 명세는 user agent가 포인터 이동 데이터를 어떻게 병합하거나 예측해야 하는지를 정의하지 않습니다. 이 정보에 접근하기 위한 API만을 정의합니다.

10.1 병합 이벤트

성능상의 이유로, user agent는 포인터의 측정 가능한 속성 (좌표, pressure, tangential pressure, tilt, twist, 접촉 기하 등)가 업데이트될 때마다 pointermove 이벤트를 보내지 않을 수 있습니다. 대신 여러 변경을 하나의 pointermove 또는 pointerrawupdate 이벤트로 병합(coalesce)할 수 있습니다. 이러한 방식은 user agent가 수행해야 하는 이벤트 처리 양을 줄이는 데 도움이 되지만, 특히 빠르고 큰 이동의 경우 포인터 위치를 추적할 때의 세분성(granularity)과 충실도(fidelity)가 자연스럽게 낮아집니다. getCoalescedEvents 메서드를 사용하면 애플리케이션이 병합되지 않은 원시 위치 변경에 접근할 수 있습니다. 이를 통해 포인터 이동 데이터를 보다 정밀하게 처리할 수 있습니다. 예를 들어 드로잉 애플리케이션에서는 병합되지 않은 이벤트를 사용해 실제 포인터 움직임에 더 가까운 매끄러운 곡선을 그릴 수 있습니다.

곡선을 확대해 병합된 점과 비병합 점을 보여주는 그림
그림 7 드로잉 애플리케이션의 곡선 예 — pointermove 이벤트에서 병합된 좌표(회색 점)만 사용하면 곡선이 눈에 띄게 각지고 거칩니다. 반면 getCoalescedEvents()가 제공하는 더 세밀한 점(빨간 원)을 사용해 그린 동일 선은 포인터 움직임을 더 부드럽게 근사합니다.

PointerEvent는 연관된 coalesced events list(0개 이상의 PointerEvent 목록)을 가집니다. 신뢰된(trusted) pointermovepointerrawupdate 이벤트의 경우, 이 목록은 해당 이벤트로 병합된 모든 PointerEvent의 시퀀스입니다. 신뢰된 "부모" pointermovepointerrawupdate 이벤트는 이러한 병합 이벤트의 누적을 나타내지만 (예: 디스플레이 주사율에 맞추는 등) 추가 처리를 포함할 수 있습니다. 결과적으로, 이러한 이벤트의 coalesced events list에는 항상 최소 하나의 이벤트가 포함됩니다. 그 외의 모든 신뢰된 이벤트 타입의 경우 목록은 비어 있습니다. 신뢰되지 않은(untrusted) 이벤트는 생성자에 전달된 값으로 coalesced events list가 초기화됩니다.

Note
신뢰된 부모 이벤트는 병합 이벤트의 요약/집계이므로, 개발자는 부모 이벤트 또는 모든 병합 이벤트 중 하나만 처리하면 되고 둘 다 처리할 필요는 없습니다.
Note
coalesced events list를 포함하는 신뢰된 이벤트가 JavaScript에서 다시 디스패치되면, 이벤트 디스패치 알고리즘은 이벤트의 isTrusted 비트를 false로 설정하지만, coalesced events list 내 이벤트들의 해당 비트는 원래의 true 값에서 변경되지 않습니다.

신뢰된 이벤트의 coalesced events list에 있는 이벤트는 다음을 가집니다:

Example 12: coalesced events list를 사용하는 기본 캔버스 드로잉 애플리케이션
<style>
    /* 고유의 user agent 직접 조작 동작(예: 패닝 또는 줌)을 비활성화하여
       캔버스 요소의 모든 이벤트가 애플리케이션에 전달되도록 합니다. */

    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의 속성은 coalesced events list의 이벤트를 가장 잘 표현하도록 초기화됩니다. user agent가 이를 수행해야 하는 구체적인 방법은 이 명세에서 다루지 않습니다.

디스패치된 모든 이벤트의 순서는 원본 이벤트의 실제 순서와 MUST로 일치해야 합니다. 예를 들어 pointerdown 이벤트가 병합된 pointermove 이벤트들의 디스패치를 유발하는 경우, user agent는 먼저 해당 pointerId의 모든 병합 이벤트를 포함하는 하나의 pointermove 이벤트를 디스패치하고, 그 다음에 pointerdown 이벤트를 디스패치해야 합니다.

Note

다음은 증가하는 timeStamp 값을 가진 실제 이벤트와 user agent가 디스패치한 이벤트의 예시입니다:

실제 이벤트 디스패치된 이벤트
포인터 (pointerId=2) 좌표 변경 pointerrawupdate (pointerId=2), 병합 이벤트 1개 포함
포인터 (pointerId=1) 좌표 변경 pointerrawupdate (pointerId=1), 병합 이벤트 1개 포함
포인터 (pointerId=2) 좌표 변경 pointerrawupdate (pointerId=2), 병합 이벤트 1개 포함
포인터 (pointerId=2) 좌표 변경 pointerrawupdate (pointerId=2), 병합 이벤트 1개 포함
포인터 (pointerId=1) 좌표 변경 pointerrawupdate (pointerId=1), 병합 이벤트 1개 포함
포인터 (pointerId=2) 좌표 변경 pointerrawupdate (pointerId=2), 병합 이벤트 1개 포함
포인터 (pointerId=1) 버튼 누름 pointermove (pointerId=1), 병합 이벤트 2개 포함
pointermove (pointerId=2), 병합 이벤트 4개 포함
pointerdown (pointerId=1), 병합 이벤트 0개
포인터 (pointerId=2) 좌표 변경 pointerrawupdate (pointerId=2), 병합 이벤트 1개 포함
포인터 (pointerId=2) 좌표 변경 pointerrawupdate (pointerId=2), 병합 이벤트 1개 포함
포인터 (pointerId=1) 버튼 뗌 pointermove (pointerId=2), 병합 이벤트 2개 포함
pointerup (pointerId=1), 병합 이벤트 0개

10.2 예측 이벤트

일부 user agent는 일련의 확인된 포인터 이동 이후, 현재 제스처에 대한 선행 이벤트 및 이동의 속도/궤적을 바탕으로 향후 포인터 이동의 위치를 예측할 수 있는 내장 알고리즘을 갖고 있습니다. 애플리케이션은 이 정보를 getPredictedEvents 메서드와 함께 사용해 체감 지연을 줄이기 위해 추정 위치로 미리 “앞서 그리기”를 수행하고, 실제 포인트가 수신되면 이 예측 포인트를 폐기할 수 있습니다.

병합된 점을 사용해 그린 선과 예측된 미래 포인트를 보여주는 그림
그림 8 드로잉 애플리케이션의 선(좌하단에서 우상단으로 그린 제스처의 결과) 예 — pointermove 이벤트의 병합 좌표를 사용하며, user agent가 예측한 미래 포인트(회색 원)를 표시합니다.

PointerEvent는 연관된 predicted events list(0개 이상의 PointerEvent 목록)을 가집니다. 신뢰된 pointermove 이벤트의 경우, user agent가 향후 해당 이벤트를 따라올 것으로 예측하는 PointerEvent들의 시퀀스입니다. 그 외의 모든 신뢰된 이벤트 타입의 경우 목록은 비어 있습니다. 신뢰되지 않은 이벤트는 생성자에 전달된 값으로 predicted events list가 초기화됩니다.

Note

pointerrawupdate 이벤트는 비어 있지 않은 coalesced events list를 가질 수 있지만, 성능상의 이유로 predicted events list는 보통 비어 있습니다.

Note
predicted events list를 포함하는 신뢰된 이벤트가 JavaScript에서 다시 디스패치되면, 이벤트 디스패치 알고리즘은 이벤트의 isTrusted 비트를 false로 설정하지만, predicted events list 내 이벤트들의 해당 비트는 원래의 true 값에서 변경되지 않습니다.

목록의 이벤트 개수와 현재 타임스탬프로부터의 거리(미래 시간)는 user agent와 그가 사용하는 예측 알고리즘에 의해 결정됩니다.

신뢰된 이벤트의 predicted events list에 있는 이벤트는 다음을 가집니다:

Note

작성자는 예측 이벤트를 다음 포인터 이벤트가 디스패치될 때까지의 유효한 예측으로만 간주해야 합니다. user agent가 어느 정도 미래까지 이벤트를 예측하는지에 따라, 일반 포인터 이벤트가 하나 이상의 예측 이벤트의 타임스탬프보다 먼저 디스패치될 수 있습니다.

Example 13: coalesced/predicted 이벤트를 사용한 드로잉의 개념적 접근

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가 생성될 때, user agent는 coalesced events listpredicted events list의 각 이벤트에 대해 다음 단계를 SHOULD로 수행해야 합니다:

  1. 이벤트의 pointerId, pointerType, isPrimary, isTrusted를 "부모" 포인터 이벤트의 해당 속성과 일치하도록 설정합니다.
  2. 이벤트의 cancelablebubbles를 false로 설정합니다 (이 이벤트들은 단독으로 디스패치되지 않기 때문입니다).
  3. 이벤트의 coalesced events listpredicted events list를 빈 목록으로 설정합니다.
  4. 그 외 모든 속성은 기본 PointerEvent 값으로 초기화합니다.

신뢰된 PointerEventtarget이 변경되면, user agent는 coalesced events listpredicted events list의 각 이벤트에 대해 다음을 SHOULD로 수행합니다:

  1. 이벤트의 target을 "부모" 포인터 이벤트의 target과 일치하도록 설정합니다.

11. 마우스 이벤트와의 호환성 매핑

오늘날 존재하는 웹 콘텐츠의 절대 다수는 오직 Mouse Events에 맞추어 작성되어 있습니다. 다음은 user agent가 일반적인 포인터 입력을 이 콘텐츠와의 호환성을 위해 마우스 이벤트로 MAY 매핑하는 알고리즘을 설명합니다.

마우스 이벤트와의 호환성 매핑은 이 명세의 OPTIONAL 기능입니다. User agent는 기존 레거시 콘텐츠와 최상의 호환성을 위해 이 기능을 지원하는 것이 권장됩니다.

Note

높은 수준에서, 호환성 마우스 이벤트는 해당하는 포인터 이벤트와 “인터리브”되도록 의도되었습니다. 그러나 이 구체적 순서는 필수는 아니며, 호환성 마우스 이벤트를 구현하는 user agent는 상대적 순서가 일관되는 한 마우스 이벤트 디스패치를 지연하거나 묶어서 MAY 할 수 있습니다.

특히 터치스크린 입력의 경우, user agent는 (작성자가 touch-action으로 명시적으로 억제하지 않는 한) 제스처 인식을 위한 추가 휴리스틱을 MAY 적용할 수 있습니다. pointerdown 이벤트와 pointerup 이벤트 사이의 이벤트 시퀀스 동안 제스처 인식은 어떤 제스처를 감지할지 / 무시할지를 판단하기 위해 pointerup 이벤트까지 대기해야 할 수도 있습니다. 그 결과 user agent가 특정 제스처로 의도되지 않았다고 판단하면 전체 시퀀스에 대한 호환성 마우스 이벤트가 마지막 pointerup 이후 함께 디스패치될 수 있습니다. 이러한 user agent 제스처 인식의 구체사항은 이 명세에서 정의되지 않으며 구현마다 다를 수 있습니다.

호환성 마우스 이벤트 지원 여부와 관계없이, user agent는 MUST 항상 click, auxclick, contextmenu 이벤트를 지원해야 합니다. 이는 해당 이벤트가 PointerEvent 타입이며 따라서 호환성 마우스 이벤트가 아니기 때문입니다. 포인터 이벤트 동안 preventDefault를 호출하는 것은 MUST NOT click, auxclick, contextmenu 발생 여부에 영향을 주지 않습니다.

Note

일부 고수준 이벤트(contextmenu, focus, blur 등)의 포인터 이벤트와의 상대적 순서는 정의되지 않았으며 user agent마다 다릅니다. 예: 일부 user agent에서는 contextmenu가 종종 pointerup 뒤에 오지만, 다른 것에서는 pointerup 또는 pointercancel 앞에 오기도 하며, 어떤 상황에서는 (예: 키보드 상호작용 결과) 해당하는 포인터 이벤트 없이 발생할 수도 있습니다.

추가로 user agent는 click, auxclick, contextmenu 이벤트를 발생시킬지 자체 휴리스틱을 적용할 수 있습니다. 일부 user agent는 같은 타입의 다른 (primary가 아닌) 포인터가 있거나, 다른 타입의 primary 포인터가 있는 경우 이러한 이벤트를 발생시키지 않을 수 있습니다. 또한 user agent는 특정 동작이 “깨끗한” 탭, 클릭, 롱프레스가 아니었다고(예: 터치 스크린에서 손가락이 접촉 중 과도하게 움직임) 판단하여 click, auxclick, contextmenu 이벤트를 발생시키지 않기로 결정할 수 있습니다. 이러한 user agent 동작 측면은 명세에서 정의하지 않으며 구현마다 다를 수 있습니다.

별도 언급이 없는 한, 매핑된 마우스 이벤트의 대상은 해당 포인터 이벤트의 대상과 동일해야 SHOULD 하며, 대상이 더 이상 자신의 ownerDocument 트리에 참여하지 않는 경우 마우스 이벤트는 (트리에서 제거된 시점의) 원래 대상의 여전히 트리에 참여하는 가장 가까운 상위 노드에서 발생해야 합니다. 즉, 마우스 이벤트를 위해 (새 대상 노드를 기반으로) 새로운 이벤트 경로가 구성됩니다.

작성자는 pointerdown 이벤트를 취소하여 특정 호환성 마우스 이벤트 생성을 방지할 수 있습니다.

마우스 이벤트는 포인터가 down 상태일 때만 방지될 수 있습니다. Hover 상태의 포인터(예: 버튼을 누르지 않은 마우스)는 그 마우스 이벤트를 방지할 수 없습니다.

mouseover, mouseout, mouseenter, mouseleave 이벤트는 (포인터가 down 상태여도) 결코 방지되지 않습니다.

호환성 마우스 이벤트는 포인터 이벤트 EventListener가 [DOM]의 passive로 설정되어 있을 때는 방지할 수 없습니다.

11.1 레거시 마우스 포인터의 유효 위치 추적

primary pointer만 호환성 마우스 이벤트를 생성할 수 있지만, 복수의 primary 포인터가 동시에 활성 상태일 수 있으며 각 포인터는 자체 호환성 마우스 이벤트를 생성합니다. MouseEvent에 의존하는 스크립트와의 호환성을 위해 마우스 전환 이벤트(mouseover, mouseout, mouseenter, mouseleave)는 단일 레거시 마우스 입력의 이동을 시뮬레이션해야 SHOULD 합니다. 이는 모든 이벤트 타겟의 진입/이탈 상태가 [UIEVENTS]에 부합하도록 하기 위함입니다. User agent는 문서에서 레거시 마우스 포인터의 유효 위치를 다음과 같이 유지하여 이를 보장해야 SHOULD 합니다.

pointerdown, pointerup, pointermove 이벤트 또는 window에서 발생하는 pointerleave 이벤트를 발행하기 직전에, user agent는 다음 단계를 SHOULD 수행해야 합니다:

  1. T를 디스패치 중인 pointerdown, pointerup 또는 pointermove 이벤트의 대상으로 둡니다. pointerleave 이벤트의 경우 T를 unset 합니다.
  2. T와 현재 레거시 마우스 포인터의 유효 위치가 모두 unset 이거나 동일하면 단계를 종료합니다.
  3. 현재 레거시 마우스 포인터의 유효 위치에서 T로 마우스가 이동하는 것으로 [UIEVENTS]에 따라 mouseover, mouseout, mouseenter, mouseleave를 디스패치합니다. 현재 유효 위치 또는 T가 unset이면 창 밖(out-of-window) 마우스 위치로 간주합니다.
  4. 레거시 마우스 포인터의 유효 위치T로 설정합니다.
Note

레거시 마우스 포인터의 유효 위치 개념은 포인터 전환 이벤트(pointerover, pointerout, pointerenter, pointerleave)와 해당하는 레거시 마우스 전환 이벤트(mouseover, mouseout, mouseenter, mouseleave) 사이에 항상 직접 매핑이 존재하지 않는 사실을 모델링합니다. 아래 애니메이션은 단일 레거시 마우스 입력을 사용해 두 개의 primary 포인터를 조화시키기 위해 user agent가 포인터 전환 이벤트보다 더 많은 레거시 마우스 전환 이벤트를 디스패치해야 하는 사례를 보여줍니다.

Figure 9 동시 마우스 포인터(흰 커서)와 터치 포인터(흰 “손” 커서)가 단일 레거시 마우스 입력(주황 커서)을 두 포인터 사이에서 이동시키는 모습.

이 애니메이션에서, 마우스 클릭과 터치 탭 사이 기간을 주목하세요. 버튼 1은 (이 기간 동안 “실제” 마우스 포인터가 버튼 사각형을 벗어나지 않았기 때문에) pointerout 이벤트를 받지 않지만, 터치 탭 시 레거시 마우스 포인터의 유효 위치가 버튼 2로 이동할 때 mouseout 이벤트를 받습니다. 유사하게 터치 탭과 마우스가 버튼 1을 떠나기 전 사이 기간에도 같은 이유로 버튼 1은 pointerover 이벤트를 받지 않지만, 유효 위치가 다시 버튼 1 내부로 돌아올 때 mouseover 이벤트를 받습니다.

11.2 Hover를 지원하는 장치에 대한 매핑

User agent가 hover를 지원하는 장치에 대해 포인터 이벤트를 디스패치하려 할 때마다, 다음 단계를 SHOULD 수행해야 합니다:

  1. 디스패치할 포인터 이벤트의 isPrimary 속성이 false이면 포인터 이벤트를 디스패치하고 종료합니다.
  2. 디스패치할 포인터 이벤트가 pointerdown, pointerup, pointermove 이벤트이거나, window에서의 pointerleave 이벤트라면 레거시 마우스 포인터의 유효 위치 추적에 설명된 대로 호환성 마우스 전환 이벤트를 디스패치합니다.
  3. 포인터 이벤트를 디스패치합니다.
  4. 디스패치된 포인터 이벤트가 pointerdown이고 그 이벤트가 canceled 되었다면, 이 pointerType에 대해 PREVENT MOUSE EVENT 플래그를 설정합니다.
  5. PREVENT MOUSE EVENT 플래그가 해당 pointerType에 설정되어 있지 않고 디스패치된 포인터 이벤트가 다음 중 하나라면:
  6. 디스패치된 포인터 이벤트가 pointerup 또는 pointercancel였다면, 해당 pointerTypePREVENT MOUSE EVENT 플래그를 해제합니다.

11.3 Hover를 지원하지 않는 장치에 대한 매핑

대부분의 터치스크린과 같은 일부 장치는 활성 상태가 아닐 때 좌표(또는 좌표 집합)를 hover하는 기능을 지원하지 않습니다. 마우스 이벤트에 맞추어 작성된 기존 콘텐츠는 마우스가 이벤트를 생성한다고 가정하므로 일반적으로 다음 특성이 참입니다:

Note
Hover는 (예: “hover 메뉴”) 마우스 중심으로 설계된 콘텐츠에서 UI 요소의 가시성을 토글하는 데 때때로 사용됩니다. 이 콘텐츠는 종종 hover를 지원하지 않는 장치와 호환되지 않습니다. 이 명세는 이 시나리오에 대한 매핑이나 동작을 정의하지 않으며, 향후 버전에서 고려될 것입니다.

이러한 유형의 입력 장치에 대해 user agent는 다른 매핑을 제공해야 합니다. User agent가 hover를 지원하지 않는 장치에 대해 포인터 이벤트를 디스패치하려 할 때마다 다음 단계를 SHOULD 수행해야 합니다:

  1. 디스패치할 포인터 이벤트의 isPrimary 속성이 false이면 포인터 이벤트를 디스패치하고 종료합니다.
  2. 디스패치할 포인터 이벤트가 pointerover이고 해당 포인터에 대한 pointerdown 이벤트가 아직 디스패치되지 않았다면 레거시 마우스 전용 코드를 위한 호환성으로 mousemove 이벤트를 발생시킵니다.
  3. 디스패치할 포인터 이벤트가 pointerdown, pointerup, pointermove 이벤트이거나, window에서의 pointerleave 이벤트라면 레거시 마우스 포인터의 유효 위치 추적에 설명된 대로 호환성 마우스 전환 이벤트를 디스패치합니다.
  4. 포인터 이벤트를 디스패치합니다.
  5. 디스패치된 포인터 이벤트가 pointerdown이고 그 이벤트가 canceled 되었다면 해당 pointerTypePREVENT MOUSE EVENT 플래그를 설정합니다.
  6. PREVENT MOUSE EVENT 플래그가 설정되지 않았고 디스패치된 포인터 이벤트가 다음 중 하나라면:
  7. 디스패치된 포인터 이벤트가 pointerup 또는 pointercancel라면 해당 pointerTypePREVENT MOUSE EVENT 플래그를 해제합니다.

User agent가 [TOUCH-EVENTS]에 정의된 Touch Events와 Pointer Events를 모두 지원하는 경우, user agent는 이 섹션에 기술된 호환성 마우스 이벤트와 [TOUCH-EVENTS]에 개괄된 폴백 마우스 이벤트MUST NOT 둘 다 생성해서는 안 됩니다.

Note

hover를 지원하지 않는 primary 포인터(예: 터치스크린의 단일 손가락)로 요소를 활성화(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 이벤트가 canceled 된다면 시퀀스는 다음과 같습니다:

  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, 이벤트 구현에서 직접 발생하는 보안 및 프라이버시 이슈로 한정됩니다.

이 명세에서 정의된 많은 이벤트 타입은 사용자 동작에 대한 응답으로 디스패치됩니다. 이는 악의적인 이벤트 리스너가 사용자가 일반적으로 기밀로 간주하는 정보(예: 페이지 상호작용 중 사용자의 마우스/스타일러스/손가락 이동 경로)를 획득할 수 있게 합니다.

포인터 이벤트에는 (사용자 장치가 지원하는 경우) 펜 입력이 유지되는 각도나 기울기, 접촉 표면의 기하, 스타일러스 또는 터치 스크린에 가해진 압력과 같은 추가 정보가 포함됩니다. 각도, 기울기, 기하 및 압력 정보는 사용자 장치의 센서와 직접 관련되므로 이 명세는 출처(origin)가 이러한 센서에 접근하는 것을 허용합니다.

이 센서 데이터 및 사용된 입력 메커니즘 유형(마우스, 터치, 펜)을 판별하는 능력은 사용자 또는 사용자 장치 및 환경 특성을 추론하는 데 사용될 수 있습니다. 이러한 추론된 특성과 장치/환경 정보 자체는 민감할 수 있으며—예: 악의적인 사이트가 사용자가 보조기술을 사용 중인지 추가로 추론할 수 있도록 할 수 있습니다. 이 정보는 사용자 프로파일 작성 및/또는 특정 사용자를 “지문채취(fingerprinting)”하여 추적하는 데 잠재적으로 사용될 수 있습니다.

완화책으로, user agent는 특정 센서 데이터(각도, 기울기, 압력 등)에 대한 접근을 사용자가 비활성화하거나, 사용자 명시적 옵트인(opt-in) 이후에만 이용 가능하도록 하는 기능을 포함하는 것을 고려할 수 있습니다.

이 명세는 작성자가 “predicted events”에 접근하는 방법을 정의합니다. 자체적으로 user agent가 예측에 사용할 알고리즘은 정의하지 않습니다. 명세 작성자들은 알고리즘이 사용자가 수행 중인 현재 제스처와 관련된 이전 포인터 이벤트에만 의존한다고 예상합니다. User agent는 자체 예측 알고리즘 구현이 사용자나 여러 사이트에 걸친 전체 상호작용 기록 등 추가 데이터에 의존하지 않아 사용자에 대한 민감한 정보를 노출하거나 “fingerprint”에 사용되지 않도록 보장할 책임이 있습니다.

이러한 고려사항 외에, 작업 그룹은 이 명세가 다음과 같다고 판단합니다:

13. 용어집

이 섹션은 비규범적입니다.

active buttons state
buttons 속성 값이 0이 아닌 상태. 마우스의 경우 하나 이상의 버튼이 눌려 있을 때. 터치의 경우 디지타이저와 물리적 접촉이 있을 때. 펜의 경우 펜이 디지타이저와 물리적 접촉 중이거나, 호버 중 하나 이상의 버튼이 눌린 경우.
active document
active pointer에 대해 마지막으로 그 포인터의 이벤트를 받은 문서.
active pointer
이벤트를 생성할 수 있는 모든 터치 접촉, 펜/스타일러스, 마우스 커서 또는 기타 포인터. 고유 pointerId로 식별되는 포인터가 문서 내에서 추가 이벤트를 생성할 가능성이 있으면 여전히 active로 간주. 예:
  • 장치에 연결된 마우스는 항상 active.
  • 화면상의 터치 접촉은 active.
  • 터치 접촉 또는 펜/스타일러스가 디지타이저 범위를 벗어나면 더 이상 active가 아님.
Note
일부 플랫폼에서는 active 포인터 집합에 user agent를 대상으로 하지 않는 입력(다른 애플리케이션 대상 포함)도 포함됩니다.
canceled event
preventDefault() 호출, 이벤트 핸들러에서 false 반환, 또는 [UIEVENTS] 및 [HTML]에 정의된 기타 수단으로 기본 동작이 방지된 이벤트.
contact geometry
디지타이저 위 입력(주로 터치)의 경계 박스. 일반적으로 단일 픽셀보다 포인터 입력 해상도가 더 거친 장치에 해당. 일부 장치는 이 데이터를 전혀 보고하지 않음.
digitizer
표면이 접촉 및/또는 근접한 입력을 감지할 수 있는 입력 감지 장치 유형. 가장 일반적으로 터치 접촉 또는 펜/스타일러스 입력을 감지하는 표면.
direct manipulation
일부 user agent(예: 터치스크린 장치의 브라우저)는 포인터가 컨트롤과 상호작용할 뿐 아니라 현재 페이지를 직접 패닝하거나 확대/축소할 수 있게 하여 직접 물리적 접촉의 환상을 제공하는 “direct manipulation” 메타포를 구현합니다. 예: 터치스크린 장치의 사용자는 손가락이나 스타일러스로 페이지를 “잡고” 포인터를 이동하여 패닝할 수 있습니다. 이는 일반 데스크톱/랩톱에서 마우스 포인터로 스크롤바를 사용해 패닝하는 것과 대조됩니다.
Note
일부 경우 노트북 등의 터치패드는 사용자가 드래그하여 스크롤하도록 허용합니다. 그러나 이는 일반적으로 터치패드가 “가짜” 마우스 휠 이벤트를 생성하여 이루어지므로 direct manipulation으로 간주되지 않습니다.
hit test
User agent가 포인터 이벤트 대상 요소를 결정하는 과정. 일반적으로 포인터 위치와 문서 내 요소의 시각적 레이아웃을 고려하여 결정.
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 작업 초안(Working Draft). 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 권고(Recommendation). 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. 상시 표준. URL: https://html.spec.whatwg.org/multipage/
[infra]
Infra Standard. Anne van Kesteren; Domenic Denicola. WHATWG. 상시 표준. 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. 현재 모범 사례. 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. 상시 표준. URL: https://webidl.spec.whatwg.org/

D.2 참고용 참고 문헌

[COMPAT]
Compatibility Standard. Mike Taylor. WHATWG. 상시 표준. 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/