Руководство по реализации входных устройств Haptics

В этом документе описана реализация протокола для устройств ввода с поддержкой тактильной обратной связи, подключающихся к совместимому узлу Windows 11. Это не включает рекомендации по механическим ограничениям, электрическим ограничениям или выбору компонентов для создания хаптикового отклика в оборудовании входного устройства.

Поддерживаемые классы устройств

Windows 11 поддерживает следующие классы устройств ввода с поддержкой хаптичного ввода:

  • Haptic Touchpad — это расширение класса Устройства Сенсорной панели на Windows. Это руководство по реализации дополняет руководство по реализации сенсорной панели и фокусируется на реализации тактильной отдачи в сенсоре сенсорной панели, поэтому тактильные сенсорные панели должны соответствовать требованиям в руководстве по реализации сенсорной панели в дополнение к тем, которые содержатся здесь.

  • Haptic Mouse — это расширение класса "Устройство мыши" на Windows. Хаптичные мыши должны соответствовать требованиям, содержащимся в этой документации.

Замечание

Устройства ввода пера с поддержкой haptic — это специальный класс устройства, который не будет рассматриваться в этом документе. Сведения о том, как реализовать устройство пера с тактильной обратной связью, см. в руководстве по реализации Тактильного Пера.

Реализация протокола тактильных ощущений устройства ввода

Для понимания информации, представленной здесь, требуется хорошее понимание протокола HID. Дополнительные сведения о протоколе HID см. в следующих ресурсах:

Встроенное ПО устройства ввода с поддержкой Haptic должно сообщать только об использовании, описанном в этом разделе. Windows будет использовать встроенное ПО и собственные драйверы HID, чтобы включить устройство и предоставить Windows приложениям доступ к устройству.

Примеры дескрипторов для каждого поддерживаемого класса устройства приведены в разделе "Примеры дескрипторов отчетов" ниже.

Обратная связь с тактильной отдачей, инициируемая хостом

Устройство ввода с тактильной обратной связью может поддерживать тактильную обратную связь, инициированную хостом, которая может быть активирована в любое время после инициализации. Функционал, связанный с тактильными сигналами, должен быть включён в коллекцию HID SimpleHapticsController (Page 0x0E, Usage 0x01).

  • Для тачпадов эта коллекция должна быть дочерним элементом коллекции верхнего уровня Windows Precision Touchpad.
  • Для мышей это должна быть коллекция верхнего уровня, располагающаяся рядом с коллекцией верхнего уровня Mouse.

Для поддержки тактильной обратной связи, инициированной хостом, требуются отчеты HID.

  • Отчет GET_FEATURE, который используется хостом для запроса поддерживаемых форм волн и их длительности. См. раздел "Отчет о параметрах формы сигнала" ниже.
  • Отчет OUTPUT, используемый хостом для ручного запуска хаптики. См. ниже раздел "Отчет о ручном запуске триггера".

Для сенсорных панелей эти отчёты должны быть определены на двух логических дочерних коллекциях SimpleHapticsController, являющихся дочерними для основной дочерней коллекции SimpleHapticsController. Для мышей эти отчеты можно определить непосредственно в коллекции верхнего уровня.

Волновые формы

В следующей таблице определяются формы волн, поддерживаемые хостом для устройств ввода с поддержкой тактильной обратной связи. Формы сигналов, поддерживаемые устройством, связаны с порядковым индексом. Использование формы волны и её продолжительность предоставляются хосту через отчет о характеристиках формы волны (см. ниже). При активации обратной связи хост предоставляет порядковое значение необходимой формы волны в качестве значения для ручного использования триггера.

