게임패드

W3C 작업 초안

이 문서에 대한 자세한 정보
이 버전:
https://www.w3.org/TR/2025/WD-gamepad-20250710/
최신 게시 버전:
https://www.w3.org/TR/gamepad/
최신 편집자 초안:
https://w3c.github.io/gamepad/
이력:
https://www.w3.org/standards/history/gamepad/
커밋 이력
테스트 스위트:
https://wpt.live/gamepad/
구현 보고서:
https://wpt.fyi/results/gamepad
편집자:
Steve Agoston (Sony)
Matt Reynolds (Google)
이전 편집자:
James Hollyer (Google)
Brandon Jones (Google)
Scott Graham (Google)
Ted Mielczarek (Mozilla)
피드백:
GitHub w3c/gamepad (pull requests, new issue, open issues)
브라우저 지원:
caniuse.com

초록

Gamepad 명세는 게임패드 장치를 나타내는 저수준 인터페이스를 정의합니다.

이 문서의 상태

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

이 문서는 진행 중인 작업입니다.

이 문서는 웹 애플리케이션 워킹 그룹권고안 트랙을 사용하여 작업 초안으로 발행했습니다.

작업 초안으로 발행되었다고 해서 W3C와 그 회원의 승인을 의미하지는 않습니다.

이 문서는 초안 문서이며 언제든지 다른 문서로 갱신, 대체 또는 폐기될 수 있습니다. 진행 중인 작업 외의 용도로 이 문서를 인용하는 것은 부적절합니다.

이 문서는 W3C 특허 정책에 따라 운영되는 그룹에서 작성했습니다. W3C는 해당 그룹의 산출물과 관련하여 이루어진 모든 특허 공개의 공개 목록을 유지합니다; 그 페이지에는 특허를 공개하는 방법에 대한 지침도 포함되어 있습니다. 본인이 필수 청구항을 포함한다고 믿는 특허를 실제로 알고 있는 개인은 W3C 특허 정책 6절에 따라 그 정보를 공개해야 합니다.

이 문서는 2023년 11월 03일 W3C 프로세스 문서의 적용을 받습니다.

1. 소개

이 절은 비규범적입니다.

일부 사용자 에이전트에는 연결된 게임패드 장치가 있습니다. 이러한 장치는 게임 애플리케이션의 입력과 "10 foot" 사용자 인터페이스(프레젠테이션, 미디어 뷰어)에 적합하며 바람직합니다.

현재 게임패드를 입력으로 사용하는 유일한 방법은 마우스 또는 키보드 이벤트를 에뮬레이트하는 것이지만, 이는 정보를 잃게 하며 에뮬레이션을 수행하기 위해 사용자 에이전트 외부의 추가 소프트웨어를 필요로 합니다.

한편, 네이티브 애플리케이션은 시스템 API를 통해 이러한 장치에 접근할 수 있습니다.

Gamepad API는 웹 애플리케이션이 게임패드 데이터에 직접 동작할 수 있게 하는 인터페이스를 명시함으로써 이 문제에 대한 해결책을 제공합니다.

2. 범위

게임을 제어하도록 설계된 외부 장치와 인터페이스하는 것은 완전한 일반성으로 접근할 경우 매우 크고 다루기 어려워질 가능성이 있습니다. 이 명세에서는 널리 구현될 수 있고 폭넓게 유용한 기능의 유용한 부분 집합을 제공하기 위해 범위를 명시적으로 좁히기로 선택합니다.

구체적으로, 우리는 게임패드를 지원하는 데 필요한 기능만 지원하기로 선택합니다. 게임패드를 지원하려면 두 가지 입력 유형, 즉 버튼과 축이 필요합니다. 버튼과 축은 모두 아날로그 값으로 보고되며, 버튼은 [0 .. 1] 범위이고, 축은 [-1 .. 1] 범위입니다.

주요 목표는 게임패드 장치를 지원하는 것이지만, 이러한 두 가지 유형의 아날로그 입력을 지원하면 현재 게임 시스템에서 흔히 쓰이는 조이스틱, 운전대, 페달, 가속도계 등 다른 유사한 장치도 지원할 수 있습니다. 따라서 "gamepad"라는 이름은 이 명세가 다루는 전체 장치 집합의 일반적인 이름이 되려는 것이 아니라 예시적인 이름입니다.

우리는 일부 게임 맥락에서도 사용될 수 있는 더 복잡한 장치, 즉 모션 감지, 깊이 감지, 비디오 분석, 제스처 인식 등을 수행하는 장치에 대한 지원은 명시적으로 제외합니다.

3. 모델

게임패드는 입력 컨트롤과 출력 컨트롤의 모음입니다. 입력 컨트롤에는 시간이 지남에 따라 갱신될 수 있는 입력 값 모음이 있습니다. 입력 컨트롤에는 게임패드의 버튼, 트리거, 조이스틱, 엄지스틱, 터치 표면이 포함됩니다. 출력 컨트롤게임패드와 상호작용하는 사용자에게 피드백을 제공하기 위해 게임패드의 동작을 변경하는 기능입니다. 출력 컨트롤에는 게임패드의 햅틱 액추에이터가 포함됩니다. 게임패드사용자 에이전트가 그 입력 컨트롤의 현재 상태를 읽을 수 있으면 사용 가능합니다. 게임패드사용 가능하지 않으면 사용 불가합니다. 게임패드사용 가능한 동안에는 그 입력 컨트롤출력 컨트롤이 변경될 수 없습니다.

사용자 에이전트는 다음을 담당합니다:

게임패드에는 게임패드 식별자 문자열이 있습니다. 이는 게임패드의 브랜드나 스타일을 식별하는 사람이 읽을 수 있는 문자열입니다. 그 내용은 사용자 에이전트가 결정합니다.

3.1 입력 컨트롤 배치

게임패드에는 입력 컨트롤 각각의 위치, 방향, 유형을 설명하는 입력 컨트롤 배치가 있을 수 있습니다. 사용자 에이전트게임패드표준 배치와 대응하는 시점을 인식할 책임이 있습니다. 이는 게임패드가 같은 표준 배치와 대응하는 다른 게임패드와 상호 교환하여 사용할 수 있게 하는 입력 컨트롤 배치를 갖는다는 뜻입니다. 사용자 에이전트는 그 입력 컨트롤이 표준 배치에 설명된 입력 컨트롤과 거의 같은 상대적 위치와 방향을 가지면, 그 배치가 표준 배치와 대응한다고 간주하는 것이 좋습니다.

사용자 에이전트는 보통 게임패드입력 컨트롤 배치를 직접 검사할 수 없으며, 배치를 결정하기 위해 휴리스틱을 사용할 수 있습니다. 사용자 에이전트게임패드표준 배치와 대응하는지 결정할 때 장치 식별자를 고려하는 것이 좋습니다. 시스템이 각 입력 컨트롤에 레이블을 할당하고 그 레이블이 특정 배치를 암시한다면, 사용자 에이전트는 그 게임패드가 그 배치를 가진다고 간주하는 것이 좋습니다. 같은 입력 컨트롤을 가진 표준 모델과 접근성 모델이 있을 때, 사용자 에이전트는 접근성 모델이 표준 모델과 같은 입력 컨트롤 배치를 가진다고 간주하는 것이 좋습니다.

참고
접근성 게임패드 모델은 제조사의 의도가 표준 배치를 가진 게임패드의 교체용 대체품을 제공하는 데 있는 게임패드입니다. 예를 들어 Xbox Adaptive Controller와 PlayStation Access Controller는 접근성 게임패드 모델입니다. Xbox Wireless Controller와 DualSense는 이에 대응하는 표준 모델입니다.

3.2 입력 값

각 입력 컨트롤에는 연결된 입력 값이 하나 이상 있으며, 이는 컨트롤의 현재 상태를 나타내는 숫자 값입니다. 입력 값은 언제든 갱신될 수 있습니다. 사용자 에이전트입력 값이 갱신된 시점을 감지할 책임이 있으며, 갱신과 갱신된 값이 읽히는 시점 사이의 지연을 최소화하려고 노력하는 것이 좋습니다.

입력 값을 읽으면 그 논리 값, 즉 현재 상태의 비스케일 숫자 표현이 반환됩니다. 입력 값에는 또한 경계 내 논리 값의 최솟값과 최댓값을 정의하는 논리 최솟값논리 최댓값이 있습니다.

입력 값에는 입력 값이 나타내는 데이터의 유형을 식별하는 32비트 값인 HID 사용 식별자가 연결될 수 있습니다. HID 사용은 입력 컨트롤 배치를 정확히 설명하지는 않지만, 관례상 유사한 배치를 가진 많은 게임패드는 유사한 사용을 사용합니다. 사용자 에이전트입력 컨트롤 배치를 결정할 때 HID 사용 식별자에 관한 관례에 의존하는 것이 좋습니다.

3.3

