Przewodnik implementacji haptyki urządzenia wejściowego

Ten dokument zawiera szczegółowe informacje na temat implementacji protokołu dla haptycznych urządzeń wejściowych łączących się z zgodnym hostem Windows 11. Nie obejmuje to wskazówek dotyczących ograniczeń mechanicznych, ograniczeń elektrycznych ani wyboru składników do generowania odpowiedzi haptycznej w sprzęcie urządzenia wejściowego.

Obsługiwane klasy urządzeń

Windows 11 obsługuje następujące klasy urządzeń wejściowych z obsługą haptyki:

  • Haptic Touchpad to rozszerzenie klasy urządzenia Touchpad w Windows. Ten przewodnik implementacji stanowi uzupełnienie Przewodnika Implementacji Touchpad i skupia się na implementacji haptyki w digitalizatorze touchpada, więc dotykowe panele dotykowe muszą spełniać wymagania z Przewodnika Implementacji Touchpad oprócz tych zawartych tutaj.

  • Haptic Mouse to rozszerzenie klasy Mouse Device na Windows. Myszy haptyczne muszą spełniać wymagania zawarte w tej dokumentacji.

Uwaga / Notatka

Urządzenia wejściowe pióra z obsługą haptyczną są specjalną klasą urządzeń, które nie zostaną omówione w tym dokumencie. Aby uzyskać informacje na temat implementacji urządzenia pióra z haptycznym sprzężeniem zwrotnym, zobacz w Przewodniku po implementacji haptycznego pióra.

Implementacja protokołu urządzenia wejściowego Haptics

Aby zrozumieć przedstawione tutaj informacje, należy dobrze zrozumieć protokół HID. Aby uzyskać informacje o protokole HID, zobacz następujące zasoby:

Oprogramowanie układowe urządzenia wejściowego z obsługą haptyczną musi zgłaszać tylko użycia opisane w tym temacie. Windows będzie używać oprogramowania układowego i własnych sterowników HID w celu włączenia urządzenia i udzielenia Windows aplikacjom dostępu do urządzenia.

Przykładowe deskryptory dla każdej obsługiwanej klasy urządzeń znajdują się w poniższej sekcji Przykładowe deskryptory raportów.

Host-Initiated Sprzężenie Zwrotne Haptyczne

Urządzenie wejściowe z obsługą haptyki może obsługiwać sprzężenie zwrotne haptyczne inicjowane przez hosta, które mogą być wyzwalane w dowolnym momencie po enumeracji. Funkcjonalność związana z haptycznością należy uwzględnić w kolekcji HID SimpleHapticsController (Page 0x0E, Usage 0x01).

  • W przypadku tabletów dotykowych ta kolekcja musi być elementem podrzędnym kolekcji Windows Precision Touchpad najwyższego poziomu.
  • W przypadku myszy ta kolekcja musi być kolekcją najwyższego poziomu i elementem równorzędnym kolekcji Najwyższego poziomu myszy.

Obsługa opinii haptycznych inicjowanych przez hosta wymaga raportów HID:

  • Raport GET_FEATURE używany przez hosta do wykonywania zapytań dotyczących obsługiwanych kształtów falowych i ich czasów trwania. Zobacz sekcję "Raport funkcji informacji o formach falowych" poniżej.
  • Raport output używany przez host do ręcznego wyzwalania efektów haptycznych. Zobacz sekcję "Raport danych wyjściowych wyzwalacza ręcznego" poniżej.

W przypadku touchpadów te raporty muszą być zdefiniowane w dwóch logicznych kolekcjach elementów podrzędnych SimpleHapticsController, które są nadrzędne względem głównej kolekcji podrzędnej SimpleHapticsController. W przypadku myszy te raporty można definiować bezpośrednio w kolekcji najwyższego poziomu.

Przebiegi

W poniższej tabeli zdefiniowano kształty fal sygnału obsługiwane przez hosta dla urządzeń wejściowych z funkcją haptyczną. Kształty fali obsługiwane przez urządzenie są skojarzone z numerami porządkowymi. Użycie i czas trwania kształtów falowych są udostępniane hostowi za pośrednictwem raportu funkcji informacji o formach falowych (patrz poniżej). Podczas wyzwalania sprzężenia zwrotnego, host udostępnia liczbowy wskaźnik żądanego kształtu fali jako wartość użycia wyzwalacza ręcznego.