Обязательный и необязательный
Форма сигнала Идентификатор Обязательный или необязательный Description
None 0x1001 Mandatory Без операции. Не должно влиять на режим воспроизведения текущих звуковых волновых форм.
Остановка 0x1002 Mandatory Остановка воспроизведения текущих волновых форм
Навести курсор 0x1008 Mandatory Легкий импульс, указывающий состояния наведения, сигнализируя потенциал для предстоящего действия
Сталкиваться 0x1012 Mandatory Мягкий импульс, указывающий на достижение границы или предела
Align 0x1013 Mandatory Резкий импульс при привязке объекта к направляющей выравнивания
Step 0x1014 Mandatory Твердый импульс для дискретных изменений, таких как перемещение по шагам или значениям
Рост 0x1015 Mandatory Динамический импульс, который передает движение, переходы или интеллектуальную системную активность
Click 0x1003 См. ниже Средний импульс при нажатии содержимого, например кнопки
Нажать 0x1006 См. ниже Пульс, представляющий нажатие кнопки
Релиз 0x1007 См. ниже Пульс, представляющий выпуск кнопки
Success 0x1009 См. ниже Возрастающий паттерн, подтверждающий выполнение действия
Ошибка 0x100A См. ниже Шаблон убывания, указывающий на неудачное действие

Формы сигналов нажатия и отпускания являются необязательными, но если одна из них поддерживается, другая тоже должна быть поддержана. Для сенсорных панелей форма волны должна соответствовать обратной связи, связанной с инициированным устройством нажатием и отпусканием.

Формы волны успеха и ошибок обязательны для мышей и необязательны для тачпадов. Если один поддерживается, другой должен быть также.

Форма волны Click необязательна для мышей и запрещена для сенсорной панели. Для сенсорных панелей такая тактильная отдача вызвала бы путаницу с существующей тактильной отдачей при нажатии кнопок. Для мышей рекомендуется использовать сигнал в форме волны при условии, что такая отдача не вызовет аналогичной путаницы (например, путаница возникнет, если тактильная отдача мыши будет исходить из-под левой кнопки мыши).

Запрещено

Следующие формы сигналов не должны поддерживаться.

Форма сигнала Идентификатор Примечания.
Buzz Непрерывный 0x1004 Непрерывные волны не должны поддерживаться.
Грохот непрерывный 0x1005 Непрерывные волны не должны поддерживаться.
Непрерывная подача чернил 0x100B Применимо только к перам.
Непрерывный карандаш 0x100C Применимо только к перам.
Непрерывный маркер 0x100D Применимо только к перам.
Маркер с плоским наконечником (непрерывный) 0x100E Применимо только к перам.
Кисть непрерывная 0x100F Применимо только к перам.
Автоматическое стирание 0x1010 Применимо только к перам.
Sparkle Непрерывный 0x1011 Применимо только к перам.

Отчет о характеристиках информации формы волны

Хост выдает этот отчет GET_FEATURE при запросе устройства на поддерживаемые формы сигналов. Этот отчет функции должен содержать уникальный идентификатор отчета.

Отчет должен иметь две дочерние логические коллекции, одна для списка волн и одна для списка длительности. Эти коллекции должны определять диапазон использования на странице ординалов (0x0A), что позволяет хосту запрашивать форму сигнала и длительность, связанную с каждым порядковым номером.

Обязательные и необязательные применения
Член Страница Идентификатор Обязательный или необязательный Description
Список форм волн 0x0E 0x10 Mandatory Логическая коллекция, содержащая упорядоченный список хаптиковых волн, поддерживаемых устройством
Список длительности 0x0E 0x11 Mandatory Логическая коллекция, содержащая упорядоченный список длительности для волновых форм в списке волн
Список форм сигналов (обязательный)

Эта коллекция предоставляет сопоставление порядковых чисел и соответствующих волновых форм. Порядковые номера 1 и 2 неявно соответствуют None и Stop и не требуется объявлять их в дескрипторе. Таким образом, минимальное значение диапазона использования коллекции может быть 3, а максимальное значение должно быть достаточно большим, чтобы назначить порядковые номера всем поддерживаемым формам волн. Для назначения волновых форм порядковым номерам 3 и выше не требуется соблюдать порядок — только порядковым номерам 1 и 2 даны фиксированные определения.