게임패드에는 입력이 있을 수 있습니다. 은 기준 위치로부터 컨트롤의 현재 변위를 나타내는 입력 값입니다.

게임패드에는 축 목록이 있으며, 이는 목록으로서 사용자 에이전트가 결정한 어떤 순서로 게임패드에 대한 모든 입력을 포함합니다.

입력 컨트롤은 사용자가 입력 컨트롤과 상호작용을 멈추면 이 자동으로 중앙 위치로 돌아가도록 설계될 수 있습니다. 그렇다면 그 에는 선호 축 상태가 있습니다. 선호 축 상태가 있는 에는 추가 입력 값, 즉 중앙 위치 값도 있을 수 있습니다. 이는 이 중앙에 있을 때의 논리 값입니다.

3.4 버튼

게임패드에는 버튼 입력이 있을 수 있습니다. 버튼은 눌러서 활성화할 수 있는 입력 컨트롤입니다. 게임패드에는 버튼 목록이 있으며, 이는 목록으로서 사용자 에이전트가 결정한 어떤 순서로 게임패드에 대한 모든 버튼 입력을 포함합니다.

입력 컨트롤은 사용자가 입력 컨트롤과 상호작용을 멈추면 버튼이 자동으로 눌리지 않은 상태로 돌아가도록 설계될 수 있습니다. 그렇다면 그 버튼에는 선호 버튼 상태가 있습니다.

버튼에는 그 버튼이 활성화된 때를 나타내는 디지털 스위치가 있을 수 있습니다. 그렇다면 그 버튼에는 추가 입력 값, 즉 디지털 버튼 값이 있으며, 이는 버튼이 활성화되어 있으면 true이고, 그렇지 않으면 false입니다.

버튼에는 그 버튼이 어느 정도 활성화되었는지 보고할 수 있게 하는 아날로그 센서가 있을 수 있습니다. 그렇다면 그 버튼에는 다음이 있습니다:

버튼은 터치를 감지할 수 있을 수 있습니다. 그렇다면 그 버튼에는 추가 입력 값, 즉 버튼 터치 값이 있으며, 이는 버튼이 터치되고 있으면 true이고, 그렇지 않으면 false입니다.

3.5 터치 표면

게임패드에는 터치 표면이 있을 수 있습니다. 터치 표면은 접촉 지점을 나타내는 2D 위치 데이터를 제공하는 입력 컨트롤입니다. 게임패드에는 터치 표면 목록이 있으며, 이는 목록으로서 게임패드터치 표면을 포함합니다. 이 목록은 게임패드의 왼쪽에 더 가까운 터치 표면이 목록의 시작 부분에 더 가깝게 나타나도록 정렬됩니다.

터치 표면에는 활성 터치 지점 목록 입력 값이 있습니다. 이는 센서가 현재 감지한 접촉 지점을 나타내는 0개 이상의 터치 지점목록입니다. 터치 지점은 단일 시점의 단일 접촉 지점을 나타냅니다. 터치 지점에는 터치 표면의 좌표계에서 위치를 나타내는 터치 x 좌표터치 y 좌표가 있습니다. 터치 표면게임패드의 위쪽, 아래쪽, 앞쪽 또는 뒤쪽에 있으면 터치 x 좌표는 좌우 축을 따라 측정되고, 그렇지 않으면 상하 축을 따라 측정됩니다. 터치 y 좌표는 수직 축을 따라 측정됩니다.

터치 표면게임패드의 왼쪽 또는 오른쪽 면에 있으면, 그 두 치수 중 어느 것도 수평 축과 정렬되지 않습니다.

터치 표면에는 표면 치수 입력 값이 있을 수 있습니다. 표면 너비표면 높이 입력 값터치 x 좌표터치 y 좌표와 같은 단위로 표현된 터치 표면의 치수입니다. 터치 표면은 두 치수 값을 모두 갖거나 어느 값도 갖지 않습니다.

터치 지점은 새 접촉 지점일 수도 있고 이전 접촉의 연속일 수도 있습니다. 터치 지점사용자 에이전트가 그것이 이전 GamepadTouch가 나타낸 터치 지점의 연속이라고 식별하면 기존 활성 터치 지점의 일부입니다. 기존 활성 터치 지점의 일부터치 지점에 대한 활성 터치 지점 ID는 이전 GamepadTouchtouchId입니다.

3.6 출력 컨트롤

게임패드에는 햅틱 액추에이터가 있을 수 있습니다. 햅틱 액추에이터는 사용자가 느낄 수 있는 방식으로 게임패드를 움직일 수 있는 출력 컨트롤입니다. 햅틱 액추에이터는 사용자에게 피드백을 제공하는 햅틱 효과를 생성하는 데 사용될 수 있습니다. 여러 액추에이터의 진동은 결합되어 더 복잡한 효과를 생성합니다. 사용자 에이전트사용 가능한 게임패드에서 햅틱 액추에이터햅틱 효과를 재생하고 중지하도록 명령할 책임이 있습니다.

게임패드에는 전체 게임패드를 진동시키는 햅틱 효과를 재생할 수 있는 햅틱 액추에이터진동 액추에이터가 있을 수 있습니다.

햅틱 액추에이터에는 하나 이상의 GamepadHapticEffectType 값을 포함하는 지원되는 효과 유형목록이 있으며, 이는 게임패드사용 가능한 동안에는 변경될 수 없습니다.

4. Gamepad 인터페이스

이 인터페이스는 개별 게임패드 장치를 정의합니다.

WebIDL[Exposed=Window]
interface Gamepad {
  readonly attribute DOMString id;
  readonly attribute long index;
  readonly attribute boolean connected;
  readonly attribute DOMHighResTimeStamp timestamp;
  readonly attribute GamepadMappingType mapping;
  readonly attribute FrozenArray<double> axes;
  readonly attribute FrozenArray<GamepadButton> buttons;
  readonly attribute FrozenArray<GamepadTouch> touches;
  [SameObject] readonly attribute GamepadHapticActuator vibrationActuator;
};

시스템과 통신하는 데 사용되는 알고리즘은 일반적으로 비동기적으로 완료되며, 게임패드 태스크 소스에 작업을 큐에 넣습니다.

Gamepad 인스턴스는 다음 표에 설명된 내부 슬롯으로 생성됩니다:

내부 슬롯 초기값 설명(비규범적)
[[connected]] false 장치가 시스템에 연결되어 있음을 나타내는 플래그
[[timestamp]] undefined Gamepad에 대한 데이터가 마지막으로 갱신된 시간
[[axes]] sequence 이 장치가 노출하는 축의 현재 상태를 나타내는 double 값의 sequence
[[buttons]] sequence 이 장치가 노출하는 버튼의 현재 상태를 나타내는 GamepadButton 객체의 sequence
[[exposed]] false Gamepad 객체가 스크립트에 노출되었음을 나타내는 플래그
[[axisMapping]] ordered map 매핑되지 않은 축 인덱스에서 axes 배열의 인덱스로의 매핑
[[axisMinimums]] list 각 축의 최소 논리 값을 포함하는 list
[[axisMaximums]] list 각 축의 최대 논리 값을 포함하는 list
[[buttonMapping]] ordered map 매핑되지 않은 버튼 인덱스에서 buttons 배열의 인덱스로의 매핑
[[buttonMinimums]] list 각 버튼의 최소 논리 값을 포함하는 list.
[[buttonMaximums]] list 각 버튼의 최대 논리 값을 포함하는 list
[[touches]] list 사용자에 의해 생성된 터치의 목록이 있으면 이를 보관합니다. 게임패드가 터치 표면을 지원하지 않으면 목록은 비어 있는 상태로 남습니다.
[[nextTouchId]] 0 다음 수신 터치에 사용할 touchId 값.
[[vibrationActuator]] undefined 전체 게임패드를 진동시키는 햅틱 효과를 생성할 수 있는 GamepadHapticActuator 객체
id 속성

게임패드의 식별 문자열입니다. 이 문자열은 연결된 게임패드 장치의 브랜드나 스타일을 식별합니다.

id 문자열의 정확한 형식은 명시하지 않습니다. 사용자 에이전트는 장치를 고유하게 식별하지 않고 제품을 식별하는 문자열을 선택하는 것이 RECOMMENDED입니다. 예를 들어 USB 게임패드는 idVendoridProduct 값으로 식별될 수 있습니다. 일련번호나 Bluetooth 장치 주소와 같은 고유 식별자는 id 문자열에 포함되어서는 MUST NOT 됩니다.

index 속성
Navigator에서의 게임패드 인덱스입니다. 여러 게임패드가 사용자 에이전트에 연결되어 있을 때, 인덱스는 0부터 시작하여 선착순 기준으로 할당되어야 MUST 합니다. 게임패드의 연결이 끊어지면, 이전에 할당된 인덱스는 계속 연결되어 있는 게임패드에 재할당되어서는 MUST NOT 됩니다. 그러나 게임패드의 연결이 끊어진 뒤, 이후 같은 게임패드나 다른 게임패드가 연결되면, 이전에 사용된 가장 낮은 인덱스를 다시 사용해야 MUST 합니다.
connected 속성