Obowiązkowe i opcjonalne
Przebieg identyfikator Obowiązkowe/opcjonalne Description
Żaden 0x1001 Mandatory Brak operacji. Nie należy wpływać na stan odtwarzania bieżących fal dźwiękowych.
Zatrzymaj 0x1002 Mandatory Zatrzymuje odtwarzanie trwających kształtów fal
Hover 0x1008 Mandatory Impuls światła wskazujący stany aktywowania, sygnalizując potencjał nadchodzącej akcji
Zderzają się 0x1012 Mandatory Impuls miękki wskazujący osiągnięcie granicy lub limitu
Align 0x1013 Mandatory Ostry impuls, gdy obiekt przyciąga się do prowadnicy wyrównania
Step 0x1014 Mandatory Stały impuls dla dyskretnych zmian, takich jak przechodzenie przez kroki czy wartości
Rosnąć 0x1015 Mandatory Impuls dynamiczny, który przekazuje ruch, przejścia lub inteligentną aktywność systemu
Kliknij 0x1003 Zobacz poniżej Średni impuls po kliknięciu elementu, takiego jak przycisk
Prasa 0x1006 Zobacz poniżej Impuls reprezentujący naciśnięcie przycisku
Uwolnij 0x1007 Zobacz poniżej Impuls reprezentujący zwolnienie przycisku
Powodzenie 0x1009 Zobacz poniżej Wzorzec rosnąco potwierdzający ukończoną akcję
Error 0x100A Zobacz poniżej Wzorzec malejący wskazujący akcję, która zakończyła się niepowodzeniem

Kształty fali naciśnięcia i zwolnienia są opcjonalne, ale jeśli jeden jest obsługiwany, drugi również musi być. W przypadku touchpadów kształty fal powinny być zgodne z odczuwanym naciskiem i zwolnieniem inicjowanym przez urządzenie.

Kształty fali Powodzenie i Błąd są obowiązkowe dla myszy i opcjonalne dla tabletów dotykowych. Jeśli jeden z nich jest obsługiwany, to również drugi musi być.

Sygnał Click jest opcjonalny dla myszy i niedozwolony dla touchpadów. W przypadku touchpadów taki sygnał zwrotny powodowałby zamieszanie z istniejącym haptycznym sprzężeniem zwrotnym przy naciskaniu przycisków. W przypadku myszy zaleca się taki przebieg, o ile sprzężenie zwrotne nie powodowałoby podobnego zamieszania (np. mylące byłoby, gdyby haptyczne sprzężenie zwrotne myszy pochodziło spod lewego przycisku myszy).

Zakazany

Następujące kształty fali NIE MOGĄ być obsługiwane.

Przebieg identyfikator Notatki
Buzz Continuous 0x1004 Kształty fali ciągłej nie mogą być obsługiwane.
Ciągłe wibracje 0x1005 Kształty fali ciągłej nie mogą być obsługiwane.
Nieprzerwane zasilanie atramentem 0x100B Dotyczy tylko długopisów.
Ołówek ciągły 0x100C Dotyczy tylko długopisów.
Znacznik ciągły 0x100D Dotyczy tylko długopisów.
Znacznik szselowy ciągły 0x100E Dotyczy tylko długopisów.
Ciągłe szczotkowanie 0x100F Dotyczy tylko długopisów.
Gumka ciągła 0x1010 Dotyczy tylko długopisów.
Sparkle Ciągły 0x1011 Dotyczy tylko długopisów.

Raport funkcji informacji o kształtach falowych

Komputer hosta wyda raport „GET_FEATURE” podczas zapytania urządzenia o obsługiwane kształty fal. Ten raport funkcji musi mieć dedykowany identyfikator raportu.

Raport musi mieć dwie podrzędne kolekcje logiczne: jedną dla listy fal i jedną dla listy czasów trwania. Te kolekcje muszą definiować zakres użycia na stronie Porządkowe (0x0A), która umożliwia hostowi wykonywanie zapytań dotyczących kształtów falowych i czasu trwania skojarzonych z każdą porządkową.

Obowiązkowe i opcjonalne użycie
Członek Strona identyfikator Obowiązkowe/opcjonalne Description
Lista kształtów falowych 0x0E 0x10 Mandatory Kolekcja logiczna zawierająca uporządkowaną listę haptycznych kształtów fali obsługiwanych przez urządzenie
Lista czasu trwania 0x0E 0x11 Mandatory Kolekcja logiczna zawierająca uporządkowaną listę czasów trwania kształtów falowych na liście kształtów fali
Lista kształtów falowych (obowiązkowe)

Ta kolekcja zapewnia odwzorowanie pomiędzy liczbami porządkowymi a odpowiadającymi im przebiegami falowymi. Liczebniki porządkowe 1 i 2 odpowiadają domyślnie brakowi i zatrzymaniu i nie muszą być deklarowane w deskryptorze. W związku z tym minimalna wartość użycia zakresu użycia kolekcji może wynosić 3, a maksymalna wartość użycia musi być wystarczająco duża, aby przypisać liczby porządkowe do wszystkich obsługiwanych form fal. Nie ma wymaganej kolejności przypisywania fal do liczb porządkowych 3 i wyższych — tylko liczby porządkowe 1 i 2 mają stałe definicje.

Jeśli wartość maksymalna użycia jest większa niż liczba kształtów fal obsługiwanych przez urządzenie, urządzenie powinno zgłaszać wartość Brak dla nieobsługiwanych wartości domyślnych.

Logiczny zakres użycia musi obejmować wszystkie obsługiwane użycia kształtów fal. Zakres fizyczny i jednostki muszą mieć wartość 0.

Lista czasu trwania (obowiązkowe)

Ta kolekcja zawiera czasy trwania kształtów fal zdefiniowanych na liście kształtów falowych. Minimalne i maksymalne użycie zakresu użycia kolekcji muszą być identyczne z wartościami listy kształtów falowych.

Dyskretne kształty fali muszą mieć niezerowy czas trwania. Brak i Zatrzymaj, jeśli określono, muszą mieć czas trwania równy zero.

Logiczne minimum zakresu użycia musi wynosić zero, a logiczne maksimum musi być co najmniej tak duże, jak czas trwania najdłuższego dyskretnego kształtu fali. Host będzie traktować wartości logiczne jako milisekundy. Zakres fizyczny musi być zerowy lub identyczny z zakresem logicznym. Jeśli zakres fizyczny i zakres logiczny są zgodne, jednostki muszą być milisekundami.

Raport wyjściowy wyzwalacza ręcznego

Serwer wyda ten raport przy uruchamianiu dyskretnych sprzężeń zwrotnych haptycznych. Ten raport wyjściowy musi mieć dedykowany identyfikator raportu.

Obowiązkowe i opcjonalne użycie
Członek Strona identyfikator Obowiązkowe/opcjonalne Description
Wyzwalacz ręczny 0x0E 0x21 Mandatory Kształt fali do wyzwolenia jako jawne polecenie z hosta
Intensywność 0x0E 0x23 Mandatory Intensywność opinii
Liczba powtórzeń 0x0E 0x24 Zobacz poniżej Liczba powtórzeń opinii po początkowym odtwarzaniu
Okres ponownego pobierania 0x0E 0x25 Zobacz poniżej Czas oczekiwania przed ponownym uruchomieniem sprzężenia zwrotnego podczas powtarzania
Czas odcięcia kształtów falowych 0x0E 0x28 Zobacz poniżej Maksymalny czas odtwarzania informacji zwrotnej przed odcięciem

Liczba powtórzeń, okres ponownego uruchomienia i czas odcinania przebiegu są opcjonalne, ale jeśli jedno z nich jest obsługiwane, pozostałe dwa muszą być również.

Zabronione użycie
Usage identyfikator Notatki
Wyzwalacz automatyczny 0x20 Nieobsługiwane przez hosta.
Kontrolka skojarzona z automatycznym wyzwalaczem 0x22 Nieobsługiwane przez hosta.
Wyzwalacz ręczny (obowiązkowy)

To użycie zawiera numer porządkowy kształtu fali, zgodnie z definicją w raporcie informacyjnym o kształtach fal, o którego odtworzenie poprosił host. Gdy raport wyjściowy zawierający wartość porządkową inną niż Brak jest wysyłany do urządzenia, powinno ono natychmiast rozpocząć odtwarzanie wskazanej fali dźwiękowej z dodatkowymi właściwościami zawartymi w raporcie wyjściowym (intensywność, liczba powtórzeń, okres ponownego uruchomienia, czas wyłączenia, jeśli jest obsługiwany). Urządzenie powinno honorować tylko liczby porządkowe dla dyskretnych kształtów fal, Brak i Zatrzymaj. Jeśli liczebnik porządkowy odpowiada Stop, należy zatrzymać wszelkie trwające dyskretne odtwarzanie kształtów falowych. Jeśli liczba porządkowa odpowiada None, nie należy podejmować żadnych działań, a trwająca informacja zwrotna haptyczna powinna być nadal odtwarzana.

Zakres logiczny musi zawierać wszystkie możliwe liczby porządkowe, w tym niejawne liczby porządkowe 1 (Brak) i 2 (Zatrzymaj). Zakres fizyczny i jednostki muszą mieć wartość 0.

Intensywność (obowiązkowe)

To użycie reprezentuje procent maksymalnej intensywności stosowany do żądanego kształtu falowego, gdzie logiczne maksimum oznacza maksymalną intensywność, a logiczne minimum brak sprzężenia zwrotnego.

Minimum logiczne musi wynosić zero, a wartość logiczna powinna być wybierana na podstawie możliwości urządzenia — na przykład jeśli urządzenie obsługuje cztery poziomy intensywności, wartość logiczna powinna wynosić cztery. Jeśli urządzenie obsługuje bardziej szczegółową intensywność, wartość logiczna może być większa, ale nie może przekraczać 100. Urządzenie musi obsługiwać co najmniej cztery poziomy intensywności, więc minimalna wartość logiczna wynosi cztery. Intensywność zerowa wskazuje, że nie należy generować żadnej informacji zwrotnej — gospodarz użyje tej wartości tylko dla Stop.

Zakres fizyczny i jednostki muszą mieć wartość 0.

Liczba powtórzeń (opcjonalnie)

To użycie reprezentuje liczbę razy, ile należy powtórzyć sygnał po jego początkowym odtworzeniu. Wartość zero wskazuje, że kształt fali powinien być odtwarzany tylko raz.

Jeśli to użycie jest obsługiwane, okres ponownego pobierania i użycie czasu redukcji również musi być obsługiwane.

Minimalna wartość logiczna musi być równa zero, a maksymalna wartość logiczna musi być większa niż zero. Maksimum logiczne powinno być ustawione na rozsądną wartość (na przykład 10). Zakres fizyczny i jednostki muszą mieć wartość 0.

Okres ponownego uruchamiania (opcjonalnie)

To użycie reprezentuje czas trwania między ponawianiami kształtów fal, mierzony od czasu rozpoczęcia poprzedniego wyzwalacza. Wartość zero powinna być interpretowana jako identyczna z domyślnym czasem trwania dla kształtów fali, więc ponowne pobieranie następuje natychmiast po zakończeniu poprzedniego. Wartości mniejsze niż domyślny czas trwania kształtu fali powinny przerwać go i ponownie uruchomić.

Jeśli to użycie jest obsługiwane, należy również obsługiwać użycie liczby powtórzeń i czasu odcięcia.

Host będzie traktować wartości logiczne jako milisekundy. Minimum logiczne musi wynosić zero, a maksimum logiczne musi wynosić co najmniej 1000 (reprezentując jedną sekundę). Zakres fizyczny musi być zerowy lub identyczny z zakresem logicznym. Jeśli zakres fizyczny jest inny niż zero, jednostki muszą być milisekundami.

Czas odcięcia fali (opcjonalnie)

To użycie reprezentuje maksymalny czas, przez jaki pojedynczy wyzwalacz może spowodować odtwarzanie, uwzględniając liczbę powtórzeń i okres ponownego wyzwalania.

Jeśli to użycie jest obsługiwane, użycie liczby powtórzeń i ponownego pobierania okresów również musi być obsługiwane.

Host będzie traktować wartości logiczne jako milisekundy. Minimum logiczne musi być co najmniej tak duże, jak czas trwania najdłuższej dyskretnej formy fali, pomnożony przez logiczny maksymalny użytek liczby powtórzeń plus jeden. To logiczne minimum reprezentuje czas trwania wyzwalania najdłuższego kształtu fali z maksymalną obsługiwaną liczbą powtórzonych wyzwalaczy i bez opóźnień między ponownymi wyzwoleniami. Maksymalna wartość logiczna może być ograniczona, aby zapobiec nadmiernie długiemu czasowi trwania sprzężenia haptycznego na pojedyncze żądanie, zgodnie z uznaniem systemu urządzenia. Zakres fizyczny musi być zerowy lub identyczny z zakresem logicznym. Jeśli zakres fizyczny jest inny niż zero, jednostki muszą być milisekundami.

Wskazówki dotyczące haptycznego panelu dotykowego

Elementy w tej sekcji dotyczą tylko dotykowych tabletów dotykowych.

Sprzężenie zwrotne inicjowane przez urządzenie

Haptic touchpad jest odpowiedzialny za wyzwalanie sprzężenia zwrotnego haptycznego, jak tylko wykryje, że powierzchnia touchpada została naciśnięta lub zwolniona. Może on obsługiwać raporty SET_FEATURE, aby umożliwić użytkownikom dostosowywanie jego zachowania podczas wykonywania tych czynności:

  • Intensywność haptycznej informacji zwrotnej
  • Siła wymagana do uruchomienia naciśnięcia przycisku

Oba te raporty funkcji są obowiązkowe, jeśli touchpad obsługuje również opinie haptyczne inicjowane przez hosta. Każdy raport musi używać odrębnego identyfikatora raportu, który nie jest używany z żadnym innym użyciem.

Podczas wyliczania host oceni obsługiwane zakresy logiczne i fizyczne z deskryptora oraz wykona obliczenia dla uwidocznionych opcji ustawień interfejsu użytkownika, w tym wartości domyślne. Host wysyła polecenie SET_FEATURE, aby przekazać wartość określoną przez użytkownika do urządzenia; wysłanie może mieć miejsce w dowolnym momencie, ale ma miejsce za każdym razem, gdy ustawienie zostanie zmienione, następuje przełączenie użytkownika oraz podczas enumeracji urządzenia lub jego resetu. Przed wydaniem raportu SET_FEATURE urządzenie powinno użyć rozsądnej wartości domyślnej własnego wyboru (np. środka zakresu logicznego).

Raport intensywności funkcji dotykowej

Ten raport typu SET_FEATURE określa preferencje użytkownika dotyczące intensywności haptycznego sprzężenia zwrotnego przy nacisku i zwolnieniu przycisku. Nie ma zastosowania do intensywności informacji zwrotnej inicjowanej przez hosta, jeśli jest to obsługiwane przez urządzenie. Aby obsługiwać tę konfigurację, urządzenie musi zdefiniować kolekcję podrzędnych elementów logicznych SimpleHapticsController (Page 0x0E, Usage 0x01) w głównej kolekcji Windows Precision Touchpad, zawierającą użycie intensywności haptycznej (Page 0x0E, Usage 0x23) jako raport funkcji z dedykowanym identyfikatorem raportu. Ta kolekcja podrzędna nie może zawierać wyzwań Auto Trigger (Strona 0x0E, Użycie 0x20) ani Manual Trigger (Strona 0x0E, Użycie 0x21). Musi być oddzielona od kolekcji podrzędnej SimpleHapticsController używanej do informacji zwrotnej haptycznej inicjowanej przez hosta (jeśli jest obsługiwana).