Если максимальное количество использования больше, чем количество форм волны, поддерживаемых устройством, устройство должно вывести None для неподдерживаемых порядковых номеров.

Логический диапазон диапазона использования должен включать все поддерживаемые использования форм сигналов. Физический диапазон и единицы должны иметь значение 0.

Список продолжительности (обязательный)

Эта коллекция предоставляет длительность волновых форм, определенных в списке волн. Минимальное и максимальное значение диапазона использования коллекции должно совпадать с диапазоном использования списка форм сигналов.

Дискретные волновые формы должны иметь ненулевое время. None и Stop, если указано, должны иметь продолжительность ноль.

Логический минимум диапазона использования должен быть равен нулю, и логический максимум должен быть по крайней мере больше, чем длительность самой длинной дискретной волны. Хост будет рассматривать логические значения как миллисекунды. Физический диапазон должен быть равен нулю или идентичен логическому диапазону. Если физический диапазон и логический диапазон совпадают, единицы должны быть миллисекундами.

Отчет о выходных данных ручного триггера

Хост выдает этот отчет при срабатывании дискретной хаптической обратной связи. Этот выходной отчет должен иметь выделенный идентификатор отчета.

Обязательные и необязательные применения
Член Страница Идентификатор Обязательный или необязательный Description
Ручной триггер 0x0E 0x21 Mandatory Форма волны для запуска в виде явной команды с узла
Интенсивность 0x0E 0x23 Mandatory Интенсивность обратной связи
Число повторов 0x0E 0x24 См. ниже Количество раз повторения обратной связи после первоначального воспроизведения
Период повторного запуска 0x0E 0x25 См. ниже Длительность ожидания перед повторной активацией обратной связи при повторе
Время отреза волны 0x0E 0x28 См. ниже Максимальное время воспроизведения обратной связи до её остановки.

Количество повторений, период повторного запуска и время обрезания формы сигнала являются необязательными, но если одно поддерживается, остальные два также должны быть поддержаны.

Запрещенные использования
Usage Идентификатор Примечания.
Автоматический триггер 0x20 Не поддерживается хостом.
Автоматический триггер связанного элемента управления 0x22 Не поддерживается хостом.
Ручной триггер (обязательный)

Это использование содержит порядковый номер волны, как определено в отчете о функции волн, который был запрошен хостом для воспроизведения. Если на устройство отправляется выходной отчет, содержащий порядковый номер, отличный от None, оно должно немедленно начать воспроизведение указанной формы сигнала с дополнительными параметрами, указанными в выходном отчете (интенсивность, число повторов, период повтора, время отсечения, если поддерживается устройством). Устройство должно учитывать порядковые номера только для дискретных волновых форм, None и Stop. Если порядковый номер соответствует Стоп, следует остановить текущее воспроизведение дискретного сигнала. Если порядковое значение соответствует None, действие не должно выполняться, и продолжающаяся тактильная обратная связь должна оставаться активной.

Логический диапазон должен включать все возможные порядковые порядки, включая неявные порядковые номера 1 (нет) и 2 (stop). Физический диапазон и единицы должны иметь значение 0.

Интенсивность (обязательно)

Это использование представляет процент максимальной интенсивности, применяемой к запрошенной волне, с логическим максимумом, представляющим максимальную интенсивность, и логический минимум, представляющий отсутствие обратной связи вообще.

Логический минимум должен быть равен нулю, и логический максимум должен быть выбран на основе возможностей устройства, например, если устройство поддерживает четыре уровня интенсивности, логический максимум должен быть четыре. Если устройство поддерживает более детализированную интенсивность, логический максимум может быть больше, но он не должен превышать 100. Устройство должно поддерживать по крайней мере четыре уровня интенсивности, поэтому минимальное логическое максимальное значение равно четырем. Интенсивность, равная нулю, указывает, что обратная связь не должна осуществляться, — главный процесс будет использовать только это значение для Stop.