이 객체가 나타내는 물리적 장치가 여전히 시스템에 연결되어 있는지를 나타냅니다. 게임패드가 물리적으로 분리되었거나, 전원이 꺼졌거나, 그 밖의 이유로 사용할 수 없게 되어 사용 불가 상태가 되면, connected 속성은 false로 설정되어야 MUST 합니다.

connected getter 단계는 다음과 같습니다:

  1. this.[[connected]]를 반환합니다.
timestamp 속성

timestamp는 작성자가 이 게임패드에 대한 axes 또는 buttons 속성이 마지막으로 갱신된 시간을 판단할 수 있게 합니다. 값은 시스템이 장치로부터 새 버튼 또는 축 입력 값을 받을 때마다 현재 고해상도 시간으로 설정되어야 MUST 합니다. 하드웨어에서 데이터가 수신되지 않은 경우, timestampGamepad가 처음으로 스크립트에 사용 가능하게 된 시점의 현재 고해상도 시간이어야 MUST 합니다.

경고

사용자 에이전트는 [HR-TIME]의 클록 해상도 권고를 따라 timestamp 속성의 최소 해상도를 5마이크로초로 설정하는 것이 SHOULD입니다.

timestamp getter 단계는 다음과 같습니다:

  1. this.[[timestamp]]를 반환합니다.
mapping 속성

이 장치에 사용 중인 매핑입니다. 사용자 에이전트가 장치의 배치를 알고 있다면, mapping을 대응하는 GamepadMappingType 값으로 설정하여 매핑이 사용 중임을 나타내는 것이 SHOULD입니다.

게임패드 장치에 대한 매핑을 선택하려면 다음 단계를 실행합니다:

  1. 게임패드 장치의 버튼 및 축 배치가 Standard Gamepad 배치와 대응하면, "standard"를 반환합니다.
  2. ""를 반환합니다.
axes 속성

게임패드의 모든 축에 대한 값 배열입니다. 모든 축 값은 [-1 .. 1] 범위로 선형 정규화되어야 MUST 합니다. 컨트롤러가 지면에 수직이고 방향 스틱이 위를 가리키는 경우, -1은 "앞쪽" 또는 "왼쪽"에 대응하는 것이 SHOULD이며, 1은 "뒤쪽" 또는 "오른쪽"에 대응하는 것이 SHOULD입니다. 2D 입력 장치에서 온 축은 axes 배열에서 서로 이웃해 나타나는 것이 SHOULD이며, X 다음 Y 순서입니다. 축은 중요도가 감소하는 순서로 나타나는 것이 RECOMMENDED이며, 따라서 요소 0과 1은 일반적으로 방향 스틱의 X 및 Y 축을 나타냅니다. 사용자 에이전트가 다른 값 (또는 다른 순서의 값)을 반환해야 할 때까지 같은 객체가 반환되어야 MUST 합니다.

axes getter 단계는 다음과 같습니다:

  1. this.[[axes]]를 반환합니다.
buttons 속성

게임패드의 모든 버튼에 대한 버튼 상태 배열입니다. 버튼은 중요도가 감소하는 순서로 나타나는 것이 RECOMMENDED이며, 따라서 주 버튼, 보조 버튼, 제3 버튼 등이 buttons 배열의 요소 0, 1, 2, ...로 나타납니다. 사용자 에이전트가 다른 값(또는 다른 순서의 값)을 반환해야 할 때까지 같은 객체가 반환되어야 MUST 합니다.

buttons getter 단계는 다음과 같습니다:

  1. this.[[buttons]]를 반환합니다.
touches 속성

모든 터치 표면에서 생성된 GamepadTouch 객체의 list입니다.

touches getter 단계는 다음과 같습니다:

  1. this.[[touches]]를 반환합니다.
vibrationActuator 속성

장치의 기본 진동 액추에이터를 나타내는 GamepadHapticActuator 객체입니다.

vibrationActuator getter 단계는 다음과 같습니다:

  1. this.[[vibrationActuator]]를 반환합니다.

4.1 입력 수신

시스템이 새 버튼 또는 축 입력 값을 받으면, 다음 단계를 실행합니다:

  1. gamepad를 새 버튼 또는 축 입력 값을 받은 장치를 나타내는 Gamepad 객체로 둡니다.
  2. gamepad관련 전역 객체를 사용하여 gamepad에 대한 게임패드 상태 갱신을 수행하도록, 게임패드 태스크 소스전역 태스크를 큐에 넣습니다.

gamepad에 대해 게임패드 상태를 갱신하려면 다음 단계를 실행합니다:

  1. nowgamepad관련 전역 객체가 주어진 현재 고해상도 시간으로 둡니다.
  2. gamepad.[[timestamp]]now로 설정합니다.
  3. gamepad에 대해 축 매핑 및 정규화 단계를 실행합니다.
  4. gamepad에 대해 버튼 매핑 및 정규화 단계를 실행합니다.
  5. gamepad에 대해 터치 기록 단계를 실행합니다.
  6. navigatorgamepad관련 전역 객체Navigator 객체로 둡니다.
  7. navigator.[[hasGamepadGesture]]false이고 gamepad게임패드 사용자 제스처를 포함하면:
    1. navigator.[[hasGamepadGesture]]true로 설정합니다.
    2. navigator.[[gamepads]]의 각 connectedGamepad에 대해 반복합니다:
      1. connectedGamepadnull과 같지 않으면:
        1. connectedGamepad.[[exposed]]true로 설정합니다.
        2. connectedGamepad.[[timestamp]]now로 설정합니다.
        3. documentgamepad관련 전역 객체연결된 Document로 둡니다; 그렇지 않으면 null로 둡니다.
        4. documentnull이 아니고 완전히 활성 상태이면, 게임패드 태스크 소스전역 태스크를 큐에 넣어, GamepadEvent를 사용하고 그 gamepad 속성을 connectedGamepad로 초기화하여, gamepad관련 전역 객체에서 gamepadconnected라는 이름의 이벤트를 발송합니다.

gamepad에 대해 축을 매핑하고 정규화하려면 다음 단계를 실행합니다:

  1. axisValuesgamepad가 나타내는 장치의 각 축 입력에 대한 가장 최근의 논리 축 입력 값을 나타내는 unsigned long 값의 list로 둡니다.
  2. maxRawAxisIndexaxisValuessize − 1로 둡니다.
  3. 0부터 maxRawAxisIndex까지 범위의 각 rawAxisIndex에 대해 반복합니다:
    1. mappedIndexgamepad.[[axisMapping]][rawAxisIndex]로 둡니다.
    2. logicalValueaxisValues[rawAxisIndex]로 둡니다.
    3. logicalMinimumgamepad.[[axisMinimums]][rawAxisIndex]로 둡니다.
    4. logicalMaximumgamepad.[[axisMaximums]][rawAxisIndex]로 둡니다.
    5. normalizedValue를 2 (logicalValuelogicalMinimum) / (logicalMaximumlogicalMinimum) − 1로 둡니다.
    6. gamepad.[[axes]][axisIndex]를 normalizedValue로 설정합니다.

gamepad에 대해 버튼을 매핑하고 정규화하려면 다음 단계를 실행합니다:

  1. buttonValuesgamepad가 나타내는 장치의 각 버튼 입력에 대한 가장 최근의 논리 버튼 입력 값을 나타내는 unsigned long 값의 list로 둡니다.
  2. maxRawButtonIndexbuttonValuessize − 1로 둡니다.
  3. 0부터 maxRawButtonIndex까지의 범위의 각 rawButtonIndex에 대해 반복합니다:
    1. mappedIndexgamepad.[[buttonMapping]][rawButtonIndex]로 둡니다.
    2. logicalValuebuttonValues[rawButtonIndex]로 둡니다.
    3. logicalMinimumgamepad.[[buttonMinimums]][rawButtonIndex]로 둡니다.
    4. logicalMaximumgamepad.[[buttonMaximums]][rawButtonIndex]로 둡니다.
    5. normalizedValue를 (logicalValuelogicalMinimum) / (logicalMaximumlogicalMinimum)로 둡니다.
    6. buttongamepad.[[buttons]][mappedIndex]로 둡니다.
    7. button.[[value]]normalizedValue로 설정합니다.
    8. 버튼에 순수한 눌림 또는 해제 상태를 나타내는 디지털 스위치가 있으면, 버튼이 눌린 경우 button.[[pressed]]true로, 눌리지 않은 경우 false로 설정합니다.

      그렇지 않으면, 값이 버튼 누름 임계값을 넘는 경우 button.[[pressed]]true로, 임계값을 넘지 않는 경우 false로 설정합니다.

    9. 버튼이 터치를 감지할 수 있으면, 버튼이 현재 터치되고 있는 경우 button.[[touched]]true로 설정합니다.

      그렇지 않으면, button.[[touched]]button.[[pressed]]로 설정합니다.

