Copyright © 2025 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
이 명세의 기능은 'Pointer Events'에서 발견되는 기능을 확장하거나 수정합니다. 'Pointer Events'는 마우스, 펜, 터치스크린 등의 장치로부터 하드웨어에 독립적인 포인터 입력을 처리하기 위한 이벤트와 관련 인터페이스를 설명하는 W3C 권고안입니다. 기존 마우스 기반 콘텐츠와의 호환성을 위해, 이 명세는 다른 포인터 장치 유형에 대해서도 마우스 이벤트를 발생시키는 매핑을 설명합니다.
이 섹션은 이 문서가 발행될 당시의 상태를 설명합니다. 현재 W3C 발행 목록과 이 기술 보고서의 최신 개정판은 W3C 표준 및 초안 인덱스에서 확인할 수 있습니다.
이 명세는 [PointerEvents2]의 업데이트 버전입니다.
이 개정판에는 새로운 기능이 포함되어 있습니다:
altitudeAngleazimuthAnglepointerrawupdate 이벤트(고주파 이벤트용)이 개정판에는 명확한 설명도 포함되어 있습니다:
pointerId를 할당하는 전략 및 접근법click,
auxclick, contextmenu 이벤트와의 관계이 명세가 후보 권고안 단계를 벗어나기 전에, 두 개 이상의 독립적인 구현이 각각의 테스트를 통과해야 하지만, 모든 테스트를 단일 구현이 통과할 필요는 없습니다.
이 문서는 Pointer Events 워킹 그룹이 권고안 트랙을 사용하여 후보 권고안 스냅샷으로 발행했습니다.
후보 권고안으로 발행된다고 해서 W3C와 그 구성원이 이를 승인했다는 것을 의미하지는 않습니다. 후보 권고안 스냅샷은 광범위한 검토를 받았으며, 구현 경험을 수집하기 위해 발행된 것으로, 워킹 그룹 구성원이 구현에 대해 로열티 없는 라이선스를 약속했음을 의미합니다.
이 후보 권고안은 2025년 12월 4일 이전에는 제안된 권고안 단계로 진입하지 않을 예정입니다.
이 문서는 W3C 특허 정책을 따르는 그룹에 의해 제작되었습니다. W3C는 공개 특허 공개 목록을 해당 그룹 산출물과 연결하여 관리합니다. 해당 페이지에는 특허 공개 방법도 안내되어 있습니다. 특정 특허에 대한 실질적인 정보를 가진 경우, Essential Claim이 포함되어 있다고 생각할 경우 W3C 특허 정책 6절에 따라 그 정보를 공개해야 합니다.
본 문서는 2025년 8월 18일 W3C 프로세스 문서에 의해 관리됩니다.
이 섹션은 권고 사항이 아닙니다.
오늘날 대부분의 [HTML] 콘텐츠는 마우스 입력에 맞추어 사용되거나 설계됩니다. 입력을 사용자 정의 방식으로 처리하는 경우 대개 [UIEVENTS] 마우스 이벤트에 맞추어 코딩합니다. 그러나 최근의 컴퓨팅 장치들은 터치스크린이나 펜 입력 등 다양한 입력 방식을 채택하고 있습니다. 각각의 입력 방식별로 이벤트 타입이 제안되어 왔지만, 이러한 접근법은 새 입력 타입을 지원할 때 불필요한 중복 로직 및 이벤트 처리 오버헤드를 초래합니다. 이로 인해 콘텐츠가 특정 단일 장치만을 염두에 두고 작성되면 호환성 문제가 자주 발생합니다. 또한, 기존 마우스 기반 콘텐츠와의 호환성 때문에 대부분의 user agents는 모든 입력 타입에 대해 마우스 이벤트를 발생시킵니다. 이로 인해 마우스 이벤트가 실제 마우스 장치에서 온 것인지, 아니면 호환성을 위해 다른 입력 장치에서 생성된 것인지 모호해지며, 두 장치 타입 모두를 동시에 지원하는 코드를 작성하기가 어렵습니다.
여러 입력 타입에 대응하는 코딩 비용을 줄이고, 위에서 언급한 마우스 이벤트의 모호성 문제를 해소하기 위해, 이 명세에서는 포인터라는 더 추상적인 입력 개념을 정의합니다. 포인터란 마우스 커서, 펜, 터치(멀티터치 포함), 또는 기타 포인팅 입력 장치로 화면에 접촉하는 모든 지점이 될 수 있습니다. 이 모델을 사용하면 사용자가 어떤 하드웨어를 사용하든 잘 동작하는 사이트와 애플리케이션을 쉽게 작성할 수 있습니다. 장치별 처리가 필요한 상황에 대비해, 이 명세는 이벤트를 생성한 장치 유형을 검사할 수 있는 속성도 정의합니다. 주요 목표는 크로스-디바이스 포인터 입력을 위해 더 쉽게 작성할 수 있도록 단일 이벤트 및 인터페이스 집합을 제공하되, 확장 경험에 필요한 경우 장치별 처리가 가능하도록 하는 것입니다.
또 다른 주요 목표는 멀티스레드 유저 에이전트가 직접 조작 동작(예: 터치스크린에서 손가락이나 스타일러스로 팬/줌 등)을, 스크립트 실행에 블로킹되지 않고 처리할 수 있도록 하는 것입니다.
이 명세는 다양한 포인터 입력에 대해 통합된 이벤트 모델을 정의하지만, 키보드나 키보드와 유사한 인터페이스(예: 터치스크린 기반 장치에서 구동되는 화면 판독기 또는 유사 보조 기술 등과 같이, 사용자가 포커스 가능한 컨트롤 및 요소를 순차적으로 탐색하는 환경)는 포괄하지 않습니다. 유저 에이전트가 이러한 인터페이스에 반응하여 포인터 이벤트를 생성할 수도 있지만, 이 명세에서는 해당 시나리오를 다루지 않습니다.
우선, 작성자들은 focus, blur,
click과 같은 고수준 이벤트에 응답하여 모든 입력 방식에 대해 동등한 기능을 제공하도록 권장합니다. 그러나 저수준 이벤트(예: 포인터 이벤트)를 사용할
경우 모든 입력 타입이 지원되는지 확인해야 합니다. 키보드 및 키보드와 유사한 인터페이스의 경우, 명시적 키보드 이벤트 처리가 추가로 필요할 수 있습니다. 자세한 내용은 키보드 접근성 [WCAG22]를 참고하시기 바랍니다.
일반적인 포인터 입력 처리를 위한 이벤트는 마우스 이벤트와 매우 유사합니다: pointerdown,
pointermove, pointerup, pointerover, pointerout
등등. 이로 인해 마우스 이벤트 기반 콘텐츠를 손쉽게 포인터 이벤트 기반으로 이관할 수 있습니다.
포인터 이벤트는 마우스 이벤트에 있는 모든 기존 속성(클라이언트 좌표, 타겟 요소, 버튼 상태 등)과 더불어 압력, 접촉 영역, 기울기 등 다른 입력 방식의 새로운 속성을 추가로 제공합니다.
작성자는 포인터 이벤트로 입력 타입 간에 로직을 공유하고, 필요할 때만 특정 입력 타입에 맞게 세부 구현을 분기할 수 있습니다.
포인터 이벤트는 다양한 입력 장치에서 기원하지만, 반드시 특정 장치별 이벤트를 기반으로 생성된다고 명의된 것은 아닙니다. 호환성을 위해 그럴 수도 있고 장려되지만, 이 명세는 마우스 이벤트나 터치 이벤트 같은 타 장치 이벤트 지원을 필수로 요구하지 않습니다. 유저 에이전트는 다른 장치 이벤트 지원 없이 포인터 이벤트만 지원할 수도 있습니다. 마우스 전용 이벤트에 맞추어 작성된 콘텐츠와의 호환성을 위해, 이 명세에서는 마우스가 아닌 장치의 포인터 입력을 기반으로 호환성 마우스 이벤트를 어떻게 생성할지에 대한 선택적 섹션도 제공합니다.
이 명세는 [TOUCH-EVENTS]에 정의된 터치 이벤트와 포인터 이벤트를 모두 지원하는 유저 에이전트의 예상 동작에 대한 지침을 제공하지 않습니다. 두 명세의 관계에 대한 추가 정보는 Touch Events 커뮤니티 그룹을 참고하세요.
비규범으로 표시된 섹션뿐 아니라, 이 명세의 모든 작성 가이드라인, 다이어그램, 예시 및 주석은 비규범입니다. 본 명세에서 그 외의 모든 내용이 규범적입니다.
이 문서에서 MAY, MUST, MUST NOT, OPTIONAL, SHOULD와 같은 주요 단어는 BCP 14 [RFC2119] [RFC8174] 에서 설명한 바와 같이, 오직 대문자로 나타날 때만 해당 의미를 갖습니다.
이 섹션은 권고 사항이 아닙니다.
아래는 본 명세의 일부 API를 작성자들이 어떻게 사용할 수 있는지 보여주는 기본 예시입니다. 더 구체적인 예시는 각 섹션에 따로 제공됩니다.
/* 포인터 이벤트 또는 기존 터치/마우스에 바인딩 */
if (window.PointerEvent) {
// Pointer Event가 지원되면 포인터 이벤트만 리슨
target.addEventListener("pointerdown", function(e) {
// 필요하다면 e.pointerType에 따라 별도 분기 처리
// 터치/펜/마우스 구분 동작
...
});
...
} else {
// 기존 터치/마우스 이벤트 핸들러
target.addEventListener('touchstart', function(e) {
// 호환성을 위한 마우스 이벤트 및 클릭 방지
e.preventDefault();
...
});
...
target.addEventListener('mousedown', ...);
...
}
// 키보드 처리를 위한 추가 이벤트 리스너
...
window.addEventListener("pointerdown", detectInputType);
function detectInputType(event) {
switch(event.pointerType) {
case "mouse":
/* 마우스 입력 감지 */
break;
case "pen":
/* 펜/스타일러스 입력 감지 */
break;
case "touch":
/* 터치 입력 감지 */
break;
default:
/* pointerType이 비어 있음(감지 불가)
또는 UA별 커스텀 타입 */
}
}
<div style="position:absolute; top:0px; left:0px; width:100px;height:100px;"></div>
<script>
window.addEventListener("pointerdown", checkPointerSize);
function checkPointerSize(event) {
event.target.style.width = event.width + "px";
event.target.style.height = event.height + "px";
}
</script>
const event1 = new PointerEvent("pointerover",
{ bubbles: true,
cancelable: true,
composed: true,
pointerId: 42,
pointerType: "pen",
clientX: 300,
clientY: 500
});
eventTarget.dispatchEvent(event1);
let pointerEventInitDict =
{
bubbles: true,
cancelable: true,
composed: true,
pointerId: 42,
pointerType: "pen",
clientX: 300,
clientY: 500,
};
const p1 = new PointerEvent("pointermove", pointerEventInitDict);
pointerEventInitDict.clientX += 10;
const p2 = new PointerEvent("pointermove", pointerEventInitDict);
pointerEventInitDict.coalescedEvents = [p1, p2];
const event2 = new PointerEvent("pointermove", pointerEventInitDict);
eventTarget.dispatchEvent(event2);
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;
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;
[SecureContext] sequence<PointerEvent> getCoalescedEvents();
sequence<PointerEvent> getPredictedEvents();
};
pointerId이벤트를 발생시킨 포인터에 대한 고유 식별자입니다. user agents는 기본 마우스 포인터에 대해 일반적인 pointerId
값 0 또는 1을 MAY 예약할 수 있습니다. pointerId
값 -1은 포인팅 장치가 아닌 것에 의해 생성된 이벤트를 나타내기 위해 MUST 예약되어야
합니다. 그 외 포인터에 대해, 사용자 에이전트는 pointerId 값을 할당하는 전략과 접근 방식을
자유롭게 구현할 수 있습니다. 다만, [HTML]에서 정의하는 최상위
탐색 컨텍스트 내의 모든 활성 포인터는 고유해야 하며, 식별자는 다른 최상위 탐색 컨텍스트에 의해 영향을 받아서는
MUST NOT 않습니다(즉, 한 최상위 탐색 컨텍스트는 포인터가 해당 컨텍스트 밖으로 이동해 다른 최상위 탐색
컨텍스트로 들어갈 때 동일한 pointerId를 가질 것이라고 가정할 수 없음).
user agent는 이전의
활성 포인터에서 사용한 pointerId
값을 재활용할 수도 있고, 특정 포인팅 장치에 대해 항상 동일한 pointerId를 재사용할 수도 MAY 합니다(예: 다중 사용자 협업 애플리케이션에서 특정 사용자의 특정 펜/스타일러스 입력을 고유하게 식별하기 위해).
그러나 후자의 경우, 지문 채취 및 다른 페이지/도메인 간 추적 가능성을 최소화하려면, 해당 페이지/세션의 기간 동안에만 그 특정 포인팅 장치에 pointerId를 명시적으로 연관해야 MUST 하며, 그 장치가 새로운 세션에서 다시 사용될 때는 새로운 무작위화된 pointerId를 선택해야 MUST 합니다.
width포인터의 접촉 지오메트리의 X축 방향 크기를 CSS 픽셀([CSS21])로
나타냅니다. 이 값은 주어진 포인터에 대해 각 이벤트마다 MAY 업데이트될 수 있습니다. (전통적인 마우스처럼)
일반적으로 접촉 지오메트리가 없는 입력이나, 하드웨어가 실제 지오메트리를 감지하지 못하는 경우에는 user agent가 기본값 1을
반환해야 MUST 합니다.
height포인터의 접촉 지오메트리의 Y축 방향 크기를 CSS 픽셀([CSS21])로
나타냅니다. 이 값은 주어진 포인터에 대해 각 이벤트마다 MAY 업데이트될 수 있습니다. (전통적인 마우스처럼)
일반적으로 접촉 지오메트리가 없는 입력이나, 하드웨어가 실제 지오메트리를 감지하지 못하는 경우에는 user agent가 기본값 1을
반환해야 MUST 합니다.
pressure포인터 입력의 정규화된 압력으로, [0,1] 범위입니다. 0과 1은 각각 하드웨어가 감지 가능한
최소 및 최대 압력을 나타냅니다. 압력을 지원하지 않는 하드웨어나 플랫폼의 경우, 활성 버튼
상태에서는 값이 0.5, 그렇지 않으면 0이어야 MUST
합니다.
tangentialPressure정규화된 접선 압력(바렐 압력이라고도 함)으로, 일반적으로 추가 제어(예: 에어브러시 스타일러스의 휠)에 의해 설정됩니다. 값의 범위는
[-1,1]이며, 0은 제어의 중립 위치입니다. 일부 하드웨어는 [0,1] 범위의 양수 값만
지원할 수 있습니다. 접선 압력을 지원하지 않는 하드웨어나 플랫폼의 경우, 값은 0이어야 MUST
합니다.
tiltXY-Z 평면과 트랜스듀서(예: 펜/스타일러스) 축과 Y축을 포함하는 평면 사이의 평면 각(도 단위, [-90,90] 범위)입니다. 양의
tiltX는 오른쪽(증가하는 X 값 방향)입니다. tiltX는 tiltY와 함께 사용하여
디지타이저에 대한 트랜스듀서의 법선에서의 기울기를 나타낼 수 있습니다. 기울기나 각도를 보고하지 않는 하드웨어 및 플랫폼의 경우, 값은
0이어야 MUST 합니다.
tiltX.
tiltYX-Z 평면과 트랜스듀서(예: 펜/스타일러스) 축과 X축을 포함하는 평면 사이의 평면 각(도 단위, [-90,90] 범위)입니다. 양의
tiltY는 사용자 쪽(증가하는 Y 값 방향)입니다. tiltY는 tiltX와 함께 사용하여
디지타이저에 대한 트랜스듀서의 법선에서의 기울기를 나타낼 수 있습니다. 기울기나 각도를 보고하지 않는 하드웨어 및 플랫폼의 경우, 값은
0이어야 MUST 합니다.
tiltY.
twist트랜스듀서(예: 펜/스타일러스)의 주축을 중심으로 한 시계 방향 회전(도 단위, [0,359] 범위)입니다. 트위스트를 보고하지 않는 하드웨어
및 플랫폼의 경우, 값은 0이어야 MUST 합니다.
altitudeAngle트랜스듀서(예: 펜/스타일러스)의 고도(라디안)로, [0,π/2] 범위입니다 — 0은 표면(X-Y 평면)과 평행,
π/2는 표면에 수직입니다. 기울기나 각도를 보고하지 않는 하드웨어 및 플랫폼의 경우, 값은 π/2이어야 MUST 합니다.
altitudeAngle의 기본값은 π/2로, 트랜스듀서를 표면에 수직으로 둡니다.
이는 Touch Events - Level
2 명세의 altitudeAngle 기본값(0) 정의와 다릅니다.
altitudeAngle = π/4 (X-Y 평면에서 45도).azimuthAngle트랜스듀서(예: 펜/스타일러스)의 방위각(라디안)으로, [0, 2π] 범위입니다 — 0은 캡이 X-Y 평면에서 증가하는
X 값 방향(수직으로 내려다볼 때 “3시” 방향)을 가리키는 상태를 나타내며, 시계 방향으로 갈수록 값이 증가합니다(π/2가 “6시”,
π가 “9시”, 3π/2가 “12시”). 트랜스듀서가 표면에 완전히
수직이면(altitudeAngle이 π/2) 값은 0이어야 MUST 합니다. 기울기나 각도를 보고하지 않는 하드웨어 및 플랫폼의 경우에도 값은 0이어야
MUST 합니다.
azimuthAngle = π/6 (“4시” 방향).pointerType이벤트를 발생시킨 장치 유형(예: mouse, pen, touch)을 나타냅니다. 사용자 에이전트가 마우스, 펜/스타일러스 또는 터치 입력 장치에 대해 포인터 이벤트를 발행하는 경우, pointerType의
값은 다음 표를 MUST 따릅니다:
| 포인터 장치 유형 | pointerType 값 |
|---|---|
| Mouse | mouse |
| Pen / stylus | pen |
| Touch contact | touch |
장치 유형을 사용자 에이전트가 감지할 수 없다면, 값은 빈 문자열이어야 MUST 합니다. 위에 나열된 것 외의 포인터 장치
유형을 지원하는 사용자 에이전트는 서로 다른 장치 유형 간 이름 충돌을 피하기 위해 pointerType 값을 벤더 프리픽스 형태로 제공하는
것이 SHOULD 입니다. 향후 명세에서는 다른 장치 유형에 대해 추가적인 규범 값들을 MAY 제공할 수 있습니다.
pointerType 사용법은 예제
2를 참고하십시오. 또한, 일부 사용자 에이전트는 자체 커스텀 pointerType 값을 구현했거나,
pointerType이 단순히 빈 문자열인 상황을 대비해 기본 처리 로직을 포함하는 것이 좋습니다.
isPrimary해당 포인터가 이 포인터 유형의 기본 포인터를 나타내는지 여부를 표시합니다.
getCoalescedEvents()coalesced 이벤트 목록을 반환하는 메서드입니다.
getPredictedEvents()predicted 이벤트 목록을 반환하는 메서드입니다.
PointerEventInit 딕셔너리는 PointerEvent 인터페이스의 생성자에서 사용되며, 신뢰할 수 없는(합성된)
포인터 이벤트를 구성하는 메커니즘을 제공합니다. 이는 [UIEVENTS]에 정의된 MouseEventInit
딕셔너리를 상속합니다. 신뢰할 수 없는 포인터 이벤트를 발생시키는 샘플 코드는 예시를 참고하십시오.
이벤트
구성 단계에서 PointerEvent는 PointerEventInit의 coalescedEvents를 coalesced 이벤트 목록으로 복제하고,
PointerEventInit의 predictedEvents를 predicted 이벤트 목록으로 복제합니다.
PointerEvent 인터페이스는 UI
Events에 정의된 MouseEvent를 상속합니다.
또한, 다양한 좌표 속성을 분수 좌표를 허용하도록 long에서 double로 변경하는 CSSOM
View Module의 제안 확장에 유의하십시오. 이 제안 확장을 이미
PointerEvent에는 적용했지만 일반 MouseEvent에는 적용하지 않은 사용자
에이전트의 경우,
click,
auxclick, contextmenu 이벤트에 대해 추가 요구 사항이 있습니다.
멀티 포인터(예: 멀티 터치) 시나리오에서, isPrimary 속성은 각 포인터 유형에 대해 활성 포인터 집합 중 주
포인터를 식별하는 데 사용됩니다.
pointerType별로 하나)가 기본으로 간주됩니다.
예를 들어, 터치 접촉과 마우스 커서를 동시에 이동하면 두 포인터 모두 기본으로 간주됩니다.
isPrimary가 false인 다른 포인터에 대한 포인터 이벤트를 MAY 발행할 수 있습니다.포인터 이벤트를
발행한다는 것은, 이름이 e인 이벤트를 발행하되, PointerEvent를 사용하고 그 속성을 PointerEvent 인터페이스 및 속성과 기본 동작에 정의된 대로 설정하는 것을 의미합니다.
이 이벤트가 gotpointercapture, lostpointercapture, click,
auxclick, contextmenu가 아닌 경우, 이 PointerEvent에 대해 대기 중인 포인터 캡처 처리 단계를 실행합니다.
이벤트가 발행될 대상(대상 결정)은 다음과 같이 정합니다:
targetDocument를 target의 노드 문서 [DOM]로 둡니다.
이 이벤트가 pointerdown, pointermove, 또는 pointerup인 경우, 해당 이벤트의 pointerId에 대한 활성 문서를 targetDocument로 설정합니다.
이 이벤트가 pointerdown이고, 관련 장치가 직접 조작 장치이며, 대상이 Element인 경우,
암시적 포인터 캡처에 설명된 대로 이 pointerId에 대해 대상 요소로 포인터 캡처 설정을 수행합니다.
이 이벤트를 발행하기 전에, user
agent는 이벤트 순서 보장
[UIEVENTS]을 위해, 포인팅 장치가 previousTarget에서 대상 위로 이동한
것처럼 대상을 취급해야 SHOULD 합니다. needsOverEvent 플래그가 설정되어 있으면, 대상 요소가
같더라도 pointerover 이벤트가 필요합니다.
결정된 대상에 이벤트를 발행합니다.
결정된 대상을 해당 포인터의 previousTarget으로 저장하고, needsOverEvent 플래그를 false로
재설정합니다. previousTarget이 더 이상 [DOM]의 연결됨 상태가 아니라면,
previousTarget로 이벤트를 디스패치하는 이벤트 경로에 해당하는 가장 가까이 여전히 연결됨 [DOM] 부모로
previousTarget을 업데이트하고, needsOverEvent 플래그를 true로 설정합니다.
이 명세에서 정의된 이벤트 유형에 대한 bubbles 및 cancelable 속성과 기본 동작은 다음 표에 나와 있습니다. 각
이벤트 유형의 세부 사항은 포인터 이벤트 유형에 설명되어 있습니다.
| 이벤트 유형 | Bubbles | Cancelable | 기본 동작 |
|---|---|---|---|
pointerover |
Yes | Yes | None |
pointerenter |
No | No | None |
pointerdown |
Yes | Yes | Varies: 포인터가 기본일 때, mousedown 이벤트의 모든 기본 동작
이 이벤트를 취소하면 이후 호환성 마우스 이벤트 발행도 방지됩니다. |
pointermove |
Yes | Yes | Varies: 포인터가 기본일 때, mousemove의 모든 기본 동작
|
pointerrawupdate |
Yes | No | None |
pointerup |
Yes | Yes | Varies: 포인터가 기본일 때, mouseup의 모든 기본 동작
|
pointercancel |
Yes | No | None |
pointerout |
Yes | Yes | None |
pointerleave |
No | No | None |
gotpointercapture |
Yes | No | None |
lostpointercapture
|
Yes | No | None |
뷰포트 조작(패닝 및 줌) — 일반적으로 직접 조작 상호작용의 결과 — 은 의도적으로 포인터
이벤트의 기본 동작이 아닙니다. 즉, 이러한 동작(예: 터치스크린에서 손가락을 움직여 페이지를 패닝하는 동작)은 포인터 이벤트를 취소하여 억제할 수 없습니다. 작성자는
문서의 특정 영역에 대해 touch-action을 사용하여 명시적으로 직접
조작 동작을 선언해야 합니다. 이벤트 취소에 대한 의존성을 제거하면 사용자 에이전트가 성능 최적화를 수행하기 쉬워집니다.
pointerenter와 pointerleave 이벤트의 경우, [DOM]의 composed 속성은
false여야 SHOULD 하며; 위 표의 다른 포인터 이벤트에서는 이 속성이
true여야 SHOULD 합니다.
위 표의 모든 포인터 이벤트에서, [UIEVENTS]의 detail 속성은 0이어야
SHOULD 합니다.
fromElement와
toElement를 노출합니다. 이러한 사용자 에이전트는 작성자가 표준화된 대체(target 및
relatedTarget)로 전환할 수 있도록, 포인터 이벤트에서 해당(상속된) 속성 값들을 null로 설정하는 것이
좋습니다.
MouseEvent의 relatedTarget과
유사하게, relatedTarget는 ( pointerover 또는
pointerenter 이벤트의 경우) 포인터가 방금 떠난 요소, 또는 (pointerout 또는 pointerleave 이벤트의 경우) 포인터가 진입 중인 요소로 초기화되어야
합니다. 다른 포인터 이벤트의 경우 이 값은 기본적으로 null입니다. 요소가 포인터 캡처를 받으면, 해당 포인터에 대한 이후 모든 이벤트는 캡처링 요소의 경계 내부에 있는
것으로 간주됩니다.
gotpointercapture 및 lostpointercapture 이벤트의 경우, 위 표에서 정의된
속성을 제외한 모든 속성은 사용자 에이전트가 대기 중인 포인터 캡처 처리
단계를 실행하고 gotpointercapture 및 lostpointercapture 이벤트를 발행하도록 만든 포인터
이벤트와 동일해야 합니다.
user agent는 포인터 캡처를 암시적으로 해제할 때뿐 아니라, gotpointercapture나 lostpointercapture가 아닌 포인터 이벤트를 발행할
때도 아래 단계를 MUST 실행해야 합니다.
lostpointercapture라는 이름의 포인터 이벤트를
포인터 캡처 대상 오버라이드 노드에 발행합니다.
gotpointercapture라는 이름의 포인터 이벤트를
대기 중 포인터
캡처 대상 오버라이드에 발행합니다.
click,
auxclick, contextmenu 이벤트 섹션에 정의된 바와 같이, lostpointercapture 이벤트가 디스패치된
이후에도,
해당하는 click, auxclick 또는 contextmenu 이벤트(있는 경우)는
여전히 캡처링 대상에 디스패치됩니다.
user agent는 특정 pointerId로 웹 페이지가 포인터 이벤트를 계속
수신할 가능성이 낮다고 감지하는 경우, 포인터 이벤트 스트림을 억제해야 MUST 합니다. 다음 시나리오 중 하나라도 해당 조건을 만족합니다(추가 시나리오가 MAY 있을 수 있음):
touch-action CSS 속성 섹션을 참고하세요.
user agent가 포인터 이벤트 스트림을 억제할 수 있는 다른 시나리오에는 다음이 포함됩니다:
이러한 시나리오를 감지하는 방법은 이 명세의 범위를 벗어납니다.
user agent는 포인터 이벤트 스트림을 억제하기 위해 다음 단계를 MUST 실행합니다:
pointercancel 이벤트를 발행합니다.pointerout 이벤트를 발행합니다.pointerleave 이벤트를 발행합니다.화면 표면에 대해 상대적으로 이동했거나 속성 중 일부가 변경된 포인터 장치는 포인터 이벤트 유형에 정의된 다양한 이벤트를 발생시킵니다.
화면 표면에 대해 상대적으로 이동하지 않았고 어떤 속성도 변경되지 않은 정지 상태의 포인터 장치의 경우, user agent는 레이아웃 변경이 포인터의 히트
테스트 대상을 변경했을 때 특정 경계 이벤트를 MUST 발생시켜야 합니다. 자세한 내용은 pointerover, pointerenter, pointerout, pointerleave를 참조하십시오. user agent는 성능상의 이유(예: 경계 이벤트 리스너로 인해 과도한
히트 테스트나 레이아웃 변경이 발생하는 것을 방지하기 위해) 이러한 경계 이벤트의 발생을 MAY 지연시킬 수 있습니다.
pointermove 이벤트를 결코 발생시키지 않습니다.Pointer Events는 X-Y 평면에 대한 트랜스듀서의 방향을 표현하기 위해 상호 보완적인 두 집합의 속성을 포함합니다: 원래 Pointer Events 명세에서 도입된
tiltX / tiltY, 그리고 Touch
Events - Level 2
명세에서 채택한 azimuthAngle / altitudeAngle.
구체적인 하드웨어와 플랫폼에 따라, 사용자 에이전트는 화면 평면에 대한 트랜스듀서 방향 값 집합을 하나만 수신할 가능성이 높습니다 — tiltX /
tiltY 또는 altitudeAngle / azimuthAngle 중 하나입니다. 사용자 에이전트는 이러한
값을 변환하기 위해 아래 알고리즘을 MUST 사용해야 합니다.
사용자 에이전트가 azimuthAngle / altitudeAngle에서 tiltX /
tiltY를 계산하는 경우, 최종 정수 값은 Math.round [ECMASCRIPT] 규칙을 사용해 반올림하는 것이 SHOULD 입니다.
/* tiltX/tiltY와 altitudeAngle/azimuthAngle 간 변환 */
function spherical2tilt(altitudeAngle, azimuthAngle) {
const radToDeg = 180/Math.PI;
let tiltXrad = 0;
let tiltYrad = 0;
if (altitudeAngle == 0) {
// 펜이 X-Y 평면에 있음
if (azimuthAngle == 0 || azimuthAngle == 2*Math.PI) {
// 펜이 X축 양의 방향에 있음
tiltXrad = Math.PI/2;
}
if (azimuthAngle == Math.PI/2) {
// 펜이 Y축 양의 방향에 있음
tiltYrad = Math.PI/2;
}
if (azimuthAngle == Math.PI) {
// 펜이 X축 음의 방향에 있음
tiltXrad = -Math.PI/2;
}
if (azimuthAngle == 3*Math.PI/2) {
// 펜이 Y축 음의 방향에 있음
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;
// 방위각 계산
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) {
// 방위각을 계산하기에 충분한 정보가 없음
azimuthAngle = 0;
} else {
// 경계가 아닌 경우: tiltX와 tiltY가 0이나 ±90이 아님
const tanX = Math.tan(tiltXrad);
const tanY = Math.tan(tiltYrad);
azimuthAngle = Math.atan2(tanY, tanX);
if (azimuthAngle < 0) {
azimuthAngle += 2*Math.PI;
}
}
// 고도각 계산
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 {
// 경계가 아닌 경우: tiltX와 tiltY가 0이나 ±90이 아님
altitudeAngle = Math.atan(1.0/Math.sqrt(Math.pow(Math.tan(tiltXrad),2) + Math.pow(Math.tan(tiltYrad),2)));
}
return {"altitudeAngle":altitudeAngle, "azimuthAngle":azimuthAngle};
}
아래는 이 명세에서 정의한 이벤트 유형입니다.
기본 포인터의 경우, 아래 이벤트들(gotpointercapture 및 lostpointercapture는 제외)이 호환성 마우스 이벤트도 발생시킬 수 있습니다.
user agent는 다음 중 하나가
발생하면 MUST 이름이 pointerover인 포인터 이벤트를 발생시켜야 합니다:
pointerdown 이벤트를 발생시키기 전에, 호버를 지원하지 않는 장치에 대해(자세한 내용은 pointerdown 참조).user agent는 다음 중 하나가
발생하면 MUST 이름이 pointerenter인 포인터 이벤트를 발생시켜야 합니다:
pointerdown 이벤트를 발생시키기 전에, 호버를 지원하지 않는 장치에 대해(자세한 내용은 pointerdown 참조).pointerover와 유사하지만 두 가지 차이가 있습니다: pointerenter는 버블링되지 않으며, 디스패치 시 하위 요소의 히트
테스트 경계까지 고려합니다.mouseenter 이벤트 및 [CSS21]에
설명된 CSS :hover 의사 클래스와 유사성이 있습니다. 또한 pointerleave 이벤트도 참고하십시오.user agent는 포인터가 활성 버튼 상태로 진입하면 MUST 이름이 pointerdown인 포인터 이벤트를 발생시켜야
합니다. 마우스의 경우, 버튼이 하나 이상 눌린 상태로 전환될 때입니다. 터치의 경우, 디지타이저와 물리적 접촉이 이루어질 때입니다. 펜의 경우, 버튼이 눌리지
않은 상태에서 디지타이저에 물리적 접촉을 하거나, 호버 중에 버튼이 눌리지 않은 상태에서 하나 이상 눌린 상태로 전환될 때입니다.
pointerdown 및 pointerup이 mousedown 및
mouseup의 모든 상황과 동일하게 발생하지 않음을 의미합니다. 자세한 내용은 조합 버튼을
참조하십시오.
호버를 지원하지 않는 입력 장치의 경우, user
agent는 MUST 이름이 pointerover인 포인터 이벤트를, 이어서 pointerenter 이벤트를 발생시킨 다음 pointerdown 이벤트를 디스패치해야 합니다.
pointerdown 이벤트를 취소할 수
있습니다(isPrimary 속성이 true인 경우). 이는 해당 포인터에
PREVENT MOUSE EVENT 플래그를 설정합니다. 다만, 이로 인해 mouseover,
mouseenter, mouseout, mouseleave 이벤트의 발생이 방지되지는 않습니다.
user agent는 포인터가
pointerdown 또는 pointerup 이벤트를 발생시키지 않는 속성들 중 어느 하나라도 변경될 때, 이름이
pointermove인 포인터 이벤트를 MUST 발생시켜야 합니다. 여기에는 좌표, 압력, 접선 압력, 기울기, 회전, 접촉 지오메트리(width 및
height), 또는 조합 버튼에 대한 모든 변경이 포함됩니다.
사용자 에이전트는 성능상의 이유로(예: 성능 최적화) pointermove 이벤트의 디스패치를 MAY 지연시킬 수 있습니다.
이러한 단일 디스패치된 pointermove 이벤트에 대해, 병합된(coalesced) 이벤트 정보는 getCoalescedEvents 메서드를 통해
노출됩니다.
이러한 이벤트의 최종 좌표는 이벤트의 대상을 찾는 데 사용해야 합니다.
user agent는 보안 컨텍스트 내에서만,
포인터가 pointerdown 또는 pointerup 이벤트를 발생시키지 않는 속성 중 일부를 변경할 때, MUST 이름이 pointerrawupdate인 포인터 이벤트를 발생시켜야 합니다.
해당 속성 목록은 pointermove 이벤트를 참조하십시오.
pointermove와 달리, 사용자 에이전트는 pointerrawupdate 이벤트를 가능한 한 빨리, 그리고
JavaScript가 처리할 수 있을 만큼 자주 디스패치하는 것이 SHOULD 입니다.
pointerrawupdate 이벤트의 target은
pointermove 이벤트의 것과 다를 수 있습니다. 이는 pointermove 이벤트가 지연되거나 병합될 수 있고,
target을 찾는 데 사용되는 이벤트의 최종 위치가 병합된 이벤트들의 위치와 다를 수 있기 때문입니다.
이와 동일한 pointerId를 가진 다른 pointerrawupdate가 이미 존재하고 아직 이벤트 루프에서 디스패치되지
않았다면, user agent는 새 pointerrawupdate를 별도의 태스크를 만들지 않고 해당
이벤트와 MAY 병합(coalesce)할 수 있습니다.
이로 인해 pointerrawupdate가 병합된 이벤트를 갖게 될 수 있으며,
이벤트가 이벤트 루프에서 처리되는 즉시,
하나의 pointerrawupdate 이벤트의 병합된 이벤트로 모두 전달됩니다.
자세한 내용은 getCoalescedEvents를 참조하십시오.
pointerrawupdate와 pointermove의 순서와 관련해,
플랫폼으로부터의 업데이트가 pointerrawupdate 및 pointermove 이벤트를 모두 유발하는 경우,
user agent는 대응되는 pointermove보다 먼저 pointerrawupdate 이벤트를 MUST 디스패치해야 합니다.
target을 제외하면, 마지막 pointermove 이벤트 이후 디스패치된 모든 pointerrawupdate 이벤트들의 병합된 이벤트 목록을
연결(concatenate)한 결과는, 다음 pointermove 이벤트의 병합된 이벤트와(다른 이벤트 속성 측면에서)
동일합니다.
pointerrawupdate의 속성은 pointermove와 대부분 동일하나, pointerrawupdate의 경우
cancelable 속성은 MUST false여야 합니다.
사용자 에이전트는 호환성 마우스 이벤트를 pointerrawupdate에 대해 발생시키지 않는 것이 SHOULD 입니다.
pointerrawupdate
이벤트에 대한 리스너를 추가하면 웹 페이지 성능에 부정적인 영향을 줄 수 있습니다.
대부분의 사용 사례에서는 다른 포인터 이벤트 유형들로 충분합니다.
pointerrawupdate 리스너는 JavaScript가 매우
높은 빈도의 이벤트를 필요로 하고, 그만큼 빠르게 처리할 수 있을 때에만 추가해야 합니다.
이러한 경우에는 다른 유형의 포인터 이벤트를 수신할 필요가 없을 가능성이 높습니다.
user agent는 포인터가 활성 버튼 상태에서 벗어날 때, 이름이 pointerup인 포인터 이벤트를 MUST
발생시켜야 합니다. 마우스의 경우, 하나 이상 눌린 상태에서 아무 버튼도 눌리지 않은 상태로 전환될 때입니다. 터치의 경우, 디지타이저로부터 물리적 접촉이 제거될
때입니다. 펜의 경우, 버튼이 눌리지 않은 상태에서 디지타이저와의 물리적 접촉이 제거되거나, 호버 중 하나 이상 눌린 상태에서 아무 버튼도 눌리지 않은 상태로 전환될 때입니다.
호버를 지원하지 않는 입력 장치의 경우, user
agent는 MUST 이름이 pointerout인 포인터 이벤트를, 이어서 pointerleave 이벤트를 발생시켜야 하며, 이는 pointerup 이벤트 디스패치 이후에 이루어집니다.
모든 pointerup 이벤트의 pressure 값은
0입니다.
user agent는 포인터가 현재 캡처된 상태라면, 포인터 캡처를 암시적으로 해제해야 MUST 합니다.
pointerdown 및 pointerup이 mousedown 및
mouseup의 모든 상황과 동일하게 발생하지 않음을 의미합니다. 자세한 내용은 조합 버튼을
참조하십시오.
user agent는 포인터 이벤트 스트림을 억제해야 하는 시나리오를 감지하면, 이름이 pointercancel인 포인터 이벤트를 MUST 발생시켜야 합니다.
pointercancel 이벤트의 다음 속성 값은 동일한 pointerId를 가진 마지막으로 디스패치된 포인터 이벤트의
값과 MUST 일치해야 합니다: width,
height, pressure, tangentialPressure, tiltX,
tiltY, twist, altitudeAngle, azimuthAngle,
pointerType, isPrimary, 그리고 [UIEVENTS]로부터 상속된
좌표들. 또한 pointercancel 이벤트의
coalescedEvents 및
predictedEvents 목록은 비어 있어야 MUST 하며, 이벤트의 cancelable 속성은 MUST false여야 합니다.
user agent는 다음 중 하나가
발생하면 MUST 이름이 pointerout인 포인터 이벤트를 발생시켜야 합니다:
pointerup 이벤트가 호버를 지원하지 않는 장치에 대해 발생한 이후(자세한 내용은
pointerup 참조).
user agent는 다음 중 하나가
발생하면 MUST 이름이 pointerleave인 포인터 이벤트를 발생시켜야 합니다:
pointerup 이벤트가 호버를 지원하지 않는 장치에 대해 발생한 이후(자세한 내용은
pointerup 참조).
pointerout과 유사하지만 두 가지 차이가 있습니다: pointerleave는 버블링되지 않으며, 디스패치 시 하위 요소의 히트
테스트 경계까지 고려합니다.mouseleave 이벤트 및 [CSS21]에
설명된 CSS :hover 의사 클래스와 유사성이 있습니다. 또한 pointerenter 이벤트도 참고하십시오.user agent는 요소가 포인터 캡처를
받으면 MUST 이름이 gotpointercapture인 포인터 이벤트를 발생시켜야 합니다. 이
이벤트는 포인터 캡처를 수신하는 요소에서 발생합니다. 해당 포인터에 대한 이후 이벤트는 이 요소에서 발생합니다. 자세한 내용은 포인터 캡처 설정 및 대기 중인 포인터 캡처 처리 섹션을 참조하십시오.
user agent는 포인터에 대한 포인터
캡처가 해제된 후, 이름이 이름이 lostpointercapture인 포인터 이벤트를 MUST 발생시켜야 합니다. 이 이벤트는 캡처가 제거된 요소에서 발생합니다. 캡처가 해제된 후 해당 포인터에 대한 모든 후속 이벤트는,
click,
auxclick, contextmenu 이벤트를 제외하고, 이벤트 대상을 결정하기 위해 일반적인 히트 테스트
메커니즘(이 명세의 범위를 벗어남)을 따릅니다. 자세한 내용은 포인터 캡처 해제, 포인터 캡처의 암시적 해제, 대기 중인 포인터 캡처 처리 섹션을 참조하십시오.
다음 섹션은 기존 Element 인터페이스에 대한 확장을 설명하며,
포인터 캡처의 설정 및 해제를 용이하게 합니다.
WebIDLpartial interface Element {
undefined setPointerCapture (long pointerId);
undefined releasePointerCapture (long pointerId);
boolean hasPointerCapture (long pointerId);
};
setPointerCapture()인수 포인터 캡처 설정은 이 메서드가 호출된 요소에,
인수로 전달된 pointerId로 식별되는 포인터에 대해 적용됩니다.
이후 해당 포인터의 이벤트에서는, 포인터가 항상 캡처 대상 위에 있는 것처럼 일반적인 히트 테스트 결과 대신
캡처 대상이 사용되며, 캡처가 해제될 때까지 이 요소를 MUST 항상 대상으로 해야 합니다.
이 메서드가 효과를 가지려면 포인터가 활성 버튼 상태에 MUST 있어야 하며,
그렇지 않으면 조용히 실패합니다. 제공된 메서드 인수가 어떤 활성 포인터와도 일치하지 않으면,
throw a "NotFoundError" DOMException.
releasePointerCapture()이 메서드가 호출된 요소에서, 인수로 전달된 pointerId로
식별되는 포인터에 대한 포인터 캡처 해제를 수행합니다.
이후 해당 포인터의 이벤트는 이벤트 대상을 결정하기 위해 일반적인 히트 테스트 메커니즘(이 명세의 범위를 벗어남)을 따릅니다.
제공된 메서드 인수가 어떤 활성 포인터와도 일치하지 않으면,
throw a "NotFoundError" DOMException.
hasPointerCapture이 메서드가 호출된 요소가, 인수로 전달된 pointerId로
식별되는 포인터에 대해
포인터 캡처를
보유하고 있는지 여부를 나타냅니다. 구체적으로, 대기 중 포인터 캡처 대상 오버라이드가
pointerId에 대해
이 메서드가 호출된 요소로 설정되어 있으면 true를 반환하고, 그렇지 않으면 false를 반환합니다.
gotpointercapture 이벤트를
수신하지 않았더라도, setPointerCapture() 호출
직후에 true를 반환합니다. 그 결과, 암시적 포인터 캡처를
pointerdown 이벤트 리스너 내부에서
감지하는 데 유용할 수 있습니다.
다음 섹션은 기존 GlobalEventHandlers
믹스인에 대한 확장을 설명하며, 이벤트 핸들러 등록을 용이하게 합니다.
WebIDLpartial interface mixin GlobalEventHandlers {
attribute EventHandler onpointerover;
attribute EventHandler onpointerenter;
attribute EventHandler onpointerdown;
attribute EventHandler onpointermove;
[SecureContext] attribute EventHandler onpointerrawupdate;
attribute EventHandler onpointerup;
attribute EventHandler onpointercancel;
attribute EventHandler onpointerout;
attribute EventHandler onpointerleave;
attribute EventHandler ongotpointercapture;
attribute EventHandler onlostpointercapture;
};
onpointeroverpointerover 이벤트 유형에 해당합니다.
onpointerenterpointerenter 이벤트 유형에 해당합니다.
onpointerdownpointerdown 이벤트 유형에 해당합니다.
onpointermovepointermove 이벤트 유형에 해당합니다.
onpointerrawupdatepointerrawupdate 이벤트 유형에 해당합니다.
onpointeruppointerup 이벤트 유형에 해당합니다.
onpointercancelpointercancel 이벤트 유형에 해당합니다.
onpointeroutpointerout 이벤트 유형에 해당합니다.
onpointerleavepointerleave 이벤트 유형에 해당합니다.
ongotpointercapturegotpointercapture
이벤트 유형에 해당합니다.
onlostpointercapturelostpointercapture
이벤트 유형에 해당합니다.
속성과 기본 동작에서 언급했듯이, 뷰포트 조작(패닝과 줌)은 포인터 이벤트를 취소하는
것으로는 억제할 수 없습니다. 대신, 작성자는 어떤 동작을 허용할지, 어떤 동작을 억제할지를 touch-action CSS 속성을 사용해 선언적으로 정의해야 합니다.
touch-action CSS 속성은 오직 터치 입력만을 가리키는 것처럼 보이지만, 실제로는 패닝과 줌을 위한 직접 조작을 허용하는 모든 형태의 포인터 입력에 적용됩니다.| 이름: | touch-action |
|---|---|
| 값: | auto | none | [ pan-x || pan-y ] |
manipulation
|
| 초기값: | auto |
| 적용 대상: | 다음 제외한 모든 요소: 대체되지 않은 인라인 요소, 테이블 행, 행 그룹, 테이블 열, 열 그룹 |
| 상속: | no |
| 백분율: | N/A |
| 미디어: | visual |
| 계산값: | 지정된 값과 동일 |
| 정규 순서: | 문법에 따름 |
| 애니메이션 유형: | 애니메이션 불가 |
touch-action CSS 속성은 (속성 이름과 달리 터치에만 국한되지 않는) 직접 조작 상호작용이 사용자
에이전트의 패닝 및 줌 동작을 트리거할 수 있는지를 결정합니다(MAY). touch-action 값 섹션을 참조하십시오.
패닝 또는 줌을 시작하기 직전에, 다음 조건이 모두 참이면 user agent는 MUST 포인터 이벤트 스트림을 억제해야 합니다:
pointerdown 이벤트가 전송된 경우, 그리고pointerdown에 이어서) 해당 포인터에 대해 아직 pointerup 또는 pointercancel 이벤트가 전송되지 않은 경우.touch-action은 포함된 탐색 컨텍스트로 적용/캐스케이드되지 않습니다. 예를 들어,
<iframe>에 touch-action을 적용하더라도, 해당 <iframe> 내부의
패닝 및 줌을 위한 직접 조작 동작에는 아무런 영향이 없습니다.
사용자가 터치스크린에서의 터치나 스타일러스와 같은 직접 조작 포인터를 사용하여 요소와 상호작용할 때, 그 입력의 효과는 다음과 같이
touch-action 속성의 값과 요소 및 그 조상들의 기본 직접 조작 동작에 의해 결정됩니다:
touch-action을 준수(conform)합니다. CSS 변환이 적용된 경우 요소의 좌표 공간은
화면 좌표와 달라질 수 있어 여기서의 적합성에 영향을 줄 수 있습니다. 예를 들어, 화면에 대해 90도 회전된 요소의 X축은 화면 좌표의 Y축과 평행합니다.touch-action 속성을 준수하는 경우 지원됩니다.
document 요소([HTML]에 정의됨) 사이에 있는 각 요소의
touch-action 속성을 준수하는 경우 지원됩니다.
touch-action 값의 변경은 동작이 지속되는 동안 무시됩니다. 예를 들어, pointerdown 핸들러 스크립트의 일환으로 어떤 요소의
touch-action 값을 auto에서 none으로 프로그래밍 방식으로 변경하더라도, 해당 포인터가 활성인
동안 사용자 에이전트는 그 입력에 대한 패닝이나 줌 동작을 중단하거나 억제하지 않습니다.
touch-action 값 pan-*의 경우에도, 제스처 시작 시 사용자 에이전트가 제스처를 직접 처리할지 여부를
결정한 후에는, 같은 제스처의 방향에 대한 이후 변경은 해당 포인터가 활성인 동안 사용자 에이전트에 의해 SHOULD 무시됩니다. 예를
들어, 어떤 요소가 touch-action: pan-y로 설정되어(사용자 에이전트가 수직 패닝만 처리함을 의미) 있고, 터치 제스처가 가로 방향으로 시작된
경우, 사용자가 손가락을 여전히 화면에 댄 채 제스처의 방향을 세로로 변경하더라도 수직 패닝은 발생하지 않아야 합니다.
touch-action 값을 처리하거나 연관시키는 방법은 이 명세의 범위를 벗어납니다.
touch-action 속성은 뷰포트 패닝과 줌과 관련된 직접 조작 동작을 다룹니다. 텍스트 선택/하이라이트, 링크 및 폼 컨트롤 활성화와 같은 사용자 에이전트의
추가 동작은 이 CSS 속성에 의해 영향을 받아서는 MUST NOT 합니다.
auto나 none 값에 대한 동작을 트리거하기 위한 정의는 이 명세의 범위를 벗어납니다.
pan-x 또는
pan-y로 단일 축으로 패닝이 제한된 경우에는, 패닝 도중 축을 변경할 수 없습니다.
touch-action 값은 [COMPAT]에 정의되어 있습니다.방향별 pan 값은 일부 오버스크롤 동작을 커스터마이즈하는 데 유용합니다.
예를 들어, 간단한 풀-투-리프레시 효과를 구현하기 위해 문서의
touch-action을 스크롤 위치가 0일 때는 pan-x pan-down으로,
그 외에는 pan-x pan-y로 설정할 수 있습니다.
이렇게 하면 문서 상단에서 시작되는 위쪽 패닝/스크롤에 대해 포인터 이벤트 핸들러가 동작을 정의할 수 있습니다.
방향별 pan 값은 네이티브로 스크롤되는 요소 내부에서 포인터 이벤트 처리로 사용자 정의 패닝을 구현하는 구성요소(또는 그 반대)를 구성하는 데에도 사용할 수 있습니다.
예를 들어, 이미지 캐러셀은 문서의 수직 패닝을 방해하지 않으면서, 가로 방향 패닝 작업에 대해 포인터 이벤트를 수신하도록 pan-y를 사용할 수
있습니다.
캐러셀이 가장 오른쪽 끝에 도달하면, 그 이후의 스크롤 작업이 가능하다면 뷰포트 내에서 문서를 스크롤할 수 있도록 touch-action을
pan-y pan-right로 변경할 수 있습니다.
진행 중인 패닝/스크롤링 작업의 동작은, 작업이 진행되는 동안 변경할 수 없습니다.
auto에서는 사용자 에이전트가 보통 더블 탭 제스처 처리를 위해 click 전에 300ms의 지연을 추가합니다. 이러한 경우,
touch-action: none 또는 touch-action: manipulation을 명시적으로 설정하면 이 지연이 제거됩니다.
탭 또는 더블 탭 제스처를 판단하는 방법은 이 명세의 범위를 벗어남에 유의하십시오.
<div style="touch-action: none;">
이 요소는 그렇지 않으면 패닝 또는 줌으로 이어지는 모든 직접 조작 상호작용에 대해 포인터 이벤트를 수신합니다.
</div>
<div style="touch-action: pan-x;">
이 요소는 수평 방향으로 패닝하지 않을 때 포인터 이벤트를 수신합니다.
</div>
<div style="overflow: auto;">
<div style="touch-action: none;">
이 요소는 그렇지 않으면 패닝 또는 줌으로 이어지는 모든 직접 조작 상호작용에 대해 포인터 이벤트를 수신합니다.
</div>
<div>
이 요소에 대한 직접 조작 상호작용은 상위 요소를 조작하는 데 소비될 수 있습니다(MAY).
</div>
</div>
<div style="overflow: auto;">
<div style="touch-action: pan-y;">
<div style="touch-action: pan-x;">
이 요소는 모든 직접 조작 상호작용에 대해 포인터 이벤트를 수신합니다. 그 이유는
이 요소는 가로 패닝만 허용하지만, 중간 조상
(스크롤 가능한 요소와 이 요소 사이)이 세로 패닝만 허용하기 때문입니다.
따라서 사용자 에이전트는 패닝/줌을 위한 어떠한 직접 조작 동작도
처리하지 않습니다.
</div>
</div>
</div>
이 섹션은 비규범적입니다.
포인터 캡처를 사용하면 특정 포인터(모든 호환성 마우스 이벤트 포함)의 이벤트를, 해당 포인터 위치의 일반적인 히트 테스트
결과가 아닌 특정 요소로 다시 타게팅할 수 있습니다. 이는 사용자 정의 슬라이더 컨트롤(예: [HTML]의
<input type="range"> 컨트롤과 유사)과 같은 시나리오에서 유용합니다. 슬라이더 엄지 요소에 포인터 캡처를 설정하면, 엄지에서 포인터가
벗어나더라도 사용자가 컨트롤을 앞뒤로 슬라이드할 수 있습니다.
pointerdown 이후, 포인터 캡처를 사용하면 포인터가 엄지에서
벗어나더라도 사용자가 엄지를 슬라이드할 수 있습니다.포인터 캡처는 Element 타입의 element에 대해
element.setPointerCapture(pointerId) 메서드를 호출하여 설정합니다.
이 메서드가 호출되면, user agent는 다음
단계를 MUST 실행해야 합니다:
pointerId가 어떤 활성 포인터와도 일치하지 않으면, throw a "NotFoundError" DOMException.pointerId로 지정된
활성 포인터로 둡니다.
InvalidStateError" DOMException.pointerLockElement)가
있다면,
throw an "InvalidStateError" DOMException.
pointerId에 대해, 대기 중 포인터 캡처 대상 오버라이드를 이 메서드가 호출된 Element로 설정합니다.
pointerdown 리스너에서 해제하려는 실패한 시도에도 해당됩니다.포인터 캡처는 element.releasePointerCapture(pointerId) 메서드를 호출하여 요소에서 명시적으로 해제합니다. 이 메서드가 호출되면, user agent는 다음 단계를 MUST 실행해야 합니다:
pointerId가 어떤 활성 포인터와도 일치하지 않고, 이 단계가 포인터 캡처의 암시적 해제의 결과로 호출된 것이 아니라면,
throw a "NotFoundError" DOMException.
pointerId에 대해 해당 Element의 hasPointerCapture가 false이면, 이 단계를
종료합니다.
pointerId에 대해, 설정되어 있다면 대기 중 포인터 캡처 대상 오버라이드를 해제합니다.패닝과 줌을 위한 직접 조작 상호작용을 구현하는 입력(예: 터치스크린에서의 터치나 스타일러스)은, 대상 요소의 어떤 pointerdown 리스너가 호출되기 직전에 setPointerCapture가 호출된 것처럼 정확히 동일하게
동작해야 SHOULD 합니다. (예를 들어 pointerdown 리스너에서) hasPointerCapture API를 사용하여 이것이 발생했는지
확인할 수 있습니다. 다음 포인터 이벤트가 발생하기 전에 해당 포인터에 대해 releasePointerCapture가 호출되지 않으면,
캡처가 활성화되었음을 나타내는 gotpointercapture 이벤트가(정상적으로) 대상에 디스패치됩니다.
pointerup 또는 pointercancel 이벤트를 발생시킨 직후,
user agent는 해당 방금 디스패치된 pointerup 또는 pointercancel 이벤트의 pointerId에 대한 대기 중 포인터 캡처 대상 오버라이드를 MUST 해제하고,
이어서 필요하다면 대기 중 포인터 캡처 처리 단계를 실행하여 lostpointercapture를 발생시켜야 합니다.
대기 중 포인터 캡처 처리 단계를 실행한 후,
포인터가 호버를 지원한다면, user agent는
캡처 없이 포인터의 현재 위치를 반영하는 데 필요한 해당 경계 이벤트도 MUST 전송해야 합니다.
포인터 캡처 대상 오버라이드가 더 이상 [DOM]에서 connected가 아닌 경우, 포인터 캡처 대상 오버라이드는 문서로 설정되어야 SHOULD 합니다.
대기 중 포인터 캡처 대상 오버라이드가 더 이상 [DOM]에서 connected가 아닌 경우, 대기 중 포인터 캡처 대상 오버라이드 노드는 해제되어야 SHOULD 합니다.
lostpointercapture
이벤트가
캡처 노드가 제거된 이후 다음 번 대기 중 포인터 캡처 처리 중에
문서에서 발생하게 됩니다.
어떤 요소에 포인터 락([PointerLock])이 성공적으로 적용되면, user agent는 어떤 요소가 캡처되었거나 캡처 대기 중인 경우가 있다면 releasePointerCapture 메서드가 호출된 것처럼
단계를 MUST 실행해야 합니다.
성능상의 이유로, 사용자 에이전트는 포인터의 pointermove
이벤트를 포인터의 측정 가능한 속성
(좌표, 압력, 접선 압력, 기울기, 회전, 접촉 지오메트리 등)이 업데이트될 때마다 보내지 않기로 선택할 수 있습니다. 대신 여러 변경 사항을
하나의 pointermove 또는 pointerrawupdate 이벤트로 병합(coalesce, 결합/통합)할 수
있습니다. 이러한 접근은 user agent가
수행해야 하는 이벤트 처리량을 줄이는 데 MUST
도움이 되지만,
포인터 위치를 추적할 때의 세분성 및 충실도가 자연스럽게 낮아지며,
특히 빠르고 큰 움직임에서 두드러집니다. getCoalescedEvents 메서드를 사용하면
애플리케이션이 병합되지 않은(raw) 위치 변화를 직접 액세스할 수 있습니다. 이를 통해 포인터 이동 데이터를 보다 정밀하게 처리할 수 있습니다. 예를 들어
드로잉 애플리케이션의 경우, 병합되지 않은 이벤트를 사용해 포인터의 실제 움직임에 더욱 근접한
매끄러운 곡선을 그릴 수 있습니다.
pointermove 이벤트의 병합된
좌표(회색 점)만 사용할 경우,
곡선이 눈에 띄게 각지고 들쭉날쭉해집니다. 반면 getCoalescedEvents()가 제공하는 더 세분화된 점들(빨간 원)로 같은 선을 그리면
포인터 움직임을 더 부드럽게 근사할 수 있습니다.PointerEvent에는 병합된 이벤트 목록이 연관되어 있으며
(0개 이상의 PointerEvent로 이루어진 목록입니다), 신뢰할 수 있는(trusted) pointermove 및
pointerrawupdate 이벤트의 경우 이 목록은
해당 이벤트로 병합된 모든 PointerEvent들의 시퀀스입니다. 신뢰할 수 있는 "부모" pointermove 및
pointerrawupdate 이벤트는 이러한 병합된 이벤트들의
누적치를 나타내지만
(예: 디스플레이 새로고침 속도에 맞추기 위한 정렬 등) 추가 처리를 포함할 수 있습니다.
그 결과, 이들 이벤트의 병합된 이벤트 목록에는 항상 최소 한 개 이상의 이벤트가 포함됩니다.
다른 모든 신뢰할 수 있는 이벤트 유형의 경우 이 목록은 비어 있습니다. 신뢰할 수 없는(untrusted) 이벤트는
생성자에 전달된 값으로 병합된 이벤트 목록이 초기화됩니다.
isTrusted 비트를
false로 설정하지만,
병합된 이벤트 목록 내부 이벤트들의 동일한 비트는
원래의 true 상태에서 변경되지 않습니다.
신뢰할 수 있는 이벤트의 병합된 이벤트 목록에 있는 이벤트들은 다음을 가집니다.
timeStamp 값
[DOM] — 모든 병합된 이벤트의
timeStamp는
getPredictedEvents 메서드가 호출된
디스패치된 포인터 이벤트의
timeStamp보다 작거나 같습니다.
병합된 이벤트 목록은 timeStamp 기준으로
시간 순(MUST)으로 정렬되며, 첫 번째 이벤트가 가장 작은
timeStamp를 가집니다.
pointerId,
pointerType,
및 isPrimary 값을 가집니다.
<style>
/* 사용자 에이전트의 기본 직접 조작 동작(예: 패닝 또는 줌)을 비활성화하여
캔버스 요소의 모든 이벤트가 애플리케이션으로 전달되도록 합니다. */
canvas { touch-action: none; }
</style>
<canvas id="drawSurface" width="500px" height="500px" style="border:1px solid black;"></canvas>
<script>
const canvas = document.getElementById("drawSurface"),
context = canvas.getContext("2d");
canvas.addEventListener("pointermove", (e)=> {
if (e.getCoalescedEvents) {
for (let coalesced_event of e.getCoalescedEvents()) {
paint(coalesced_event); // 모든 원시/비병합 지점을 그리기
}
} else {
paint(e); // 최종 병합 지점 그리기
}
});
function paint(event) {
if (event.buttons>0) {
context.fillRect(event.clientX, event.clientY, 5, 5);
}
}
</script>
디스패치되는 모든 이벤트의 순서는 원래 이벤트들의 실제 순서와 MUST 일치해야 합니다.
예를 들어 pointerdown 이벤트가 병합된 pointermove 이벤트들의 디스패치를 유발하는 경우, user agent는 먼저 해당 pointerId의 모든 병합된 이벤트를 담은 하나의 pointermove
이벤트를 디스패치한 뒤
pointerdown 이벤트를 디스패치해야 합니다.
다음은 증가하는 timeStamp 값을 가진 실제
이벤트들과
사용자 에이전트가 디스패치한 이벤트들의 예시입니다.
| 실제 이벤트 | 디스패치된 이벤트 |
|---|---|
포인터 (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개 포함 |
일부 사용자 에이전트에는 일련의 확정된 포인터 이동 이후에,
현재 제스처의 선행 이벤트 및 움직임의 속도/궤적을 바탕으로
향후 포인터 이동 위치가 어떻게 될지 예측할 수 있는 내장 알고리즘이 있습니다.
애플리케이션은 getPredictedEvents 메서드를 사용해 이
정보를 활용하여
지연 인식(latency)을 줄이기 위해 예측 위치로 미리 "그려 두고",
실제 포인트가 수신되면 이러한 예측 포인트들을 폐기할 수 있습니다.
pointermove 이벤트에서 얻은 병합된 좌표를 사용하며,
사용자 에이전트가 예측한 미래 지점들(회색 원)을 보여줍니다.PointerEvent에는 예측된 이벤트 목록이 연관되어 있으며
(0개 이상의 PointerEvent로 이루어진 목록),
신뢰할 수 있는 pointermove 이벤트의 경우
사용자 에이전트가 해당 이벤트 이후에 뒤따를 것으로 예측하는
PointerEvent들의 시퀀스입니다.
다른 모든 신뢰할 수 있는 이벤트 유형의 경우 이 목록은 비어 있습니다.
신뢰할 수 없는(untrusted) 이벤트는 생성자에 전달된 값으로
예측된 이벤트 목록이 초기화됩니다.
pointerrawupdate 이벤트는 비어 있지 않은 병합된 이벤트
목록을 가질 수 있지만,
성능상의 이유로 보통 이들의 예측된 이벤트 목록은 비어 있습니다.
isTrusted 비트를
false로 설정하지만,
예측된 이벤트 목록 내부 이벤트들의 동일한 비트는
원래의 true 상태에서 변경되지 않습니다.
목록의 이벤트 개수와 현재 타임스탬프로부터의 거리(시간적 간격)는 사용자 에이전트 및 사용 중인 예측 알고리즘에 의해 결정됩니다.
신뢰할 수 있는 이벤트의 예측된 이벤트 목록에 있는 이벤트들은 다음을 가집니다.
timeStamp 값
[DOM] — 모든 예측된 이벤트의
timeStamp는
getPredictedEvents 메서드가 호출된
디스패치된 포인터 이벤트의
timeStamp보다 크거나 같습니다.
예측된 이벤트 목록은 timeStamp 기준으로
시간 순(MUST)으로 정렬되며, 첫 번째 이벤트가 가장 작은
timeStamp를 가집니다.
pointerId,
pointerType,
및 isPrimary 값을 가집니다.
작성자는 다음 포인터 이벤트가 디스패치될 때까지의 기간에만 예측된 이벤트를 유효한 예측으로 간주해야 합니다. 사용자 에이전트가 얼마나 먼 미래까지 이벤트를 예측하는지에 따라, 일반 포인터 이벤트가 하나 이상의 예측된 이벤트의 타임스탬프보다 먼저 디스패치될 수도 있습니다.
let predicted_points = [];
window.addEventListener("pointermove", function(event) {
// 이전에 그려진 예측 포인트를 지웁니다.
for (let e of predicted_points.reverse()) {
clearPoint(e.pageX, e.pageY);
}
// 마지막으로 받은 이벤트 이후 실제로 발생한 움직임을 그립니다.
for (let e of event.getCoalescedEvents()) {
drawPoint(e.pageX, e.pageY);
}
// 지연 인식을 줄이기 위해 현재 예측 포인트를 그립니다.
predicted_points = event.getPredictedEvents();
for (let e of predicted_points) {
drawPoint(e.pageX, e.pageY);
}
});
신뢰할 수 있는 PointerEvent가 생성될 때, 사용자 에이전트는
병합된 이벤트 목록 및 예측된 이벤트 목록의 각
이벤트에 대해
다음 단계를 SHOULD 실행해야 합니다:
pointerId,
pointerType,
isPrimary 및 isTrusted를
"부모" 포인터 이벤트의 해당 속성들과 일치하도록 설정합니다.
cancelable 및 bubbles를 false로 설정합니다
(이 이벤트들은 단독으로는 디스패치되지 않기 때문입니다).PointerEvent 값으로 초기화합니다.
신뢰할 수 있는 PointerEvent의 target이 변경될 때, 사용자 에이전트는
병합된 이벤트 목록 및 예측된 이벤트 목록의 각
이벤트에 대해
다음을 SHOULD 수행해야 합니다:
오늘날 존재하는 웹 콘텐츠의 절대다수는 마우스 이벤트만을 대상으로 작성되어 있습니다. 다음은 user agent가 일반 포인터 입력을 이 콘텐츠와의 호환성을 위해 마우스 이벤트에 매핑하는 방법에 대한 알고리즘을 설명합니다(MAY).
마우스 이벤트와의 호환성 매핑은 이 명세의 OPTIONAL 기능입니다. 사용자 에이전트는 기존 레거시 콘텐츠와의 최상의 호환성을 위해 이 기능을 지원하는 것이 권장됩니다.
개략적으로, 호환성 마우스 이벤트는 해당하는 포인터 이벤트와 "상호 끼어들도록(interleaved)" 의도되었습니다. 그러나 이 구체적인 순서는 필수 사항이 아니며, 호환성 마우스 이벤트를 구현하는 사용자 에이전트는 상대적 순서를 유지하는 한 마우스 이벤트의 디스패치를 지연하거나 그룹화하기로 MAY 선택할 수 있습니다.
특히 터치스크린 입력의 경우, 사용자 에이전트는 제스처 인식을 위해 추가적인 휴리스틱을 적용할 수 있습니다(작성자가 을 통해 명시적으로 억제하지 않는 한).
touch-actionpointerdown 이벤트와 pointerup 이벤트 사이의 이벤트 시퀀스 동안, 제스처 인식은 제스처를 감지하거나
무시하기 위해 pointerup 이벤트까지 기다려야 할 수도 있습니다. 그 결과, 사용자 에이전트가
상호작용이 특정 제스처를 의도하지 않았다고 판단하면, 전체 시퀀스에 대한 호환성 마우스 이벤트가 마지막 pointerup 이벤트 이후에 한꺼번에 디스패치될 수 있습니다. 이러한 사용자
에이전트의 제스처 인식 세부 사항은 이 명세에서 정의되지 않으며, 구현마다 다를 수 있습니다.
호환성 마우스 이벤트 지원 여부와 관계없이, 사용자 에이전트는 click, auxclick 및 contextmenu 이벤트를
항상 MUST 지원해야 합니다. 이 이벤트들은 PointerEvent 타입이며, 따라서 호환성 마우스 이벤트가 아닙니다. 포인터 이벤트 중
preventDefault를 호출하는 것은 click, auxclick, 또는 contextmenu가
발행되는지 여부에 MUST NOT 영향을 미치지 않습니다.
일부 고수준 이벤트(contextmenu, focus, blur 등)의 포인터 이벤트와의 상대적
순서는 정의되어 있지 않으며 사용자 에이전트마다 다릅니다. 예를 들어, 일부 사용자 에이전트에서는 contextmenu가 종종 pointerup을 따른 후에 발생하지만, 다른 사용자 에이전트에서는 pointerup 또는 pointercancel에 앞서 발생하는 경우가 많으며, 어떤 상황에서는(예:
키보드 상호작용의 결과로) 대응되는 포인터 이벤트 없이도 발생할 수 있습니다.
또한, 사용자 에이전트는 click, auxclick, 또는 contextmenu 이벤트를 발행할지 여부를 자체
휴리스틱으로 판단할 수 있습니다. 동일한 타입의 다른(비-기본) 포인터나 다른 타입의 다른 기본 포인터가 있는 경우, 일부 사용자 에이전트는 이러한 이벤트를 발행하지 않기로 선택할
수 있습니다. 사용자 에이전트는 특정 동작이 "깨끗한" 탭, 클릭 또는 길게 누르기가 아니라고 판단할 수 있으며(예: 터치스크린에서 손가락이 화면에 닿아 있는 동안 움직임이 너무
큰 경우), click, auxclick, 또는 contextmenu 이벤트를 발행하지 않기로 결정할 수
있습니다. 이러한 사용자 에이전트 동작의 측면은 이 명세에서 정의되지 않으며 구현마다 다를 수 있습니다.
별도의 언급이 없는 한, 매핑된 마우스 이벤트의 대상(target)은 해당 포인터 이벤트의 대상과 동일해야 SHOULD 하며, 단 대상이 더 이상
자신의 ownerDocument 트리에 참여하지 않는 경우에는, 마우스 이벤트는 원래 대상이 트리에서 제거되던 시점에 여전히 자신의
ownerDocument 트리에 참여하는 가장 가까운 상위 조상 노드에서 발행되어야 합니다. 이는 마우스 이벤트를 위해 (새 대상 노드에 기반한) 새로운 이벤트 경로가
구축됨을 의미합니다.
작성자는 pointerdown 이벤트를 취소(cancelling)하여 특정 호환성 마우스 이벤트의 생성을
방지할 수 있습니다.
마우스 이벤트는 포인터가 눌린 상태일 때만 방지할 수 있습니다. 호버 중인 포인터(예: 버튼이 눌리지 않은 마우스)는 마우스 이벤트가 방지될 수 없습니다.
mouseover, mouseout, mouseenter, mouseleave
이벤트는 (포인터가 눌린 상태여도) 결코 방지되지 않습니다.
호환성 마우스 이벤트는 포인터 이벤트의 EventListener가
passive로 설정된
경우에는 방지할 수 없습니다
[DOM].
기본 포인터만이 호환성 마우스 이벤트를 생성할 수 있지만, 여러 기본 포인터가 동시에 활성화될 수 있으며 각 포인터가 자신의 호환성 마우스 이벤트를 생성할 수 있습니다.
MouseEvents에 의존하는 스크립트와의 호환성을 위해, 마우스 전이(transition) 이벤트(mouseover, mouseout,
mouseenter, mouseleave)는 단일 레거시 마우스 입력의 움직임을 시뮬레이션해야 SHOULD 합니다. 이는 [UIEVENTS]에 따라 모든 이벤트 대상의 진입/이탈 상태가 유효함을 의미합니다.
사용자 에이전트는 문서에서 레거시 마우스 포인터의 실효 위치를 다음과 같이 유지함으로써 이를 보장해야 SHOULD
합니다.
pointerdown, pointerup
또는 pointermove 이벤트, 혹은 window에서의 pointerleave 이벤트를 발행하기 직전에,
사용자 에이전트는 다음 단계를 SHOULD 실행해야 합니다:
pointerdown, pointerup 또는 pointermove 이벤트의 대상을 T로 둡니다. pointerleave 이벤트의 경우 T를 설정하지 않습니다.
mouseover, mouseout, mouseenter,
mouseleave 이벤트를 디스패치합니다. 현재 레거시 마우스 포인터의 실효 위치 또는
T가 설정되지 않은 값인 경우, 이를 창 밖(out-of-window)의 마우스 위치로 간주합니다.
레거시 마우스 포인터의 실효 위치 모델은 포인터 전이
이벤트(pointerover, pointerout,
pointerenter, pointerleave)를 해당 레거시 마우스 전이 이벤트(mouseover,
mouseout, mouseenter, mouseleave)에 항상 직접 매핑할 수는 없다는 사실을
반영합니다. 다음 애니메이션은 사용자 에이전트가 두 개의 기본 포인터를 단일 레거시 마우스 입력으로 조정하기 위해 포인터 전이 이벤트보다 더 많은 레거시 마우스 전이
이벤트를 디스패치해야 하는 사례를 보여줍니다.
이 애니메이션에서, 마우스 클릭과 터치 탭 사이의 시간 구간에 주목하십시오. 버튼 1은
이 기간 동안 "실제" 마우스 포인터가 버튼 사각형을 벗어나지 않았기 때문에
pointerout 이벤트를 받지 않습니다. 하지만 터치 탭으로 인해 레거시 마우스 포인터의 실효 위치가 버튼 2로 이동할
때 버튼 1은 mouseout 이벤트를 받습니다. 마찬가지로, 터치 탭과 마우스가 버튼 1을 떠나기 직전 사이의 시간 구간 동안 동일한 이유로 버튼
1은 pointerover 이벤트를 받지 않지만, 레거시 마우스 포인터의 실효 위치가 버튼 1 내부로
다시 이동할 때 mouseover 이벤트를 받습니다.
사용자 에이전트가 호버를 지원하는 장치에 대해 포인터 이벤트를 디스패치해야 할 때마다, 다음 단계를 SHOULD 실행해야 합니다.
isPrimary 속성이 false라면 포인터 이벤트를 디스패치하고 이 단계를 종료합니다.pointerdown, pointerup, pointermove 이벤트이거나, window에서의 pointerleave 이벤트인 경우,
레거시 마우스 포인터의 실효
위치 추적에 설명된 대로 호환성 마우스 전이 이벤트를 디스패치합니다.
pointerdown이고 그 이벤트가 취소되었다면, 해당 pointerType에 대해
PREVENT MOUSE EVENT 플래그를 설정합니다.
PREVENT MOUSE EVENT 플래그가 이 pointerType에 대해 설정되어 있지 않고, 디스패치된 포인터 이벤트가 다음 중
하나라면:
pointerdown인 경우, mousedown
이벤트를 발행합니다.
pointermove인 경우, mousemove
이벤트를 발행합니다.
pointerup인 경우, mouseup 이벤트를
발행합니다.
pointercancel인 경우,
window에서 mouseup 이벤트를 발행합니다.
pointerup 또는 pointercancel이었다면,
이 pointerType에 대한 PREVENT MOUSE EVENT 플래그를 해제합니다.
대부분의 터치스크린과 같은 일부 장치는 활성 상태가 아닐 때 좌표(또는 좌표 집합)를 호버하는 것을 지원하지 않습니다. 마우스 이벤트에 맞춰 작성된 기존 콘텐츠는 마우스가 이벤트를 생성한다고 가정하며, 일반적으로 다음과 같은 특성이 성립합니다:
mousemove 이벤트를 생성할 가능성이 높습니다.
이러한 유형의 입력 장치에 대해서는 사용자 에이전트가 다른 매핑을 제공해야 합니다. 사용자 에이전트가 호버를 지원하지 않는 장치에 대해 포인터 이벤트를 디스패치해야 할 때마다, 다음 단계를 SHOULD 실행해야 합니다:
isPrimary 속성이 false라면 포인터 이벤트를 디스패치하고 이 단계를 종료합니다.pointerover이고 해당 포인터에 대한 pointerdown 이벤트가 아직 디스패치되지 않았다면,
(레거시 마우스 전용 코드와의 호환성을 위해) mousemove 이벤트를 발행합니다.pointerdown, pointerup, pointermove 이벤트이거나, window에서의 pointerleave 이벤트인 경우,
레거시 마우스 포인터의 실효
위치 추적에 설명된 대로 호환성 마우스 전이 이벤트를 디스패치합니다.
pointerdown이고 그 이벤트가 취소되었다면, 해당 pointerType에 대해
PREVENT MOUSE EVENT 플래그를 설정합니다.
PREVENT MOUSE EVENT 플래그가 이 pointerType에 대해 설정되어 있지 않고, 디스패치된 포인터 이벤트가 다음 중
하나라면:
pointerdown인 경우, mousedown
이벤트를 발행합니다.
pointermove인 경우, mousemove
이벤트를 발행합니다.
pointerup인 경우, mouseup 이벤트를
발행합니다.
pointercancel인 경우,
window에서 mouseup 이벤트를 발행합니다.
pointerup 또는 pointercancel이었다면,
이 pointerType에 대한 PREVENT MOUSE EVENT 플래그를 해제합니다.
사용자 에이전트가 [TOUCH-EVENTS]에 정의된 터치 이벤트와 포인터 이벤트를 모두 지원하는 경우, user agent는 이 절에서 설명하는 호환성 마우스 이벤트와 [TOUCH-EVENTS]에 요약된 대체 마우스 이벤트를 MUST NOT (둘 다) 생성해야 합니다.
호버를 지원하지 않는 기본 포인터(예: 터치스크린의 단일
손가락)로 요소를 활성화(click)하는 것은 일반적으로 다음과 같은 이벤트 시퀀스를 생성합니다:
mousemovepointeroverpointerentermouseovermouseenterpointerdownmousedownpointermove 및 mousemove
이벤트pointerupmouseuppointeroutpointerleavemouseoutmouseleaveclick그러나 이 상호작용 중 pointerdown 이벤트가 취소된 경우, 이벤트 시퀀스는 다음과 같습니다:
mousemovepointeroverpointerentermouseovermouseenterpointerdownpointermove 이벤트pointeruppointeroutpointerleavemouseoutmouseleaveclick이 부록은 Pointer Events 구현에 대한 보안 및 프라이버시 고려사항을 논의합니다. 논의는 이 명세에서 정의된 이벤트 모델, API 및 이벤트의 구현으로부터 직접적으로 발생하는 보안 및 프라이버시 이슈로 한정됩니다.
이 명세에서 정의되는 많은 이벤트 유형은 사용자 동작에 대한 응답으로 디스패치됩니다. 이는 악의적인 이벤트 리스너가 사용자가 일반적으로 기밀로 여기는 정보(예: 페이지와 상호작용하는 동안 사용자의 마우스/스타일러스/손가락의 정확한 경로/움직임)에 접근할 수 있게 할 수 있습니다.
포인터 이벤트에는(사용자의 기기가 지원하는 경우) 펜 입력이 유지되는 각도나 기울기, 접촉 면의 기하, 스타일러스나 터치 스크린에 가해지는 압력과 같은 추가 정보가 포함될 수 있습니다. 각도, 기울기, 기하 및 압력에 관한 정보는 사용자의 기기에 있는 센서와 직접적으로 관련되므로, 이 명세는 오리진이 이러한 센서에 접근할 수 있도록 허용합니다.
이러한 센서 데이터와 더불어, 사용된 입력 메커니즘(마우스, 터치, 펜)의 유형을 판별할 수 있는 능력은 사용자 또는 사용자의 기기 및 환경의 특성을 추론하는 데 사용될 수 있습니다. 추론된 특성과 모든 기기/환경 정보는 그 자체로 민감할 수 있습니다 — 예를 들어, 악의적인 사이트가 사용자가 보조 기술을 사용 중인지 추가로 추론하게 만들 수 있습니다. 이 정보는 또한 사용자 프로파일을 구축하거나 특정 사용자를 "fingerprint(핑거프린팅)" 및 추적하려는 목적으로 잠재적으로 사용될 수 있습니다.
완화책으로서, 사용자 에이전트는 사용자에게 특정 센서 데이터(각도, 기울기, 압력 등)에 대한 접근을 비활성화할 수 있는 기능을 제공하고, 그리고/또는 사용자가 명시적으로 옵트인한 이후에만 이를 사용할 수 있도록 하는 것을 고려할 수 있습니다.
센서에 대한
공장 보정 정보는 센서 데이터의 특정 변동과 특성을 기반으로 개별 기기를 핑거프린팅하는 데 사용될 수 있습니다. 이 명세는 많은 센서 관련 이벤트 속성을
float 및 double 정밀도로 정의하지만, 구현에서는 노출하는 센서 데이터의 정밀도를 실질적으로 유용한 수준으로 제한할 것을 권장합니다.
0.1도보다 더 정밀해서는 안 됩니다.이 명세는 작성자가 "예측된 이벤트"에 접근할 수 있는 방법을 정의합니다. 명세 자체는 사용자 에이전트가 예측에 사용해야 하는 알고리즘을 정의하지 않습니다. 명세 작성자들은 알고리즘이 사용자가 수행 중인 현재 제스처와 관련된 이전 포인터 이벤트에만 의존하도록 상정합니다. 사용자 에이전트는 자신의 특정 예측 알고리즘 구현이 사용자에 대한 민감한 정보를 드러내거나 사용자를 "fingerprint(핑거프린팅)" 및 추적하는 데 사용될 수 있는 추가 데이터(예: 서로 다른 사이트에 걸친 사용자의 전체 상호작용 기록)에 의존하지 않도록 보장할 책임이 있습니다.
이러한 고려사항 외에, 워킹 그룹은 이 명세가 다음과 같다고 봅니다.
이 섹션은 비규범적입니다.
buttons 속성이 0이 아닌 값을 가질 때의 상태입니다. 마우스의 경우, 장치에 적어도 하나의 버튼이 눌려 있을 때입니다. 터치의 경우, 디지타이저와
물리적 접촉이 있을 때입니다. 펜의 경우, 펜이 디지타이저와 물리적 접촉을 하거나, 호버 중에 적어도 하나의 버튼이 눌려 있을 때입니다.pointerId로 식별됨)가 문서 내에서 추가 이벤트를 생성할 수
있다면, 그 포인터는 여전히 활성으로 간주됩니다. 예:
preventDefault()의 사용, 이벤트 핸들러에서 false를 반환, 또는 [UIEVENTS] 및
[HTML]에 정의된 기타 수단으로 기본 동작이 방지된 이벤트입니다.
측정 가능한 속성은 실수 또는 큰 도메인의 정수로 표현되는 연속 포인터 센서 데이터와 관련된 값을 나타냅니다. 포인터 이벤트의 경우, width,
height,
pressure,
tangentialPressure, tiltX, tiltY, twist,
altitudeAngle, azimuthAngle, 그리고 [UIEVENTS] 마우스 이벤트
모델 속성
screenX, screenY, clientX, clientY가 측정 가능한
속성입니다.
대조적으로 pointerId, pointerType,
isPrimary, 그리고
[UIEVENTS] 마우스 이벤트 모델 속성 button,
buttons, ctrlKey,
shiftKey, altKey, metaKey는 센서 데이터와 관련되지 않으므로 측정 가능한 속성으로 간주되지
않습니다.
이 문서에 포함된 일부 제안과 권고에 대해 많은 분들께 깊이 감사드립니다. 그룹 의장은 다음의 과거 및 현재 그룹 구성원과 참여자들의 기여를 인정합니다: 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.
특히 1판의 개척을 도와주신 분들께 특별한 감사를 전합니다. 특히: Charu Chandiram, Peter Freiling, Nathan Furtwangler, Thomas Olsen, Matt Rakow, Ramu Ramanathan, Justin Rogers, Jacob Rossi, Reed Townsend, Steve Wright.
이 섹션은 비규범적입니다.
다음은 [PointerEvents2] 명세와 비교하여, 이 명세의 출판물 간에 이루어진 중대하고 주요한 편집 변경 사항에 대한 정보 요약입니다. 이 명세의 에디터 초안에 대한 전체 변경 이력을 참조하십시오.
touch-action 값 제거
(pan-left, pan-right, pan-up, pan-down)click, auxclick,
contextmenu의 .button 및
.buttons 동작이 UIEvents에서 비롯됨을 명확화isTrusted 비트 명확화
pointercancel 좌표/속성에 대한 명확화 추가
click/contextmenu가 호환성
마우스 이벤트가 아님을 규범으로 명시pointerId 관련 주석의 요소를 규범 텍스트로 이동
pointercancel 발행 동작 명확화
pointermove 디스패치를 지연하는
이유로서 애니메이션 프레임 콜백에 대한 언급 제거
pointerrawmove가 빈 예측 이벤트 목록을 갖는다는
점에 대한 명시적 주석measurable properties를 포괄하도록, 위치만이 아님)
touch-action의 근거 및 목적 명확화touch-action 정의 재작성/확장 (패닝/줌
동작에만 명확히 범위를 한정)click/contextmenu 및
사용자 에이전트 휴리스틱에 관한 주석에 정보 추가pointerId를
0에서 -1로 변경touch-action과 iframe/임베디드 브라우징
컨텍스트에 관한 주석 추가azimuthAngle,
altitudeAngle, tiltX, tiltY가 포인터 이벤트 Web IDL에서 기본값을 요구하지 않도록
업데이트pointerrawupdate 및
getCoalescedEvents에 보안 컨텍스트 기준 추가click, auxclick,
contextmenu의 타입을 PointerEvent로 변경altitudeAngle/azimuthAngle
추가getPredictedEvents API 추가
getCoalescedEvents API 및
pointerrawupdate 이벤트 도입touch-action 값 추가
(pan-left, pan-right, pan-up, pan-down) 및 기존
pan-x 및 pan-y 값의 동작을 명확화
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;
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;
[SecureContext] sequence<PointerEvent> getCoalescedEvents();
sequence<PointerEvent> getPredictedEvents();
};
partial interface Element {
undefined setPointerCapture (long pointerId);
undefined releasePointerCapture (long pointerId);
boolean hasPointerCapture (long pointerId);
};
partial interface mixin GlobalEventHandlers {
attribute EventHandler onpointerover;
attribute EventHandler onpointerenter;
attribute EventHandler onpointerdown;
attribute EventHandler onpointermove;
[SecureContext] attribute EventHandler onpointerrawupdate;
attribute EventHandler onpointerup;
attribute EventHandler onpointercancel;
attribute EventHandler onpointerout;
attribute EventHandler onpointerleave;
attribute EventHandler ongotpointercapture;
attribute EventHandler onlostpointercapture;
};
partial interface Navigator {
readonly attribute long maxTouchPoints;
};
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: