이 문서에서는 호환되는 Windows 11 호스트에 연결하는 촉각 사용 입력 디바이스에 대한 프로토콜 구현에 대해 자세히 설명합니다. 여기에는 입력 장치의 하드웨어 내에서 촉각 응답을 생성하기 위한 기계적 제약 조건, 전기 제약 조건 또는 구성 요소 선택에 대한 지침이 포함되지 않습니다.
지원되는 디바이스 클래스
Windows 11은 다음과 같은 촉각 사용 입력 디바이스 클래스를 지원합니다.
촉각 터치 패드는 Windows에서 터치 패드 장치 클래스의 확장입니다. 이 구현 가이드는 터치 패드 구현 가이드에 추가하고 터치 패드 디지타이저 내에서 촉각을 구현하는 데 중점을 두므로 촉각 터치 패드는 여기에 포함된 것 외에도 터치 패드 구현 가이드 의 요구 사항을 충족해야 합니다.
촉각 마우스는 Windows에서 마우스 장치 클래스의 확장입니다. 촉각 마우스는 이 설명서에 포함된 요구 사항을 충족해야 합니다.
참고: 촉각 사용 펜 입력 디바이스는 이 문서에서 다루지 않는 특수 디바이스 클래스입니다. 촉각 피드백이 있는 펜 디바이스를 구현하는 방법에 대한 자세한 내용은 촉각 펜 구현 가이드를 참조하세요.
입력 디바이스 촉각 프로토콜 구현
여기에 제시된 정보를 이해할 수 있도록 HID 프로토콜을 잘 이해해야 합니다. HID 프로토콜에 대한 자세한 내용은 다음 리소스를 참조하세요.
촉각 사용이 가능한 입력 디바이스 펌웨어는 이 항목에 설명된 사용량만 보고하면 됩니다. Windows는 펌웨어 및 자체 HID 드라이버를 사용하여 디바이스를 사용하도록 설정하고 Windows 애플리케이션에 디바이스에 대한 액세스 권한을 부여합니다.
지원되는 각 디바이스 클래스에 대한 샘플 설명자는 아래의 샘플 보고서 설명자 섹션에 제공됩니다.
일반적인 지침
이 섹션의 항목은 입력 촉각 디바이스의 모든 클래스에 적용됩니다.
필수 HID 컬렉션
촉각과 관련된 기능은 HID SimpleHapticsController 컬렉션(페이지 0xE, 사용량 0x1)에 포함되어야 합니다.
촉각 터치 패드 디바이스의 경우 이 컬렉션은 Windows Precision Touchpad 최상위 컬렉션의 자식이어야 합니다.
Haptic Mouse 디바이스의 경우 이 컬렉션은 최상위 컬렉션이어야 하며 마우스 최상위 컬렉션의 형제여야 합니다.
Device-Initiated 촉각 피드백
촉각 기능이 있는 입력 장치는 선택적으로 버튼이 눌리거나 놓일 때 응답하여 자체 촉각 피드백을 시작할 수 있습니다.
촉각 터치 패드의 경우 아래의 "촉각 터치 패드 지침" 섹션에서는 촉각 피드백을 시작할 때 사용자가 동작을 사용자 지정할 수 있도록 디바이스가 SET_FEATURE 보고서를 지원하도록 선택하는 방법을 설명합니다.
촉각 마우스는 디바이스 시작 피드백을 트리거할 수 있지만 Windows에는 이 동작을 구성하는 메커니즘이 없습니다.
Host-Initiated 촉각 피드백
촉각 기능이 있는 입력 장치는 호스트가 시작하는 촉각 피드백을 지원할 수 있으며, 열거가 완료된 후 언제든지 발생할 수 있습니다.
촉각 터치 패드 및 마우스는 필요에 따라 호스트 시작 피드백을 지원할 수 있습니다. 촉각 터치 패드의 경우 호스트 시작 피드백이 지원되는 경우 디바이스 시작 피드백 사용자 지정에 대한 SET_FEATURE 보고서도 모두 지원되어야 합니다.
호스트에 의해 시작되는 촉각 피드백을 지원하려면 두 개의 SimpleHapticsController 논리적 자식 컬렉션(페이지 0x0E, 사용량 0x01)이 필요합니다. 이러한 논리 컬렉션은 구현 중인 디바이스 클래스에 대한 기본 SimpleHapticsController 컬렉션의 자식이어야 하며(위의 "필수 HID 컬렉션" 섹션에 설명된 대로) 터치 패드에 대한 디바이스 시작 촉각 피드백의 강도를 구성하는 데 사용되는 컬렉션과 분리되어야 합니다. 이러한 논리적 자식 컬렉션 중 하나는 호스트가 지원되는 파형 및 해당 기간을 쿼리하는 데 사용하는 GET_FEATURE 보고서를 정의해야 합니다. 다른 논리적 자식 컬렉션은 호스트가 촉각을 수동으로 트리거하는 데 사용하는 출력 보고서를 정의해야 합니다.
디바이스는 자동 트리거된 촉각에 대한 지원을 선언하지 않아야 하며 디바이스는 연속 파형을 지원하지 않아야 합니다.
파형
다음 표에서는 호스트에서 촉각 사용 입력 디바이스에 대해 지원하는 파형을 정의합니다. 디바이스에서 지원하는 파형은 서수와 연결됩니다. 파형 사용량 및 기간은 파형 정보 기능 보고서를 통해 호스트에 제공됩니다(아래 참조). 피드백을 트리거할 때 호스트는 수동 트리거 사용에 대한 값으로 원하는 파형의 서수입니다.
필수 및 선택 사항
| 파형 | Description | 페이지 | 아이디 | 필수/선택 |
|---|---|---|---|---|
| None | No-op. 진행 중인 파형의 재생 상태에 영향을 주지 않아야 합니다. | 0x0E | 0x1001 | 필수 |
| 중지 | 진행 중인 파형의 재생을 중지합니다. | 0x0E | 0x1002 | 필수 |
| 호버 | 가리키기를 나타내고 예정된 작업의 가능성을 알리는 데 사용되는 가벼운 펄스 | 0x0E | 0x1008 | 필수 |
| 충돌 | 화면 경계 또는 슬라이더와 스크롤 막대의 끝과의 충돌을 나타내는 데 사용되는 소프트 펄스 | 0x0E | 0x1012 | 필수 |
| 정렬 | 안내선 또는 캔버스 가장자리와의 끌기, 크기 조정 또는 회전 상호 작용 중에 개체 맞춤을 확인하는 선명한 펄스 | 0x0E | 0x1013 | 필수 |
| Step | 슬라이더, 목록 또는 스크러버의 항목을 단계별로 실행하는 데 사용되는 확고한 펄스 | 0x0E | 0x1014 | 필수 |
| 성장하다 | 동작, 전환 또는 지능형 시스템 활동을 전달하는 동적 펄스 | 0x0E | 0x1015 | 필수 |
| 눌러주세요 | 표면 단추를 눌렀음을 확인할 때 디바이스에 의해 트리거되는 촉각 신호입니다. 지원되는 경우 릴리스도 지원되어야 합니다. | 0x0E | 0x1006 | 선택적 |
| 해제 | 표면 단추가 해제되었음을 확인할 때 디바이스에 의해 트리거되는 촉각 신호입니다. 지원되는 경우 Press도 지원되어야 합니다. | 0x0E | 0x1007 | 선택적 |
| 성공 | 사용자에게 작업이 성공했음을 알리는 강력한 촉각 신호 | 0x0E | 0x1009 | 선택적 |
| 오류 | 사용자에게 작업이 실패했거나 오류가 발생했음을 알리는 강력한 촉각 신호 | 0x0E | 0x100A | 선택적 |
금지
다음 파형은 지원되지 않아야 합니다.
| 파형 | 아이디 | 비고 |
|---|---|---|
| 클릭 | 0x1003 | 단추 누름에 대한 기존 촉각 피드백과 혼동을 일으킬 수 있습니다. |
| 버즈 연속 | 0x1004 | 연속 파형은 지원되지 않아야 합니다. |
| 연속 럼블 | 0x1005 | 연속 파형은 지원되지 않아야 합니다. |
| 잉크 연속 | 0x100B | 펜에만 적용됩니다. |
| 연필 연속 | 0x100C | 펜에만 적용됩니다. |
| 표식 연속 | 0x100D | 펜에만 적용됩니다. |
| 끌 표식 연속 | 0x100E | 펜에만 적용됩니다. |
| 브러시 연속 | 0x100F | 펜에만 적용됩니다. |
| 지우개 연속 | 0x1010 | 펜에만 적용됩니다. |
| 스파클 연속 | 0x1011 | 펜에만 적용됩니다. |
파형 정보 기능 보고서
호스트는 지원되는 파형에 대해 디바이스를 쿼리할 때 이 GET_FEATURE 보고서를 실행합니다. 이 기능 보고서에는 전용 보고서 ID가 있어야 합니다.
논리 컬렉션에는 파형 목록과 기간 목록에 대해 하나씩 두 개의 자식 논리 컬렉션이 있어야 합니다. 이러한 컬렉션은 호스트가 각 서수와 연결된 파형 및 기간을 쿼리할 수 있도록 하는 서수 페이지(0x0A)에서 사용 범위를 정의해야 합니다.
필수 및 선택적 사용
| 회원 | Description | 페이지 | 아이디 | 필수/선택 |
|---|---|---|---|---|
| 파형 목록 | 디바이스에서 지원하는 촉각 파형의 순서가 지정된 목록을 포함하는 논리 컬렉션 | 0x0E | 0x10 | 필수 |
| 기간 목록 | 파형 목록의 파형에 대한 순서가 지정된 기간 목록을 포함하는 논리 컬렉션 | 0x0E | 0x11 | 필수 |
파형 목록(필수)
이 컬렉션은 서수와 해당 파형 간의 매핑을 제공합니다. 서수 1과 2는 WAVEFORM_NONE 해당하며 암시적으로 WAVEFORM_STOP 설명자에서 선언할 필요가 없습니다. 따라서 컬렉션 사용 범위의 최소 사용량은 3일 수 있으며 사용량 최대값은 지원되는 모든 파형에 서수가 할당될 만큼 커야 합니다.
사용량 최대값이 디바이스에서 지원하는 파형 수보다 큰 경우 디바이스는 지원되지 않는 서수에 대한 WAVEFORM_NONE 보고해야 합니다.
사용 범위의 논리적 범위에는 지원되는 모든 파형 사용이 포함되어야 합니다. 실제 범위와 단위는 0이어야 합니다.
기간 목록(필수)
이 컬렉션은 파형 목록에 정의된 파형의 기간을 제공합니다. 컬렉션 사용 범위의 최소 및 최대 사용량은 파형 목록의 사용량과 동일해야 합니다.
불연속 파형의 지속 시간은 0이 아니어야 합니다. WAVEFORM_NONE 및 WAVEFORM_STOP 지정된 경우 기간이 0이어야 합니다.
사용 범위의 논리적 최소값은 0이어야 하며 논리 최대값은 최소 가장 긴 불연속 파형의 기간만큼 커야 합니다. 호스트는 논리 값을 밀리초로 처리합니다. 물리적 범위는 0이거나 논리 범위와 동일해야 합니다. 실제 범위와 논리 범위가 일치하는 경우 단위는 밀리초여야 합니다.
수동 트리거 출력 보고서
호스트는 불연속 촉각 피드백을 트리거할 때 이 보고서를 실행합니다. 이 출력 보고서에는 전용 보고서 ID가 있어야 합니다.
필수 및 선택적 사용
| 회원 | Description | 페이지 | 아이디 | 필수/선택 |
|---|---|---|---|---|
| 수동 트리거 | 호스트에서 명시적 명령으로 실행하기 위한 파형 | 0x0E | 0x21 | 필수 |
| 강렬 | 피드백의 강도 | 0x0E | 0x23 | 필수 |
| 반복 횟수 | 초기 재생 후 피드백을 반복할 횟수 | 0x0E | 0x24 | 선택적 |
| Retrigger 기간 | 반복할 때 피드백을 다시 트리거하기 전에 대기하는 기간 | 0x0E | 0x25 | 선택적 |
| 파형 컷오프 시간 | 차단되기 전에 피드백이 재생될 수 있는 최대 시간 | 0x0E | 0x28 | 선택적 |
사용 금지
| Usage | 아이디 | 비고 |
|---|---|---|
| 자동 트리거 | 0x20 | 호스트에서 지원되지 않습니다. |
| 연결된 컨트롤 자동 트리거 | 0x22 | 호스트에서 지원되지 않습니다. |
수동 트리거(필수)
이 사용량에는 호스트에서 재생하도록 요청된 파형 정보 기능 보고서에서 정의된 파형 서수가 포함됩니다. WAVEFORM_NONE 이외의 서수가 포함된 출력 보고서를 디바이스로 보내면 출력 보고서에 포함된 추가 속성(강도, 반복 횟수, Retrigger 기간, 컷오프 시간(지원되는 경우)을 사용하여 지정된 파형 재생을 즉시 시작해야 합니다. 디바이스는 불연속 파형, WAVEFORM_NONE 및 WAVEFORM_STOP 서수만 적용해야 합니다. 서수가 WAVEFORM_STOP 해당하는 경우 진행 중인 불연속 파형 재생을 중지해야 합니다. 서수가 WAVEFORM_NONE 해당하는 경우 아무 작업도 수행해서는 안 되며 지속적인 촉각 피드백은 계속 재생되어야 합니다.
논리 범위에는 암시적 서수 1(WAVEFORM_NONE) 및 2(WAVEFORM_STOP)를 포함하여 가능한 모든 서수가 포함되어야 합니다. 실제 범위와 단위는 0이어야 합니다.
강도(필수)
이 사용량은 요청된 파형에 적용할 최대 강도의 백분율을 나타내며, 논리 최대값은 최대 강도를 나타내고 논리 최소값은 피드백이 전혀 없음을 나타냅니다.
논리적 최소값은 0이어야 하며, 디바이스의 기능에 따라 논리 최대값을 선택해야 합니다. 예를 들어 디바이스가 4단계의 강도를 지원하는 경우 논리 최대값은 4개여야 합니다. 디바이스가 더 세분화된 강도를 지원하는 경우 논리 최대값은 더 클 수 있지만 100을 초과하면 안 됩니다. 디바이스는 최소 논리 최대값이 4개이므로 최소 4단계의 강도를 지원해야 합니다. 강도가 0이면 피드백이 재생되지 않음을 나타내고 호스트는 이 값만 WAVEFORM_STOP 사용합니다.
실제 범위와 단위는 0이어야 합니다.
반복 횟수(선택 사항)
이 사용량은 초기 재생 후 파형을 반복하는 횟수를 나타냅니다. 값이 0이면 파형은 한 번만 재생되어야 합니다.
이 사용이 지원되는 경우 재시도 기간 및 중단 시간 사용도 지원되어야 합니다.
논리 최소값은 0이어야 하며 논리 최대값은 0보다 커야 합니다. 논리 최대값은 작은 값(예: 10)으로 제한해야 합니다. 실제 범위와 단위는 0이어야 합니다.
Retrigger 기간(선택 사항)
이 사용량은 이전 트리거의 시작 시간에서 측정된 파형의 재트리거 사이의 기간을 나타냅니다. 값 0은 파형의 기본 기간과 동일하게 해석되어야 하므로 이전 기간이 완료된 직후에 다시 시도기가 발생합니다. 파형의 기본 기간보다 작은 값은 파형을 중단하고 다시 시작해야 합니다.
이 사용이 지원되는 경우 반복 횟수 및 중단 시간 사용도 지원되어야 합니다.
호스트는 논리 값을 밀리초로 처리합니다. 논리적 최소값은 0이어야 하며 논리 최대값은 1000 이상이어야 합니다(1초 표시). 물리적 범위는 0이거나 논리 범위와 동일해야 합니다. 실제 범위가 0이 아니면 단위는 밀리초여야 합니다.
파형 컷오프 시간(선택 사항)
이 사용량은 반복 횟수 및 재시도 기간을 고려하여 단일 트리거가 재생될 수 있는 최대 시간을 나타냅니다.
이 사용이 지원되는 경우 반복 횟수 및 재트리거 사용도 지원되어야 합니다.
호스트는 논리 값을 밀리초로 처리합니다. 논리적 최소값은 최소 불연속 파형의 지속 시간만큼 커야 하며 반복 횟수 사용량의 논리적 최대값을 곱해야 합니다. 물리적 범위는 0이거나 논리 범위와 동일해야 합니다. 실제 범위가 0이 아니면 단위는 밀리초여야 합니다.
촉각 터치 패드 지침
이 섹션의 항목은 촉각 터치 패드에만 적용됩니다.
Device-Initiated 촉각 피드백
촉각 터치 패드는 터치 패드의 표면 단추를 누르거나 놓았다는 것을 확인할 때 촉각 피드백을 트리거하는 역할을 합니다. SET_FEATURE 보고서를 지원하여 사용자가 동작을 사용자 지정할 수 있도록 선택할 수 있습니다.
- 촉각 피드백의 강도
- 단추 누름을 트리거하는 데 필요한 힘
터치 패드가 호스트 시작 촉각 피드백도 지원하는 경우 이러한 기능 보고서는 모두 필수입니다. 각 보고서는 다른 사용과 함께 사용되지 않는 고유한 보고서 ID를 사용해야 합니다.
열거하는 동안 호스트는 설명자에서 지원되는 논리적 및 물리적 범위를 평가하고 기본값을 포함하여 설정 UI에 대해 노출된 옵션을 계산합니다. 호스트는 사용자가 지정한 값을 디바이스에 전달하기 위해 SET_FEATURE 발급해야 합니다. 이 발급은 언제든지 발생할 수 있지만 설정이 변경될 때마다, 사용자 스위치가 발생하고, 디바이스가 열거되거나 다시 설정될 때 발생합니다.
촉각 강도 기능 보고서
이 SET_FEATURE 보고서는 단추 누르기 및 해제에 대한 촉각 피드백의 강도에 대한 사용자의 기본 설정을 지정합니다. 디바이스에서 지원하는 경우 호스트 시작 피드백의 강도에는 적용되지 않습니다. 이 구성을 지원하려면 디바이스가 전용 보고서 ID가 있는 기능 보고서로 촉각 강도 사용량(페이지 0x0E, 사용량 0x23)을 포함하는 Windows Precision Touchpad 최상위 컬렉션에서 SimpleHapticsController 논리적 자식 컬렉션(페이지 0x0E, 사용량 0x01)을 정의해야 합니다. 이 자식 컬렉션에는 자동 트리거(페이지 0x0E, 사용량 0x20) 또는 수동 트리거(페이지 0x0E, 사용량 0x21) 사용이 포함되어서는 안 됩니다.
논리적 최소값은 0과 같아야 합니다. 사용자의 기본 설정은 논리 범위로 선형적으로 크기가 조정되며, 0은 단추 누르기 및 해제에 대한 피드백이 트리거되지 않음을 나타냅니다.
단추 누르기 임계값 기능 보고서
이 SET_FEATURE 보고서는 단추 누름을 트리거하는 데 필요한 힘의 양에 대한 사용자의 기본 설정을 지정합니다. 이 구성을 지원하려면 장치에서 Windows Precision Touchpad 최상위 컬렉션에 전용 보고서 ID가 있는 기능 보고서로 단추 누름 임계값 사용량(페이지 0x0D, 사용량 0xB0)을 정의해야 합니다.
논리 범위는 실제 값 범위에 선형으로 매핑되며 기본값을 중심으로 균등하게 간격을 지정하고 가운데에 배치해야 합니다. 논리 범위를 가져오면 다음 수식을 사용하여 기본값이 계산됩니다.
논리적 최소값, 기본값 및 논리 최대값은 Windows 설정 UI(각각 "낮음", "보통" 및 "높음" 지원)를 통해 사용자에게 노출되는 3가지 단추 누르기 힘 수준에 해당합니다.
단추 누름 임계값에 권장되는 물리적 범위는 최소값과 최대값 각각에 해당하는 110g에서 190g 사이의 범위를 커버하는 것입니다. 물리적 최대값 190g 및 물리적 최소 110g(따라서 위의 수식에 따라 기본값은 150g)을 활용하는 샘플 설명자는 샘플 보고서 설명자를 참조하세요.
예시 HID 보고서 설명자
샘플 햅틱 터치패드 디스크립터
다음 설명자는 모든 필수 및 선택적 사용을 지원합니다. 5개의 파형에 대한 지원을 선언하며, 가장 긴 기간은 50ms입니다.
모든 논리 범위는 디바이스 지원에 따라 업데이트해야 합니다. 다른 수의 파형을 지원하려면 다음을 수행합니다.
- 수동 트리거 사용의 논리적 범위를 업데이트해야 합니다.
- 웨이브 폼 목록 및 기간 목록에 대한 사용 범위 및 보고서 수를 업데이트해야 합니다.
다른 최대 파형 길이를 지원하려면 다음 논리 범위를 업데이트해야 합니다.
- Retrigger 기간(출력)
- 파형 컷오프 시간(출력)
- 기간 목록(기능)
0x05, 0x0D, // UsagePage(Digitizers[0x000D])
0x09, 0x05, // UsageId(Touch Pad[0x0005])
0xA1, 0x01, // Collection(Application)
0x85, 0x40, // ReportId(64)
0x05, 0x0D, // UsagePage(Digitizers[0x000D])
0x09, 0xB0, // UsageId(Button Press Threshold[0x00B0])
0x35, 0x6E, // PhysicalMinimum(110)
0x46, 0xBE, 0x00, // PhysicalMaximum(190)
0x66, 0x01, 0x01, // Unit('gram', SiLinear, Gram:1)
0x55, 0x00, // UnitExponent(1)
0x15, 0x01, // LogicalMinimum(1)
0x25, 0x03, // LogicalMaximum(3)
0x95, 0x01, // ReportCount(1)
0x75, 0x08, // ReportSize(8)
0xB1, 0x02, // Feature(Data, Variable, Absolute)
0x85, 0x41, // ReportId(65)
0x05, 0x0E, // UsagePage(Haptics[0x000E])
0x09, 0x01, // UsageId(Simple Haptic Controller[0x0001])
0xA1, 0x02, // Collection(Logical)
0x05, 0x0E, // UsagePage(Haptics[0x000E])
0x09, 0x23, // UsageId(Intensity[0x0023])
0x35, 0x00, // PhysicalMinimum(0)
0x45, 0x00, // PhysicalMaximum(0)
0x65, 0x00, // Unit(None)
0x55, 0x00, // UnitExponent(1)
0x15, 0x00, // LogicalMinimum(0)
0x25, 0x04, // LogicalMaximum(4)
0x95, 0x01, // ReportCount(1)
0x75, 0x08, // ReportSize(8)
0xB1, 0x02, // Feature(Data, Variable, Absolute)
0xC0, // EndCollection()
0x85, 0x42, // ReportId(66)
0x05, 0x0E, // UsagePage(Haptics[0x000E])
0x09, 0x01, // UsageId(Simple Haptic Controller[0x0001])
0xA1, 0x02, // Collection(Logical)
0x05, 0x0E, // UsagePage(Haptics[0x000E])
0x09, 0x10, // UsageId(Waveform List[0x0010])
0xA1, 0x02, // Collection(Logical)
0x05, 0x0A, // UsagePage(Ordinal[0x000A])
0x19, 0x03, // UsageIdMin(Instance 3[0x0003])
0x29, 0x07, // UsageIdMax(Instance 7[0x0007])
0x35, 0x00, // PhysicalMinimum(0)
0x45, 0x00, // PhysicalMaximum(0)
0x65, 0x00, // Unit(None)
0x55, 0x00, // UnitExponent(1)
0x16, 0x03, 0x10, // LogicalMinimum(4,099)
0x26, 0xFF, 0x2F, // LogicalMaximum(12,287)
0x95, 0x05, // ReportCount(5)
0x75, 0x10, // ReportSize(16)
0xB1, 0x02, // Feature(Data, Variable, Absolute)
0xC0, // EndCollection()
0x05, 0x0E, // UsagePage(Haptics[0x000E])
0x09, 0x11, // UsageId(Duration List[0x0011])
0xA1, 0x02, // Collection(Logical)
0x05, 0x0A, // UsagePage(Ordinal[0x000A])
0x19, 0x03, // UsageIdMin(Instance 3[0x0003])
0x29, 0x07, // UsageIdMax(Instance 7[0x0007])
0x35, 0x00, // PhysicalMinimum(0)
0x45, 0x32, // PhysicalMaximum(50)
0x66, 0x01, 0x10, // Unit('millisecond', SiLinear, Seconds:1)
0x55, 0x0D, // UnitExponent(0.001)
0x15, 0x00, // LogicalMinimum(0)
0x25, 0x32, // LogicalMaximum(50)
0x95, 0x05, // ReportCount(5)
0x75, 0x08, // ReportSize(8)
0xB1, 0x02, // Feature(Data, Variable, Absolute)
0xC0, // EndCollection()
0xC0, // EndCollection()
0x85, 0x43, // ReportId(67)
0x05, 0x0E, // UsagePage(Haptics[0x000E])
0x09, 0x01, // UsageId(Simple Haptic Controller[0x0001])
0xA1, 0x02, // Collection(Logical)
0x05, 0x0E, // UsagePage(Haptics[0x000E])
0x09, 0x21, // UsageId(Manual Trigger[0x0021])
0x35, 0x00, // PhysicalMinimum(0)
0x45, 0x00, // PhysicalMaximum(0)
0x65, 0x00, // Unit(None)
0x55, 0x00, // UnitExponent(1)
0x15, 0x01, // LogicalMinimum(1)
0x25, 0x07, // LogicalMaximum(7)
0x95, 0x01, // ReportCount(1)
0x75, 0x08, // ReportSize(8)
0x91, 0x02, // Output(Data, Variable, Absolute)
0x05, 0x0E, // UsagePage(Haptics[0x000E])
0x09, 0x23, // UsageId(Intensity[0x0023])
0x35, 0x00, // PhysicalMinimum(0)
0x45, 0x00, // PhysicalMaximum(0)
0x65, 0x00, // Unit(None)
0x55, 0x00, // UnitExponent(1)
0x15, 0x00, // LogicalMinimum(0)
0x25, 0x04, // LogicalMaximum(4)
0x95, 0x01, // ReportCount(1)
0x75, 0x08, // ReportSize(8)
0x91, 0x02, // Output(Data, Variable, Absolute)
0x05, 0x0E, // UsagePage(Haptics[0x000E])
0x09, 0x24, // UsageId(Repeat Count[0x0024])
0x35, 0x00, // PhysicalMinimum(0)
0x45, 0x00, // PhysicalMaximum(0)
0x65, 0x00, // Unit(None)
0x55, 0x00, // UnitExponent(1)
0x15, 0x00, // LogicalMinimum(0)
0x25, 0x05, // LogicalMaximum(5)
0x95, 0x01, // ReportCount(1)
0x75, 0x08, // ReportSize(8)
0x91, 0x02, // Output(Data, Variable, Absolute)
0x05, 0x0E, // UsagePage(Haptics[0x000E])
0x09, 0x25, // UsageId(Retrigger Period[0x0025])
0x35, 0x00, // PhysicalMinimum(0)
0x46, 0xE8, 0x03, // PhysicalMaximum(1,000)
0x66, 0x01, 0x10, // Unit('millisecond', SiLinear, Seconds:1)
0x55, 0x0D, // UnitExponent(0.001)
0x15, 0x00, // LogicalMinimum(0)
0x26, 0xE8, 0x03, // LogicalMaximum(1,000)
0x95, 0x01, // ReportCount(1)
0x75, 0x10, // ReportSize(16)
0x91, 0x02, // Output(Data, Variable, Absolute)
0x05, 0x0E, // UsagePage(Haptics[0x000E])
0x09, 0x28, // UsageId(Waveform Cutoff Time[0x0028])
0x36, 0xE8, 0x03, // PhysicalMinimum(1,000)
0x46, 0x88, 0x13, // PhysicalMaximum(5,000)
0x66, 0x01, 0x10, // Unit('millisecond', SiLinear, Seconds:1)
0x55, 0x0D, // UnitExponent(0.001)
0x16, 0xE8, 0x03, // LogicalMinimum(1,000)
0x26, 0x88, 0x13, // LogicalMaximum(5,000)
0x95, 0x01, // ReportCount(1)
0x75, 0x10, // ReportSize(16)
0x91, 0x02, // Output(Data, Variable, Absolute)
0xC0, // EndCollection()
0xC0, // EndCollection()
위의 설명자는 다음 Waratah 파일을 통해 생성되었습니다.
[[settings]]
packingInBytes = 1
optimize = false
[[unit]]
name = 'millisecond'
second = [0.001, 1.0]
[[applicationCollection]]
usage = ['Digitizers', 'Touch Pad']
# Button press threshold feature report
[[applicationCollection.featureReport]]
id = 0x40
[[applicationCollection.featureReport.variableItem]]
usage = ['Digitizers', 'Button Press Threshold']
logicalValueRange = [1, 3]
physicalValueRange = [110, 190]
unit = 'gram'
# Feedback intensity feature report
[[applicationCollection.featureReport]]
id = 0x41
[[applicationCollection.featureReport.logicalCollection]]
usage = ['Haptics', 'Simple Haptic Controller']
[[applicationCollection.featureReport.logicalCollection.variableItem]]
usage = ['Haptics', 'Intensity']
logicalValueRange = [0, 4]
# Host-initiated waveform information feature report
[[applicationCollection.featureReport]]
id = 0x42
[[applicationCollection.featureReport.logicalCollection]]
usage = ['Haptics', 'Simple Haptic Controller']
[[applicationCollection.featureReport.logicalCollection.logicalCollection]]
usage = ['Haptics', 'Waveform List']
[[applicationCollection.featureReport.logicalCollection.logicalCollection.variableItem]]
usageRange = ['Ordinal', 'Instance 3', 'Instance 7']
logicalValueRange = [0x1003, 0x2FFF]
[[applicationCollection.featureReport.logicalCollection.logicalCollection]]
usage = ['Haptics', 'Duration List']
[[applicationCollection.featureReport.logicalCollection.logicalCollection.variableItem]]
usageRange = ['Ordinal', 'Instance 3', 'Instance 7']
logicalValueRange = [0, 50]
physicalValueRange = [0, 50]
unit = 'millisecond'
# Host-initiated waveform manual trigger output report
[[applicationCollection.outputReport]]
id = 0x43
[[applicationCollection.outputReport.logicalCollection]]
usage = ['Haptics', 'Simple Haptic Controller']
[[applicationCollection.outputReport.logicalCollection.variableItem]]
usage = ['Haptics', 'Manual Trigger']
logicalValueRange = [1, 7]
[[applicationCollection.outputReport.logicalCollection.variableItem]]
usage = ['Haptics', 'Intensity']
logicalValueRange = [0, 4]
[[applicationCollection.outputReport.logicalCollection.variableItem]]
usage = ['Haptics', 'Repeat Count']
logicalValueRange = [0, 5]
[[applicationCollection.outputReport.logicalCollection.variableItem]]
usage = ['Haptics', 'Retrigger Period']
logicalValueRange = [0, 1000]
physicalValueRange = [0, 1000]
unit = 'millisecond'
[[applicationCollection.outputReport.logicalCollection.variableItem]]
usage = ['Haptics', 'Waveform Cutoff Time']
logicalValueRange = [1000, 5000]
physicalValueRange = [1000, 5000]
unit = 'millisecond'
샘플 촉각 마우스 기술서
다음 설명자는 모든 필수 및 선택적 사용을 지원합니다. 8개의 파형에 대한 지원을 선언하며, 가장 긴 기간은 200ms입니다.
모든 논리 범위는 디바이스 지원에 따라 업데이트해야 합니다. 다른 수의 파형을 지원하려면 다음을 수행합니다.
- 수동 트리거 사용의 논리적 범위를 업데이트해야 합니다.
- 웨이브 폼 목록 및 기간 목록에 대한 사용 범위 및 보고서 수를 업데이트해야 합니다.
다른 최대 파형 길이를 지원하려면 다음 논리 범위를 업데이트해야 합니다.
- Retrigger 기간(출력)
- 파형 컷오프 시간(출력)
- 기간 목록(기능)
0x05, 0x01, // UsagePage(Generic Desktop[0x0001])
0x09, 0x02, // UsageId(Mouse[0x0002])
0xA1, 0x01, // Collection(Application)
0x85, 0x01, // ReportId(1)
0x09, 0x01, // UsageId(Pointer[0x0001])
0xA1, 0x00, // Collection(Physical)
0x09, 0x30, // UsageId(X[0x0030])
0x09, 0x31, // UsageId(Y[0x0031])
0x15, 0x80, // LogicalMinimum(-128)
0x25, 0x7F, // LogicalMaximum(127)
0x95, 0x02, // ReportCount(2)
0x75, 0x08, // ReportSize(8)
0x81, 0x06, // Input(Data, Variable, Relative)
0x05, 0x09, // UsagePage(Button[0x0009])
0x19, 0x01, // UsageIdMin(Button 1[0x0001])
0x29, 0x03, // UsageIdMax(Button 3[0x0003])
0x15, 0x00, // LogicalMinimum(0)
0x25, 0x01, // LogicalMaximum(1)
0x95, 0x03, // ReportCount(3)
0x75, 0x01, // ReportSize(1)
0x81, 0x02, // Input(Data, Variable, Absolute)
0xC0, // EndCollection()
0x95, 0x01, // ReportCount(1)
0x75, 0x05, // ReportSize(5)
0x81, 0x03, // Input(Constant, Variable, Absolute)
0xC0, // EndCollection()
0x05, 0x0E, // UsagePage(Haptics[0x000E])
0x09, 0x01, // UsageId(Simple Haptic Controller[0x0001])
0xA1, 0x01, // Collection(Application)
0x85, 0x10, // ReportId(16)
0x09, 0x10, // UsageId(Waveform List[0x0010])
0xA1, 0x02, // Collection(Logical)
0x05, 0x0A, // UsagePage(Ordinal[0x000A])
0x19, 0x03, // UsageIdMin(Instance 3[0x0003])
0x29, 0x0A, // UsageIdMax(Instance 10[0x000A])
0x16, 0x03, 0x10, // LogicalMinimum(4,099)
0x26, 0xFF, 0x2F, // LogicalMaximum(12,287)
0x95, 0x08, // ReportCount(8)
0x75, 0x0E, // ReportSize(14)
0xB1, 0x02, // Feature(Data, Variable, Absolute)
0xC0, // EndCollection()
0x05, 0x0E, // UsagePage(Haptics[0x000E])
0x09, 0x11, // UsageId(Duration List[0x0011])
0xA1, 0x02, // Collection(Logical)
0x05, 0x0A, // UsagePage(Ordinal[0x000A])
0x19, 0x03, // UsageIdMin(Instance 3[0x0003])
0x29, 0x0A, // UsageIdMax(Instance 10[0x000A])
0x46, 0xC8, 0x00, // PhysicalMaximum(200)
0x66, 0x01, 0x10, // Unit('millisecond', SiLinear, Seconds:1)
0x55, 0x0D, // UnitExponent(0.001)
0x15, 0x00, // LogicalMinimum(0)
0x26, 0xC8, 0x00, // LogicalMaximum(200)
0x75, 0x08, // ReportSize(8)
0xB1, 0x02, // Feature(Data, Variable, Absolute)
0xC0, // EndCollection()
0x85, 0x11, // ReportId(17)
0x05, 0x0E, // UsagePage(Haptics[0x000E])
0x09, 0x21, // UsageId(Manual Trigger[0x0021])
0x45, 0x00, // PhysicalMaximum(0)
0x65, 0x00, // Unit(None)
0x55, 0x00, // UnitExponent(1)
0x15, 0x01, // LogicalMinimum(1)
0x25, 0x0A, // LogicalMaximum(10)
0x95, 0x01, // ReportCount(1)
0x75, 0x04, // ReportSize(4)
0x91, 0x02, // Output(Data, Variable, Absolute)
0x09, 0x23, // UsageId(Intensity[0x0023])
0x15, 0x00, // LogicalMinimum(0)
0x25, 0x04, // LogicalMaximum(4)
0x75, 0x03, // ReportSize(3)
0x91, 0x02, // Output(Data, Variable, Absolute)
0x09, 0x24, // UsageId(Repeat Count[0x0024])
0x25, 0x05, // LogicalMaximum(5)
0x91, 0x02, // Output(Data, Variable, Absolute)
0x09, 0x25, // UsageId(Retrigger Period[0x0025])
0x46, 0xE8, 0x03, // PhysicalMaximum(1,000)
0x66, 0x01, 0x10, // Unit('millisecond', SiLinear, Seconds:1)
0x55, 0x0D, // UnitExponent(0.001)
0x26, 0xE8, 0x03, // LogicalMaximum(1,000)
0x75, 0x0A, // ReportSize(10)
0x91, 0x02, // Output(Data, Variable, Absolute)
0x09, 0x28, // UsageId(Waveform Cutoff Time[0x0028])
0x36, 0xE8, 0x03, // PhysicalMinimum(1,000)
0x46, 0x88, 0x13, // PhysicalMaximum(5,000)
0x16, 0xE8, 0x03, // LogicalMinimum(1,000)
0x26, 0x88, 0x13, // LogicalMaximum(5,000)
0x75, 0x0D, // ReportSize(13)
0x91, 0x02, // Output(Data, Variable, Absolute)
0x75, 0x07, // ReportSize(7)
0x91, 0x03, // Output(Constant, Variable, Absolute)
0xC0, // EndCollection()
위의 설명자는 다음 Waratah 파일을 통해 생성되었습니다.
[[unit]]
name = 'millisecond'
second = [0.001, 1.0]
[[applicationCollection]]
usage = ['Generic Desktop', 'Mouse']
# Mouse
[[applicationCollection.inputReport]]
[[applicationCollection.inputReport.physicalCollection]]
usage = ['Generic Desktop', 'Pointer']
[[applicationCollection.inputReport.physicalCollection.variableItem]]
usage = ['Generic Desktop', 'X']
sizeInBits = 8
logicalValueRange = 'maxSignedSizeRange'
reportFlags = ['relative']
[[applicationCollection.inputReport.physicalCollection.variableItem]]
usage = ['Generic Desktop', 'Y']
sizeInBits = 8
logicalValueRange = 'maxSignedSizeRange'
reportFlags = ['relative']
[[applicationCollection.inputReport.physicalCollection.variableItem]]
usageRange = ['Button', 'Button 1', 'Button 3']
logicalValueRange = [0, 1]
[[applicationCollection]]
usage = ['Haptics', 'Simple Haptic Controller']
# Host-initiated waveform information feature report
[[applicationCollection.featureReport]]
id = 0x10
[[applicationCollection.featureReport.logicalCollection]]
usage = ['Haptics', 'Waveform List']
[[applicationCollection.featureReport.logicalCollection.variableItem]]
usageRange = ['Ordinal', 'Instance 3', 'Instance 10']
logicalValueRange = [0x1003, 0x2FFF]
[[applicationCollection.featureReport.logicalCollection]]
usage = ['Haptics', 'Duration List']
[[applicationCollection.featureReport.logicalCollection.variableItem]]
usageRange = ['Ordinal', 'Instance 3', 'Instance 10']
logicalValueRange = [0, 200]
physicalValueRange = [0, 200]
unit = 'millisecond'
# Host-initiated waveform manual trigger output report
[[applicationCollection.outputReport]]
id = 0x11
[[applicationCollection.outputReport.variableItem]]
usage = ['Haptics', 'Manual Trigger']
logicalValueRange = [1, 10]
[[applicationCollection.outputReport.variableItem]]
usage = ['Haptics', 'Intensity']
logicalValueRange = [0, 4]
[[applicationCollection.outputReport.variableItem]]
usage = ['Haptics', 'Repeat Count']
logicalValueRange = [0, 5]
[[applicationCollection.outputReport.variableItem]]
usage = ['Haptics', 'Retrigger Period']
logicalValueRange = [0, 1000]
physicalValueRange = [0, 1000]
unit = 'millisecond'
[[applicationCollection.outputReport.variableItem]]
usage = ['Haptics', 'Waveform Cutoff Time']
logicalValueRange = [1000, 5000]
physicalValueRange = [1000, 5000]
unit = 'millisecond'