gamepad에 대해 터치를 기록하려면 다음 단계를 실행합니다:

  1. Assert: Gamepad.[[touches]]비어 있습니다.
  2. gamepad의 각 터치 표면에 대해 터치 표면 열거 순서로 다음 단계를 반복합니다:
    1. surfaceId를 현재 표면 열거 인덱스로 둡니다.
    2. 터치 표면이 장치 단위의 최대 표면 치수를 노출하면, touch.surfaceDimensions를 터치 표면의 장치 단위 최대 X 및 Y 치수로 widthheight가 초기화된 DOMRectReadOnly로 설정합니다.
    3. 현재 터치 표면에 대해 gamepad가 보고한 각 활성 터치 지점에 대해 다음 단계를 반복합니다.
      1. touch를 새로 생성된 GamepadTouch 객체로 둡니다.
      2. touch.surfaceIdsurfaceId로 설정합니다.
      3. 터치 데이터가 사용자 에이전트가 추적하는 기존 활성 터치 지점의 일부이면:
        1. touch.touchId를 활성 터치 지점의 touchId로 설정합니다.
        2. 그렇지 않으면, touch.touchIdgamepad.[[nextTouchId]]로 설정하고 gamepad.[[nextTouchId]]를 증가시킵니다.
          참고: 터치 ID는 Gamepad에 상대적입니다

          Gamepad에 여러 터치 표면이 있으면 터치 ID는 표면 전체에서 고유합니다.

      4. touch.positionnew DOMPointReadOnly로 설정하되, x는 장치 터치 표면에 상대적인 장치 X 좌표로 초기화하고, -1이 가장 왼쪽 좌표이고 1이 가장 오른쪽 좌표가 되도록 [-1 .. 1]로 정규화하며, y는 장치 터치 표면으로 초기화하고, -1이 가장 위쪽 좌표이고 1이 가장 아래쪽 좌표가 되도록 [-1 .. 1]로 정규화합니다.
        참고: 가능한 구현(surfaceDimensions를 사용할 수 있는 경우)

        x = (2.0 * touchData.x / surfaceDimensions.width) - 1
        y = (2.0 * touchData.y / surfaceDimensions.height) - 1

      5. touchgamepad.[[touches]]추가합니다.

4.2 Gamepad 생성

연결된 게임패드 장치를 나타내는 Gamepad는 다음 단계를 수행하여 생성됩니다:

  1. gamepad를 새로 생성된 Gamepad 인스턴스로 둡니다:
    1. gamepadid 속성을 게임패드의 식별 문자열로 초기화합니다.
    2. gamepadindex 속성을 gamepad에 대해 사용되지 않은 게임패드 인덱스 선택의 결과로 초기화합니다.
    3. gamepadmapping 속성을 게임패드 장치에 대한 매핑 선택의 결과로 초기화합니다.
    4. gamepad.[[connected]]true로 설정합니다.
    5. gamepad.[[timestamp]]gamepad관련 전역 객체가 주어진 현재 고해상도 시간으로 설정합니다.
    6. gamepad.[[axes]]gamepad에 대한 축 초기화의 결과로 설정합니다.
    7. gamepad.[[buttons]]gamepad에 대한 버튼 초기화의 결과로 설정합니다.
    8. gamepad.[[vibrationActuator]]gamepad에 대한 GamepadHapticActuator 생성의 결과로 설정합니다.
  2. gamepad를 반환합니다.

gamepad에 대해 사용되지 않은 게임패드 인덱스를 선택하려면 다음 단계를 실행합니다:

  1. navigatorgamepad관련 전역 객체Navigator 객체로 둡니다.
  2. maxGamepadIndexnavigator.[[gamepads]]size − 1로 둡니다.
  3. 0부터 maxGamepadIndex까지의 범위의 각 gamepadIndex에 대해 반복합니다:
    1. navigator.[[gamepads]][gamepadIndex]가 null이면, gamepadIndex를 반환합니다.
  4. nullnavigator.[[gamepads]]추가합니다.
  5. navigator.[[gamepads]]size − 1을 반환합니다.

gamepad에 대해 축을 초기화하려면 다음 단계를 실행합니다:

  1. inputCountgamepad가 나타내는 장치가 노출하는 축 입력의 수로 둡니다.
  2. gamepad.[[axisMinimums]]를 각 축 입력의 최소 논리 값을 포함하며 inputCount와 같은 size를 갖는 unsigned long 값의 list로 설정합니다.
  3. gamepad.[[axisMaximums]]를 각 축 입력의 최대 논리 값을 포함하며 inputCount와 같은 size를 갖는 unsigned long 값의 list로 설정합니다.
  4. unmappedInputList를 빈 list로 둡니다.
  5. mappedIndexList를 빈 list로 둡니다.
  6. axesSize를 0으로 둡니다.
  7. 0부터 inputCount − 1까지의 범위의 각 rawInputIndex에 대해 반복합니다:
    1. 인덱스 rawInputIndex의 게임패드 축이 Standard Gamepad 축을 나타내면:
      1. canonicalIndex를 그 축에 대한 정규 인덱스로 둡니다.
      2. mappedIndexListcanonicalIndex포함하면, rawInputIndexunmappedInputList에 추가합니다.

        그렇지 않으면:

        1. gamepad.[[axisMapping]][rawInputIndex]를 canonicalIndex로 설정합니다.
        2. canonicalIndexmappedIndexList추가합니다.
        3. canonicalIndex + 1이 axesSize보다 크면, axesSizecanonicalIndex + 1로 설정합니다.

      그렇지 않으면, rawInputIndexunmappedInputList추가합니다.

  8. axisIndex를 0으로 둡니다.
  9. unmappedInputList의 각 rawInputIndex에 대해 반복합니다:
    1. mappedIndexListaxisIndex포함하는 동안:
      1. axisIndex를 증가시킵니다.
    2. gamepad.[[axisMapping]][rawInputIndex]를 axisIndex로 설정합니다.
    3. axisIndexmappedIndexList추가합니다.
    4. axisIndex + 1이 axesSize보다 크면, axesSizeaxisIndex + 1로 설정합니다.
  10. axes를 빈 list로 둡니다.
  11. 0부터 axesSize − 1까지의 범위의 각 axisIndex에 대해 반복하며, 0을 axes추가합니다.
  12. axes를 반환합니다.

gamepad에 대해 버튼을 초기화하려면 다음 단계를 실행합니다:

  1. inputCountgamepad가 나타내는 장치가 노출하는 버튼 입력의 수로 둡니다.
  2. gamepad.[[buttonMinimums]]를 각 버튼 입력의 최소 논리 값을 포함하며 inputCount와 같은 size를 갖는 unsigned long 값의 list로 설정합니다.
  3. gamepad.[[buttonMaximums]]를 각 버튼 입력의 최대 논리 값을 포함하며 inputCount와 같은 size를 갖는 unsigned long 값의 list로 설정합니다.
  4. unmappedInputList를 빈 list로 둡니다.
  5. mappedIndexList를 빈 list로 둡니다.
  6. buttonsSize를 0으로 둡니다.
  7. 0부터 inputCount − 1까지의 범위의 각 rawInputIndex에 대해 반복합니다:
    1. 인덱스 rawInputIndex의 게임패드 버튼이 Standard Gamepad 버튼을 나타내면:
      1. canonicalIndex를 그 버튼에 대한 정규 인덱스로 둡니다.
      2. mappedIndexListcanonicalIndex포함하면, rawInputIndexunmappedInputList에 추가합니다.

        그렇지 않으면:

        1. gamepad.[[buttonMapping]][rawInputIndex] 를 canonicalIndex로 설정합니다.
        2. canonicalIndexmappedIndexList추가합니다.
        3. canonicalIndex + 1이 buttonsSize보다 크면, buttonsSizecanonicalIndex + 1로 설정합니다.

      그렇지 않으면, rawInputIndexunmappedInputList추가합니다.

    2. rawInputIndex를 증가시킵니다.
  8. buttonIndex를 0으로 둡니다.
  9. unmappedInputList의 각 rawInputIndex에 대해 반복합니다:
    1. mappedIndexListbuttonIndex포함하는 동안:
      1. buttonIndex를 증가시킵니다.
    2. gamepad.[[buttonMapping]][rawInputIndex] 를 buttonIndex로 설정합니다.
    3. buttonIndexmappedIndexList추가합니다.
    4. buttonIndex + 1이 buttonsSize보다 크면, buttonsSizebuttonIndex + 1로 설정합니다.
  10. buttons를 빈 list로 둡니다.
  11. 0부터 buttonsSize − 1까지의 범위의 각 buttonIndex에 대해 반복하며, new GamepadButtonbuttons추가합니다.
  12. buttons를 반환합니다.

5. GamepadButton 인터페이스

이 인터페이스는 게임패드 장치의 개별 버튼 상태를 정의합니다.