Физический диапазон и единицы должны иметь значение 0.

Число повторов (необязательно)

Это использование представляет количество раз повторения волновой формы после первоначального воспроизведения. Значение нуля указывает, что волновая форма должна воспроизводиться только один раз.

Если это использование поддерживается, необходимо также поддерживать период повторного срабатывания и время отсечки.

Логический минимум должен быть равен нулю, а логический максимум должен быть больше нуля. Логическое максимальное значение должно быть ограничено разумным значением (например, 10). Физический диапазон и единицы должны иметь значение 0.

Период повторного запуска (необязательно)

Это использование представляет длительность между повторными запусками волнообразной формы, измеряемую от времени начала предыдущего триггера. Значение нуля должно интерпретироваться как идентичное длительности по умолчанию для формы волны, поэтому повторный запуск происходит сразу после завершения предыдущего. Значения меньше, чем длительность по умолчанию для волны, должны прервать волновую форму и перезапустить ее.

Если это использование поддерживается, необходимо также поддерживать количество повторов и время завершения.

Хост будет рассматривать логические значения как миллисекунды. Логическое минимальное значение должно быть равно нулю, а логическое максимальное значение должно быть не менее 1000 (представляющее одну секунду). Физический диапазон должен быть равен нулю или идентичен логическому диапазону. Если физический диапазон не равен нулю, единицы должны быть миллисекундами.

Время отреза волны (необязательно)

Это использование представляет максимальное время, когда один триггер может привести к воспроизведению контента, учитывая количество повторов и период повторной активации.

Если это использование поддерживается, необходимо также поддерживать число повторов и использование периода повторного срабатывания.

Хост будет рассматривать логические значения как миллисекунды. Логический минимум должен быть по крайней мере больше, чем длительность самой длинной дискретной волны, умноженной на логический максимум использования счетчика повторов плюс один. Этот логический минимум представляет длительность самой длинной формы сигнала с максимальным поддерживаемым числом повторных триггеров и без задержки между перезапусками. Логическое максимальное значение длительности может быть ограничено, чтобы предотвратить чрезмерную длительность тактильной обратной связи для одного запроса по усмотрению устройства. Физический диапазон должен быть равен нулю или идентичен логическому диапазону. Если физический диапазон не равен нулю, единицы должны быть миллисекундами.

Руководство по Haptic Touchpad

Элементы в этом разделе применяются только к сенсорным панелям с тактильной обратной связью.

Инициируемая Устройством Тактильная Обратная Связь

Гаптическая сенсорная панель отвечает за активацию гаптической обратной связи, когда она определяет нажатие или отпускание кнопки на поверхности сенсорной панели. Он может выбрать поддержку SET_FEATURE отчетов, чтобы разрешить настройку пользователем его поведения при этом:

  • Интенсивность тактильной обратной связи
  • усилие, необходимое для нажатия кнопки

Оба этих отчета о возможностях являются обязательными, если сенсорная панель также поддерживает тактильную обратную связь, инициированную узлом. Каждый отчет должен использовать отдельный идентификатор отчета, не используемый при других действиях.

Во время перечисления хост оценивает поддерживаемый логический и физический диапазон от дескриптора и вычисляет доступные параметры для интерфейса настроек, включая значения по умолчанию. Хост должен выдавать команду SET_FEATURE для передачи указанного пользователем значения устройству; это может происходить в любое время, но должно происходить при изменении параметра, переключении пользователя, а также при перечислении устройства или его сбросе. Перед выпуском отчета SET_FEATURE устройство должно использовать разумное значение по умолчанию по собственному выбору (например, середину своего логического диапазона).

Отчет о тактильной интенсивности