Minimum logiczne musi być równe zero, a maksimum logiczne musi być większe lub równe cztery. Preferencja użytkownika będzie liniowo skalowana do logicznego zakresu, przy czym zero wskazuje, że żadne sprzężenie zwrotne nie powinno być wyzwalane w przypadku naciśnięcia i zwolnienia przycisku.

Raport funkcji progu naciśnięcia przycisku

Ten raport SET_FEATURE określa preferencje użytkownika dotyczące ilości siły potrzebnej do naciśnięcia przycisku. Aby obsługiwać tę konfigurację, urządzenie musi zdefiniować użycie progu naciśnięcia przycisku (strona 0x0D, użycie 0xB0) jako raport funkcji z dedykowanym identyfikatorem raportu w kolekcji najwyższego poziomu Windows Precision Touchpad. Nie może znajdować się w kolekcji logicznej SimpleHapticsController.

Zakres logiczny jest liniowo mapowany na fizyczny zakres wartości i równomiernie rozmieszczony i wyśrodkowany wokół wartości domyślnej. Po uzyskaniu zakresu logicznego wartość domyślna zostanie obliczona przy użyciu następującej formuły:

Diagram przedstawiający formułę obliczania domyślnego progu naciśnięcia przycisku w jednostkach logicznych

Minimum logiczne, Wartość domyślna i Maksimum logiczne odpowiadają 3 odrębnym poziomom siły naciśnięcia przycisku, które są widoczne dla użytkownika za pośrednictwem interfejsu użytkownika ustawień Windows, obsługując odpowiednio "Niski", "Średni" i "Wysoki".

Zalecany zakres fizyczny dla progu naciśnięcia przycisku powinien obejmować co najmniej wartości od 110g do 190g, co odpowiada minimalnym i maksymalnym wartościom. W przypadku deskryptora próbki korzystającego z wartości Fizycznej Maksymalnej 190g i Fizycznej Minimalnej 110g (w związku z tym, na podstawie powyższej formuły, domyślna wartość to 150g), zobacz Deskryptory Przykładów Raportów.

Przykładowe deskryptory raportów HID

Przykładowy deskryptor haptycznego touchpada

Poniższy deskryptor obsługuje wszystkie obowiązkowe i opcjonalne użycie. Deklaruje wsparcie dla pięciu kształtów fal, z najdłuższym okresem trwania 50 ms.

Wszystkie zakresy logiczne powinny być aktualizowane w oparciu o obsługę urządzeń. Aby obsługiwać inną liczbę kształtów fal:

  • Należy zaktualizować zakres logiczny użycia wyzwalacza ręcznego
  • Należy zaktualizować zakresy użycia i liczbę raportów dla listy kształtów falowych i listy czasu trwania

Aby obsługiwać inną maksymalną długość kształtów fali, należy zaktualizować następujące zakresy logiczne:

  • Okres pobierania (dane wyjściowe)
  • Czas odcięcia kształtów falowych (dane wyjściowe)
  • Lista czasu trwania (funkcja)
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, 0x01, 0x10, //    LogicalMinimum(4,097)
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()

Powyższy deskryptor został wygenerowany za pośrednictwem następującego pliku 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 = [0x1001, 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'

Przykładowy opis myszy haptycznej

Poniższy deskryptor obsługuje wszystkie obowiązkowe i opcjonalne użycie. Deklaruje wsparcie dla ośmiu kształtów fali, z najdłuższym okresem trwania 200 ms.

Wszystkie zakresy logiczne powinny być aktualizowane w oparciu o obsługę urządzeń. Aby obsługiwać inną liczbę kształtów fal:

  • Należy zaktualizować zakres logiczny użycia wyzwalacza ręcznego
  • Należy zaktualizować zakresy użycia i liczbę raportów dla listy kształtów falowych i listy czasu trwania

Aby obsługiwać inną maksymalną długość kształtów fali, należy zaktualizować następujące zakresy logiczne:

  • Okres pobierania (dane wyjściowe)
  • Czas odcięcia kształtów falowych (dane wyjściowe)
  • Lista czasu trwania (funkcja)
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, 0x01, 0x10, //   LogicalMinimum(4,097)
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()

Powyższy deskryptor został wygenerowany za pośrednictwem następującego pliku 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 = [0x1001, 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'