WebIDL[Exposed=Window]
interface GamepadButton {
  readonly attribute boolean pressed;
  readonly attribute boolean touched;
  readonly attribute double value;
};

GamepadButton 인스턴스는 다음 표에 설명된 내부 슬롯으로 생성됩니다:

내부 슬롯 초기값 설명(비규범적)
[[pressed]] false 버튼이 눌렸음을 나타내는 플래그
[[touched]] false 버튼이 터치되었음을 나타내는 플래그
[[value]] 0.0 [0 .. 1] 범위로 스케일된 버튼 값을 나타내는 double
pressed 속성

버튼의 눌림 상태입니다. 이 속성은 버튼이 현재 눌려 있으면 true여야 MUST 하며, 눌려 있지 않으면 false여야 합니다. 순수한 눌림 또는 해제 상태를 나타내는 디지털 스위치가 없는 버튼의 경우, 사용자 에이전트는 값이 일정한 양을 초과할 때 버튼을 눌린 것으로 나타내기 위해 버튼 누름 임계값을 선택해야 MUST 합니다. 플랫폼 API가 권장 값을 제공하는 경우, 사용자 에이전트는 그것을 사용하는 것이 SHOULD입니다. 그 밖의 경우, 사용자 에이전트는 다른 합리적인 값을 선택하는 것이 SHOULD입니다.

pressed getter 단계는 다음과 같습니다:

  1. this.[[pressed]]를 반환합니다.
touched 속성

버튼의 터치 상태입니다. 버튼이 터치를 감지할 수 있으면, 버튼이 현재 터치되고 있는 경우 이 속성은 true여야 MUST 하며, 그렇지 않으면 false여야 합니다. 버튼이 터치를 감지할 수 없고 아날로그 값을 보고할 수 있으면, value 속성이 0보다 큰 경우 이 속성은 true여야 MUST 하며, 값이 0이면 false여야 합니다. 버튼이 터치를 감지할 수 없고 디지털 값만 보고할 수 있으면, 이 속성은 pressed 속성을 반영해야 MUST 합니다.

touched getter 단계는 다음과 같습니다:

  1. this.[[touched]]를 반환합니다.
value 속성

아날로그 센서가 있는 버튼의 경우, 이 속성은 버튼이 눌린 정도를 나타내야 MUST 합니다. 모든 버튼 값은 [0 .. 1] 범위로 선형 정규화되어야 MUST 합니다. 0은 완전히 눌리지 않음을 의미해야 MUST 하며, 1은 완전히 눌림을 의미해야 MUST 합니다. 아날로그 센서가 없는 버튼의 경우, 완전히 눌리지 않음과 완전히 눌림에 대해 각각 값 0과 1만 제공되어야 MUST 합니다.

value getter 단계는 다음과 같습니다:

  1. this.[[value]]를 반환합니다.

6. GamepadTouch 인터페이스

이 인터페이스는 그러한 입력을 지원하는 게임패드의 터치 표면에서의 터치를 정의합니다. 객체는 터치 지점을 고유하게 식별하는 터치 touchId로 구성되며, 이는 입력 매체(예: 손가락, 스타일러스 등)가 터치 장치에 접촉하는 시점부터 입력 매체가 더 이상 터치 장치에 접촉하지 않는 시점까지 유지됩니다.

WebIDLdictionary GamepadTouch {
  unsigned long touchId;
  octet surfaceId;
  DOMPointReadOnly position;
  DOMRectReadOnly? surfaceDimensions;
};
touchId 속성
터치의 고유 ID입니다. 범위는 [0 .. 4294967295]입니다.
surfaceId 속성
터치를 생성한 표면의 고유 ID입니다.
position 속성
터치의 x, y 좌표를 보관하는 DOMPointReadOnly입니다. z와 w 값은 현재 사용되지 않습니다. 각 좌표의 범위는 [-1 .. 1]로 정규화됩니다. x축에서 -1은 가장 왼쪽 좌표를 가리키고 1은 가장 오른쪽 좌표를 가리킵니다. y축에서 -1은 가장 위쪽 좌표를 가리키고 1은 가장 아래쪽 좌표를 가리킵니다.
surfaceDimensions 속성
터치 표면의 widthheight로 정수 단위에서 초기화된 DOMRectReadOnly입니다. 사용할 수 없으면 null입니다.

7. GamepadMappingType 열거형

이 열거형은 Gamepad에 대해 알려진 매핑 집합을 정의합니다.

WebIDLenum GamepadMappingType {
  "",
  "standard",
  "xr-standard",
};
""
빈 문자열은 이 게임패드에 사용 중인 매핑이 없음을 나타냅니다.
"standard"
Gamepad의 컨트롤이 Standard Gamepad 배치에 매핑되었습니다.
"xr-standard"
Gamepad의 컨트롤이 "xr-standard" gamepad mapping에 매핑되었습니다. 이 매핑은 WebXR Gamepads Module - Level 1에서 사용하기 위해 예약되어 있습니다. Gamepad 객체 중 getGamepads()가 반환하는 것은 "xr-standard"의 mapping을 보고해서는 MUST NOT 됩니다.

8. GamepadHapticActuator 인터페이스

GamepadHapticActuator는 햅틱 피드백을 목적으로 힘을 가할 수 있는 모터 또는 기타 액추에이터의 구성에 대응합니다.

WebIDL[Exposed=Window]
interface GamepadHapticActuator {
  [SameObject] readonly attribute FrozenArray<GamepadHapticEffectType> effects;
  Promise<GamepadHapticsResult> playEffect(
      GamepadHapticEffectType type,
      optional GamepadEffectParameters params = {}
  );
  Promise<GamepadHapticsResult> reset();
};

GamepadHapticActuator 인스턴스는 다음 표에 설명된 내부 슬롯으로 생성됩니다:

내부 슬롯 초기값 설명
[[effects]] GamepadHapticEffectType의 빈 list. 액추에이터가 지원하는 효과를 나타냅니다.
[[playingEffectPromise]] null 어떤 효과를 재생하기 위한 Promise, 또는 재생 중인 효과가 없으면 null.
effects 속성

액추에이터가 지원하는 모든 햅틱 효과 유형을 나타내는 GamepadHapticEffectType 값의 배열입니다. 이 속성은 사용자 에이전트가 해당 유형의 효과 재생을 지원하지 않는 경우가 아니라면, 액추에이터가 지원하는 GamepadHapticEffectType 값을 나열합니다.

effects getter 단계는 다음과 같습니다:

  1. this.[[effects]]를 반환합니다.
playEffect() 메서드

GamepadHapticEffectType typeGamepadEffectParameters params와 함께 호출되는 playEffect() 메서드 단계는 다음과 같습니다:

  1. paramstype 유형의 유효한 효과를 설명하지 않으면, TypeError거부된 promise를 반환합니다.
  2. document현재 설정 객체관련 전역 객체연결된 Document로 둡니다.
  3. documentnull이거나, document완전히 활성 상태가 아니거나, document가시성 상태"hidden"이면, "InvalidStateError" DOMException으로 거부된 promise를 반환합니다.
  4. this.[[playingEffectPromise]]null이 아니면:
    1. effectPromisethis.[[playingEffectPromise]]로 둡니다.
    2. this.[[playingEffectPromise]]null로 설정합니다.
    3. 전역 태스크를 큐에 넣습니다. 이 태스크는 this관련 전역 객체와 함께 게임패드 태스크 소스에 넣어, effectPromise를 "preempted"로 resolve합니다.
  5. this GamepadHapticActuatortype유형으로 효과를 재생할 수 없으면, 이유 NotSupportedError거부된 promise를 반환합니다.
  6. [[playingEffectPromise]]새 promise로 둡니다.
  7. playEffectTimestampdocument관련 전역 객체가 주어진 현재 고해상도 시간으로 둡니다.
  8. 다음 단계를 병렬로 수행합니다:
    1. type, params, 그리고 playEffectTimestamp를 사용하여 액추에이터에 햅틱 효과를 발행합니다.
    2. 효과가 완료될 때, this.[[playingEffectPromise]]null이 아니면, this관련 전역 객체와 함께 게임패드 태스크 소스전역 태스크를 큐에 넣어 다음 단계를 실행합니다:
      1. this.[[playingEffectPromise]]null이면, 이 단계를 중단합니다.
      2. this.[[playingEffectPromise]]를 "complete"로 resolve합니다.
      3. this.[[playingEffectPromise]]null로 설정합니다.
  9. [[playingEffectPromise]]를 반환합니다.
reset() 메서드