В этом отчете SET_FEATURE указывается предпочтение пользователя относительно интенсивности тактильной обратной связи при нажатии и отпускании кнопки. Это не применяется к интенсивности отзывов, инициированных хостом, если это поддерживается устройством. Для поддержки этой конфигурации устройство должно определить логическую коллекцию SimpleHapticsController (Page 0x0E, Usage 0x01) в коллекции Windows Precision Touchpad верхнего уровня, содержащую параметр Haptic Intensity (Page 0x0E, Usage 0x23) в качестве отчета о возможностях с выделенным идентификатором отчета. Эта дочерняя коллекция не должна содержать использования Авто Триггера (страница 0x0E, использование 0x20) или ручного триггера (страница 0x0E, использование 0x21). Он должен быть отделен от дочерней коллекции SimpleHapticsController, используемой для тактильной обратной связи, инициированной хостом (если она поддерживается).

Логический минимум должен быть равен нулю, а логический максимум должен быть больше или равен четырем. Предпочтения пользователя будут линейно масштабироваться в логический интервал, где ноль указывает, что тактильная обратная связь не должна быть активирована для нажатия и отпускания кнопки.

Отчет о функции порога нажатия кнопки

В этом SET_FEATURE отчете указывается предпочтение пользователя для объема силы, необходимого для активации нажатия кнопки. Для поддержки этой конфигурации устройство должно определить использование порога нажатия кнопки (страница 0x0D, использование 0xB0) в качестве отчета о функции с выделенным идентификатором отчета в коллекции верхнего уровня Windows Precision Touchpad. Он не должен находиться в логической коллекции SimpleHapticsController.

Логический диапазон должен линейно сопоставляться с физическим диапазоном значений, а также равномерно находиться в пределах значения по умолчанию. При получении логического диапазона значение по умолчанию будет вычисляться с помощью следующей формулы:

Схема, показывающая формулу для вычисления порогового значения нажатия кнопки по умолчанию в логических единицах

Логический минимум, значение по умолчанию и логическое максимальное значение соответствуют 3 уровням нажатия кнопки, предоставляемым пользователю с помощью пользовательского интерфейса Windows параметров (поддерживая "Низкий", "Средний" и "Высокий", соответственно).

Рекомендуемый физический диапазон для порога нажатия кнопки — по крайней мере охватывать диапазон от 110 г до 190g, соответствующий минимальному и максимальному значениям соответственно. Пример дескриптора с использованием физического максимума 190g и физического минимума 110g (таким образом, на основе приведенной выше формулы значение по умолчанию равно 150g) см. в разделе "Примеры дескрипторов отчетов".

Пример дескрипторов отчетов HID

Пример дескриптора тактильного тачпада

Следующий дескриптор поддерживает все обязательные и необязательные использования. Он объявляет поддержку пяти волновых форм, при этом самая длинная длительность составляет 50 мс.

Все логические диапазоны должны обновляться на основе уровня поддержки устройств. Для поддержки другого количества волновых форм:

  • Логический диапазон использования ручного триггера должен быть обновлен
  • Необходимо обновить диапазоны использования и количество отчетов для списка форм волнительных сигналов и длительности.

Чтобы поддерживать другую максимальную длину волн, необходимо обновить следующие логические диапазоны:

  • Период извлечения (выходные данные)
  • Время среза формы волны (результирующие данные)
  • Список длительности (функция)
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()

Приведенный выше дескриптор был создан с помощью следующего файла 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'

Пример дескриптора гаптической мыши

Следующий дескриптор поддерживает все обязательные и необязательные использования. Он объявляет поддержку восьми волновых форм, при этом самая длинная длительность составляет 200 мс.

Все логические диапазоны должны обновляться на основе уровня поддержки устройств. Для поддержки другого количества волновых форм:

  • Логический диапазон использования ручного триггера должен быть обновлен
  • Необходимо обновить диапазоны использования и количество отчетов для списка форм волнительных сигналов и длительности.

Чтобы поддерживать другую максимальную длину волн, необходимо обновить следующие логические диапазоны:

  • Период извлечения (выходные данные)
  • Время среза формы волны (результирующие данные)
  • Список длительности (функция)
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()

Приведенный выше дескриптор был создан с помощью следующего файла 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'