reset() 메서드 단계는 다음과 같습니다:

  1. document현재 설정 객체관련 전역 객체연결된 Document로 둡니다.
  2. documentnull이거나, document완전히 활성 상태가 아니거나, document가시성 상태"hidden"이면, "InvalidStateError" DOMException으로 거부된 promise를 반환합니다.
  3. resetResultPromise새 promise로 둡니다.
  4. this.[[playingEffectPromise]]null이 아니면, 다음 단계를 병렬로 수행합니다:
    1. effectPromisethis.[[playingEffectPromise]]로 둡니다.
    2. this의 게임패드 액추에이터에서 햅틱 효과를 중지합니다.
    3. 효과가 성공적으로 중지되면, 다음을 수행합니다:
      1. effectPromisethis.[[playingEffectPromise]]가 여전히 같으면, this.[[playingEffectPromise]]null로 설정합니다.
      2. this관련 전역 객체와 함께 게임패드 태스크 소스전역 태스크를 큐에 넣어, effectPromise를 "preempted"로 resolve합니다.
    4. resetResultPromise를 "complete"로 Resolve합니다
  5. resetResultPromise를 반환합니다.

GamepadHapticActuatortype[[effects]] list에서 발견될 수 있으면, type으로 효과를 재생할 수 있습니다.

GamepadHapticEffectType typeGamepadEffectParameters params를 갖는 효과가 유효한 효과를 설명하는지 확인하려면, 다음 단계를 실행합니다:

  1. GamepadHapticEffectType type의 값이 주어지면, 다음에 따라 분기합니다:
    "dual-rumble"
    params유효한 dual-rumble 효과를 설명하지 않으면, false를 반환합니다.
    "trigger-rumble"
    params유효한 trigger-rumble 효과를 설명하지 않으면, false를 반환합니다.
  2. true를 반환합니다

액추에이터에서 햅틱 효과를 발행하려면, 사용자 에이전트는 장치에 type의 효과를 렌더링하도록 명령을 보내고, 제공된 params를 사용하게 하려고 해야 MUST 합니다. 사용자 에이전트params.startDelay0.0이 아닐 때 더 정확한 재생 타이밍을 위해 제공된 playEffectTimestamp를 사용하는 것이 SHOULD입니다. 사용자 에이전트는 호환성을 높이기 위해 효과를 수정할 MAY 있습니다. 예를 들어 럼블 모터용으로 의도된 효과는 럼블 모터는 없지만 파형 기반 햅틱을 지원하는 장치에 대해 파형 기반 효과로 변환될 수 있습니다.

액추에이터에서 햅틱 효과를 중지하려면, 사용자 에이전트는 현재 재생 중인 모든 효과를 중단하도록 장치에 명령을 보내야 MUST 합니다. 햅틱 효과가 중단된 경우, 액추에이터는 가능한 한 빨리 움직임이 없는 상태로 돌아가는 것이 SHOULD입니다.

8.1 가시성 변경 처리

document가시성 상태"hidden"이 되면, 각 GamepadHapticActuator actuator에 대해 다음 단계를 실행합니다:

  1. actuator.[[playingEffectPromise]]null이면, 이 단계를 중단합니다.
  2. actuator관련 전역 객체와 함께 게임패드 태스크 소스전역 태스크를 큐에 넣어 다음 단계를 실행합니다:
    1. actuator.[[playingEffectPromise]]null이면, 이 단계를 중단합니다.
    2. actuator.[[playingEffectPromise]]를 "preempted"로 Resolve합니다.
    3. actuator.[[playingEffectPromise]]null로 설정합니다.
  3. actuator에서 햅틱 효과를 중지합니다.

8.2 GamepadHapticActuator 생성

Gamepad의 기본 진동 액추에이터를 나타내는 gamepadHapticActuator는 다음 단계를 수행하여 생성됩니다:

  1. gamepadHapticActuator를 새로 생성된 GamepadHapticActuator 인스턴스로 둡니다.
  2. supportedEffectsList를 빈 list로 둡니다.
  3. GamepadHapticEffectType의 각 열거형 값 type에 대해, 사용자 에이전트가 해당 액추에이터에서 그 유형의 효과를 시작하도록 명령을 보낼 수 있으면, typesupportedEffectsList에 추가합니다.
  4. gamepadHapticActuator.[[effects]]supportedEffectsList로 설정합니다.

9. GamepadHapticsResult 열거형

WebIDLenum GamepadHapticsResult {
  "complete",
  "preempted"
};
complete

햅틱 효과의 재생이 완료되었습니다.

preempted

현재 효과가 다른 효과에 의해 중지되었거나 대체되었습니다(즉, "선점됨").

10. GamepadHapticEffectType 열거형

효과 유형은 액추에이터가 효과 매개변수를 해석하는 방식을 정의합니다.

WebIDLenum GamepadHapticEffectType {
  "dual-rumble",
  "trigger-rumble"
};
"dual-rumble" 효과 유형

"dual-rumble"은 표준 게임패드의 각 손잡이에 편심 회전 질량(ERM) 진동 모터가 있는 햅틱 구성을 설명합니다. 이 구성에서는 어느 모터든 전체 게임패드를 진동시킬 수 있습니다. 각 모터가 만드는 진동 효과는 서로 달라서 각각의 효과를 결합하여 더 복잡한 햅틱 효과를 만들 수 있습니다.

"dual-rumble" 효과는 이 유형의 액추에이터를 위한 고정 지속 시간, 일정 강도의 진동 효과입니다. "dual-rumble" 효과는 startDelay, duration, strongMagnitude, 그리고 weakMagnitude로 정의되며, 모두 기본값이 0이므로 필수는 아닙니다.

strongMagnitudeweakMagnitude는 저주파 및 고주파 진동에 대한 강도 수준을 설정하며, [0 .. 1] 범위로 정규화되고 기본값은 0입니다.

GamepadEffectParameters params가 주어졌을 때, 유효한 dual-rumble 효과유효한 duration, 유효한 startDelay를 가져야 하며, strongMagnitudeweakMagnitude는 모두 [0 .. 1] 범위 안에 있어야 합니다.

"trigger-rumble" 효과 유형

"trigger-rumble"은 "dual-rumble"에 사용되는 두 손잡이 모터에 더해, Standard Gamepad의 아래쪽 전면 버튼 (정규 인덱스 6 및 7을 가진 버튼) 각각에 진동 모터가 있는 햅틱 구성을 설명합니다. 이러한 버튼은 가장 흔히 스프링 장착 트리거 형태를 취합니다. 이 구성에서는 어느 모터든 버튼 표면에 국소적 햅틱 피드백을 제공할 수 있습니다.

"trigger-rumble" 효과는 이 유형의 액추에이터를 위한 고정 지속 시간, 일정 강도의 진동 효과입니다. "trigger-rumble" 효과는 startDelay, duration, strongMagnitude, weakMagnitude, leftTrigger, 그리고 rightTrigger로 정의되며, 모두 기본값이 0이므로 필수는 아닙니다.

startDelay, duration, strongMagnitude, weakMagnitude는 "dual-rumble"과 같은 정의를 공유합니다. leftTriggerrightTrigger는 각각 왼쪽 및 오른쪽 아래쪽 전면 버튼 진동의 강도 수준을 설정하며, [0 .. 1] 범위로 정규화되고 기본값은 0입니다.

GamepadEffectParameters params가 주어졌을 때, 유효한 trigger-rumble 효과유효한 duration, 유효한 startDelay를 가져야 하며, strongMagnitude, weakMagnitude, leftTrigger, 그리고 rightTrigger는 [0 .. 1] 범위 안에 있어야 합니다.

11. GamepadEffectParameters 사전

GamepadEffectParameters 사전은 햅틱 효과에서 사용하는 매개변수에 대한 키를 포함합니다. 각 키의 의미는 햅틱 효과에 의해 정의되며, 일부 키는 사용되지 않을 수 있습니다.

원치 않는 장시간 실행 효과를 완화하기 위해, 사용자 에이전트유효한 효과에 대해 전체 효과 지속 시간을 어떤 최대 지속 시간으로 제한할 MAY 수 있습니다. 사용자 에이전트가 최대 5초를 사용하는 것이 RECOMMENDED됩니다.

WebIDLdictionary GamepadEffectParameters {
    unsigned long long duration = 0;
    unsigned long long startDelay = 0;
    double strongMagnitude = 0.0;
    double weakMagnitude = 0.0;
    double leftTrigger = 0.0;
    double rightTrigger = 0.0;
};
duration 멤버
duration은 진동 효과의 지속 시간을 밀리초 단위로 설정합니다.
startDelay 멤버
startDelayplayEffect()가 호출된 뒤 진동이 시작될 때까지의 지연 시간을 밀리초 단위로 설정합니다. 지연 구간 동안 액추에이터는 진동하지 않는 것이 SHOULD NOT입니다.
strongMagnitude 멤버
"dual-rumble" 또는 "trigger-rumble" 효과에서 저주파 럼블에 대한 진동 크기입니다.
weakMagnitude 멤버
"dual-rumble" 또는 "trigger-rumble" 효과에서 고주파 럼블에 대한 진동 크기입니다.
leftTrigger 멤버
"trigger-rumble" 효과에서 아래쪽 왼쪽 전면 버튼(정규 인덱스 6) 럼블에 대한 진동 크기입니다.
rightTrigger 멤버
"trigger-rumble" 효과에서 아래쪽 오른쪽 전면 버튼 (정규 인덱스 7) 럼블에 대한 진동 크기입니다.

12. Navigator 인터페이스 확장

WebIDL[Exposed=Window]
partial interface Navigator {
  sequence<Gamepad?> getGamepads();
};

Navigator 인스턴스는 다음 표에 설명된 내부 슬롯으로 생성됩니다:

내부 슬롯 초기값 설명(비규범적)
[[hasGamepadGesture]] false 게임패드 사용자 제스처가 관찰되었음을 나타내는 플래그
[[gamepads]] Gamepad? 객체의 빈 sequence Gamepad는 그 index 속성이 지정한 인덱스에 존재하거나, 할당되지 않은 인덱스에는 null이 있습니다.

12.1 getGamepads() 메서드

참고

getGamepads()에서 반환되는 게임패드 상태는 gamepaddisconnected 또는 gamepadconnected 이벤트가 발송된 뒤에야 연결 해제 또는 연결을 반영합니다.

참고

지문 채취를 완화하기 위해, getGamepads()게임패드 사용자 제스처가 관찰되기 전에는 빈 list를 반환합니다. [FINGERPRINTING-GUIDANCE]

getGamepads() 메서드 단계는 다음과 같습니다:

  1. doc현재 전역 객체연결된 Document로 둡니다.
  2. docnull이거나 doc완전히 활성 상태가 아니면, 빈 list를 반환합니다.
  3. doc"gamepad" 권한을 사용하도록 허용되지 않은 경우, "SecurityError" DOMExceptionthrow하고 이 단계를 중단합니다.
  4. this.[[hasGamepadGesture]]false이면 빈 list를 반환합니다.
  5. now현재 전역 객체가 주어진 현재 고해상도 시간으로 둡니다.
  6. gamepads를 빈 list로 둡니다.
  7. 각각에 대해, this.[[gamepads]]의 각 gamepad에 대해:
    1. gamepadnull이 아니고 gamepad.[[exposed]]false이면:
      1. gamepad.[[exposed]]true로 설정합니다.
      2. gamepad.[[timestamp]]now로 설정합니다.
    2. gamepadgamepads추가합니다.
  8. gamepads를 반환합니다.

현재 입력 상태가 사용자가 현재 게임패드와 상호작용하고 있음을 나타내면, gamepad게임패드 사용자 제스처를 포함합니다. 사용자 에이전트는 입력 상태가 게임패드 사용자 제스처를 포함하는지 확인하는 알고리즘을 제공해야 MUST 합니다. 중립 기본값을 지원하고 pressedfalse를 적어도 한 번 보고한 버튼의 경우, pressedtrue는 상호작용으로 간주하는 것이 SHOULD입니다. 버튼이 중립 기본값을 지원하지 않으면 (예를 들어 토글 스위치), pressedtrue는 상호작용으로 간주하지 않는 것이 SHOULD NOT입니다. 버튼이 pressedfalse를 한 번도 보고한 적이 없다면, 그것은 상호작용으로 간주하지 않는 것이 SHOULD NOT입니다. 축 움직임은 축이 중립 기본값을 지원하고, 현재 중립으로부터의 변위가 사용자 에이전트가 선택한 임계값보다 크며, 그 축이 임계값 아래의 값을 적어도 한 번 보고했다면 상호작용으로 간주하는 것이 SHOULD입니다. 축이 중립 기본값을 지원하지 않거나(예를 들어 자동으로 중앙으로 돌아오지 않는 조이스틱의 축), 축이 축 제스처 임계값 아래의 값을 한 번도 보고하지 않았다면, 그 축은 상호작용을 확인할 때 고려하지 않는 것이 SHOULD NOT입니다. 축 제스처 임계값은 임의의 지터가 상호작용으로 간주되지 않을 만큼 충분히 큰 것이 SHOULD입니다.

13. GamepadEvent 인터페이스

WebIDL[Exposed=Window]

interface GamepadEvent: Event {
  constructor(DOMString type, GamepadEventInit eventInitDict);
  [SameObject] readonly attribute Gamepad gamepad;
};
gamepad 속성
gamepad 속성은 이 이벤트와 연결된 게임패드 데이터에 대한 접근을 제공합니다.

13.1 GamepadEventInit 사전

WebIDLdictionary GamepadEventInit : EventInit {
  required Gamepad gamepad;
};
gamepad 멤버
이 이벤트와 연결된 Gamepad입니다.

14. 재매핑

각 장치 제조사는 많은 서로 다른 제품을 만들며, 각각 고유한 스타일과 버튼 및 축 배치를 가집니다. 사용자 에이전트는 가능한 한 이러한 장치를 많이 지원하도록 의도되어 있습니다.

또한 게임 콘솔에 의해 널리 쓰이게 된 사실상 표준 배치도 있습니다. 사용자 에이전트가 연결된 장치를 인식하면, 가능할 때 이를 정규 순서로 재매핑하는 것이 RECOMMENDED됩니다. 인식되지 않는 장치는 여전히 원시 형태로 노출되어야 합니다.

현재 하나의 정규 배치, 즉 Standard Gamepad가 있습니다. 재매핑할 때 axesbuttons의 인덱스는 아래 도표의 물리적 위치와 가능한 한 가깝게 대응해야 합니다. 또한 mapping은 "standard"로 설정되는 것이 SHOULD입니다.

Standard Gamepad 버튼은 네 개의 버튼으로 이루어진 왼쪽 클러스터, 네 개의 버튼으로 이루어진 오른쪽 클러스터, 세 개의 버튼으로 이루어진 중앙 클러스터, 그리고 게임패드의 왼쪽과 오른쪽 측면에 있는 한 쌍의 전면 버튼으로 배치됩니다. "Standard Gamepad"의 네 축은 왼쪽과 오른쪽에 하나씩 있는 한 쌍의 아날로그 스틱과 연결됩니다. 다음 표는 버튼/축과 그 물리적 위치를 설명합니다.

축 입력이 엄지스틱 축의 입력 값을 보고하고, 엄지스틱이 해당 Standard Gamepad 엄지스틱과 대략 같은 위치에 있으며, 축의 방향(상하 또는 좌우)이 Standard Gamepad 축의 방향과 일치하면, 그 축 입력은 Standard Gamepad 축을 나타냅니다. 같은 Standard Gamepad 축을 나타내는 축이 여러 개 있으면, 사용자 에이전트는 그중 하나를 Standard Gamepad 축으로 선택하고 다른 축에는 다른 인덱스를 할당하는 것이 SHOULD입니다.

버튼 입력이 버튼 또는 트리거의 입력 값을 보고하고, 그 버튼 또는 트리거가 해당 Standard Gamepad 버튼과 대략 같은 위치에 있으면, 그 버튼 입력은 Standard Gamepad 버튼을 나타냅니다.

축 또는 버튼 입력이 Standard Gamepad 축 또는 버튼을 나타내면, 그 정규 인덱스는 해당 Standard Gamepad 축 또는 버튼의 인덱스입니다.

유형 인덱스 위치
버튼 0 오른쪽 클러스터의 아래쪽 버튼
1 오른쪽 클러스터의 오른쪽 버튼
2 오른쪽 클러스터의 왼쪽 버튼
3 오른쪽 클러스터의 위쪽 버튼
4 왼쪽 위 전면 버튼
5 오른쪽 위 전면 버튼
6 왼쪽 아래 전면 버튼
7 오른쪽 아래 전면 버튼
8 중앙 클러스터의 왼쪽 버튼
9 중앙 클러스터의 오른쪽 버튼
10 왼쪽 스틱 눌림 버튼
11 오른쪽 스틱 눌림 버튼
12 왼쪽 클러스터의 위쪽 버튼
13 왼쪽 클러스터의 아래쪽 버튼
14 왼쪽 클러스터의 왼쪽 버튼
15 왼쪽 클러스터의 오른쪽 버튼
16 중앙 클러스터의 중앙 버튼
0 왼쪽 스틱의 수평 축(음수는 왼쪽/양수는 오른쪽)
1 왼쪽 스틱의 수직 축(음수는 위/양수는 아래)
2 오른쪽 스틱의 수평 축(음수는 왼쪽/양수는 오른쪽)
3 오른쪽 스틱의 수직 축(음수는 위/양수는 아래)
그림 1 Standard Gamepad 배치의 시각적 표현.

14.1 지문 채취 완화

Gamepad 객체의 기능을 검사하는 것은 능동적 지문 채취 수단으로 사용될 수 있습니다. 사용자 에이전트는 지문 채취 표면을 줄이기 위해 API를 통해 노출되는 장치 정보를 변경할 MAY 있습니다. 예를 들어, 연결된 장치에 더 많거나 더 적은 입력이 있더라도 구현은 Gamepad 객체가 Standard Gamepad 배치에 정의된 정확한 수의 버튼과 축을 갖도록 요구할 수 있습니다. [FINGERPRINTING-GUIDANCE]

15. 사용 예제

이 절은 비규범적입니다.

아래 예제는 게임패드에 대한 일반적인 접근을 보여줍니다. requestAnimationFrame() 메서드와의 관계에 유의하십시오.

function runAnimation() {
    window.requestAnimationFrame(runAnimation);
    for (const pad of navigator.getGamepads()) {
      // todo; simple demo of displaying pad.axes and pad.buttons
      console.log(pad);
    }
}

window.requestAnimationFrame(runAnimation);
모범 사례 1: requestAnimationFrame()와의 조정

대화형 애플리케이션은 일반적으로 requestAnimationFrame() 메서드를 사용하여 애니메이션을 구동하며, 애니메이션을 사용자 게임패드 입력과 조정하고자 합니다. 따라서 게임패드 데이터는 애니메이션 콜백이 실행되기 직전에 가능한 한 가깝게, 그리고 애니메이션과 일치하는 빈도로 폴링되어야 합니다. 즉, 애니메이션 콜백이 60Hz로 실행되고 있다면, 게임패드 입력도 같은 비율로 샘플링되어야 합니다.

16. gamepadconnected 이벤트

게임패드가 시스템에서 사용 가능하게 되면, 다음 단계를 실행합니다:

  1. document현재 전역 객체연결된 Document로 둡니다; 그렇지 않으면 null.
  2. documentnull이 아니고 "gamepad" 권한을 사용하도록 허용되지 않았으면, 이 단계를 중단합니다.
  3. 전역 태스크를 큐에 넣습니다. 이 태스크는 현재 전역 객체와 함께 게임패드 태스크 소스에 넣어 다음 단계를 수행합니다:
    1. gamepad를 게임패드를 나타내는 Gamepad로 둡니다.
    2. navigatorgamepad관련 전역 객체Navigator 객체로 둡니다.
    3. navigator.[[gamepads]][gamepad.index]를 gamepad로 설정합니다.
    4. navigator.[[hasGamepadGesture]]true이면:
      1. gamepad.[[exposed]]true로 설정합니다.
      2. documentnull이 아니고 완전히 활성 상태이면, 이벤트를 발송합니다. 이벤트 이름은 gamepadconnected이고, 대상은 gamepad관련 전역 객체이며, GamepadEvent를 사용하고 그 gamepad 속성을 gamepad로 초기화합니다.

이 명세를 구현하는 사용자 에이전트gamepadconnected라는 이름의 새 DOM 이벤트를 제공해야 합니다. 해당 이벤트는 GamepadEvent 유형이어야 MUST 하며, Window 객체에서 발송되어야 MUST 합니다.

사용자 에이전트는 사용자가 게임패드를 연결했음을 나타내기 위해 이 이벤트 유형을 발송해야 MUST 합니다. 페이지가 로드될 때 게임패드가 이미 연결되어 있었다면, 사용자가 버튼을 누르거나 축을 움직일 때 gamepadconnected 이벤트가 발송되는 것이 SHOULD입니다.

17. gamepaddisconnected 이벤트

게임패드가 시스템에서 사용 불가 상태가 되면, 다음 단계를 실행합니다:

  1. gamepad를 사용 불가 장치를 나타내는 Gamepad로 둡니다.
  2. gamepad관련 전역 객체와 함께 전역 태스크를 큐에 넣습니다. 이 태스크는 게임패드 태스크 소스에 넣어 다음 단계를 수행합니다:
    1. gamepad.[[connected]]false로 설정합니다.
    2. documentgamepad관련 전역 객체연결된 Document로 둡니다; 그렇지 않으면 null.
    3. gamepad.[[exposed]]true이고 documentnull이 아니며 완전히 활성 상태이면, 이벤트를 발송합니다. 이벤트 이름은 gamepaddisconnected이고, 대상은 gamepad관련 전역 객체이며, GamepadEvent를 사용하고 그 gamepad 속성을 gamepad로 초기화합니다.
    4. navigatorgamepad관련 전역 객체Navigator 객체로 둡니다.
    5. navigator.[[gamepads]][gamepad.index]를 null로 설정합니다.
    6. navigator.[[gamepads]]비어 있지 않고, navigator.[[gamepads]]의 마지막 항목null인 동안, navigator.[[gamepads]]의 마지막 항목제거합니다.

이 명세를 구현하는 사용자 에이전트gamepaddisconnected라는 이름의 새 DOM 이벤트를 제공해야 합니다. 해당 이벤트는 GamepadEvent 유형이어야 MUST 하며, Window 객체에서 발송되어야 MUST 합니다.

게임패드가 사용자 에이전트에서 연결 해제될 때, 사용자 에이전트가 이전에 해당 게임패드에 대해 gamepadconnected 이벤트를 Window에 발송한 적이 있으면, gamepaddisconnected 이벤트는 같은 Window에 발송되어야 MUST 합니다.

18. 기타 이벤트

축 및 버튼 변경 이벤트를 포함할지 제외할지, 그리고 이를 더 함께 묶을지("gamepadchanged"?), 어느 정도 분리할지("gamepadaxischanged"?), 또는 개별 축과 버튼별로 분리할지에 대해 더 많은 논의가 필요합니다.

19. WindowEventHandlers 인터페이스 믹스인 확장

이 명세는 이벤트 핸들러 등록을 용이하게 하기 위해 HTML의 WindowEventHandlers 인터페이스 믹스인을 확장하여 이벤트 핸들러 IDL 속성을 추가합니다.

WebIDLpartial interface mixin WindowEventHandlers {
  attribute EventHandler ongamepadconnected;
  attribute EventHandler ongamepaddisconnected;
};

20. Permissions Policy와의 통합

이 명세는 문자열 "gamepad"로 식별되는 정책 제어 기능을 정의합니다. 그 기본 허용 목록*입니다.

참고

문서권한 정책은 해당 문서의 어떤 콘텐츠가 getGamepads()에 접근하도록 허용되는지 결정합니다. 어떤 문서에서 비활성화되면, 문서의 어떤 콘텐츠도 getGamepads()사용하도록 허용되지 않으며, gamepadconnectedgamepaddisconnected 이벤트도 발송되지 않습니다.

21. 적합성

비규범적이라고 표시된 절뿐 아니라, 이 명세의 모든 작성 지침, 도표, 예제 및 참고는 비규범적입니다. 이 명세의 그 밖의 모든 것은 규범적입니다.

이 문서의 핵심 단어 MAY, MUST, MUST NOT, RECOMMENDED, SHOULD, 그리고 SHOULD NOT은 여기 표시된 것처럼 모두 대문자로 나타날 때, 그리고 그때에만 BCP 14 [RFC2119] [RFC8174]에 설명된 대로 해석됩니다.

A. 감사의 말

이 절은 비규범적입니다.

다음 사람들이 이 문서의 개발에 기여했습니다.

B. 참고 문헌

B.1 규범 참고 문헌

[dom]
DOM Standard. Anne van Kesteren. WHATWG. Living Standard. URL: https://dom.spec.whatwg.org/
[FINGERPRINTING-GUIDANCE]
Mitigating Browser Fingerprinting in Web Specifications. Nick Doty; Tom Ritter. W3C. 2025년 3월 21일. W3C 워킹 그룹 노트. URL: https://www.w3.org/TR/fingerprinting-guidance/
[geometry-1]
Geometry Interfaces Module Level 1. Simon Pieters; Chris Harrelson. W3C. 2018년 12월 4일. W3C 후보 권고안. URL: https://www.w3.org/TR/geometry-1/
[HR-TIME]
High Resolution Time. Yoav Weiss. W3C. 2024년 11월 7일. W3C 작업 초안. URL: https://www.w3.org/TR/hr-time-3/
[html]
HTML Standard. Anne van Kesteren; Domenic Denicola; Dominic Farolino; Ian Hickson; Philip Jägenstedt; Simon Pieters. WHATWG. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[infra]
Infra Standard. Anne van Kesteren; Domenic Denicola. WHATWG. Living Standard. URL: https://infra.spec.whatwg.org/
[permissions-policy]
Permissions Policy. Ian Clelland. W3C. 2025년 5월 6일. W3C 작업 초안. URL: https://www.w3.org/TR/permissions-policy-1/
[RFC2119]
Key words for use in RFCs to Indicate Requirement Levels. S. Bradner. IETF. 1997년 3월. 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. 2017년 5월. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc8174
[WEBIDL]
Web IDL Standard. Edgar Chen; Timothy Gu. WHATWG. Living Standard. URL: https://webidl.spec.whatwg.org/
[webxr-gamepads-module-1]
WebXR Gamepads Module - Level 1. Brandon Jones; Manish Goregaokar; Rik Cabanier. W3C. 2024년 4월 9일. W3C 작업 초안. URL: https://www.w3.org/TR/webxr-gamepads-module-1/