Partilhar via


Guia de Implementação de Haptics em Dispositivos de Entrada

Este documento detalha a implementação do protocolo para dispositivos de entrada com capacidade háptica que se ligam a um host Windows 11 compatível. Isto não inclui orientações sobre restrições mecânicas, elétricas ou seleção de componentes para gerar a resposta háptica dentro do hardware do dispositivo de entrada.

Classes de dispositivo suportadas

O Windows 11 suporta as seguintes classes de dispositivos de entrada com capacidade háptica:

  • Haptic Touchpad é uma extensão da classe Touchpad Device no Windows. Este guia de implementação adiciona ao Guia de Implementação do Touchpad e se concentra na implementação de hápticas dentro do digitalizador de touchpad, portanto, os touchpads hápticos devem atender aos requisitos do Guia de Implementação do Touchpad , além dos contidos aqui.

  • Haptic Mouse é uma extensão da classe Mouse Device no Windows. Os ratos hápticos devem cumprir os requisitos contidos nesta documentação.

Nota: Os dispositivos de entrada de caneta com capacidade háptica são uma classe especial de dispositivo que não será abordada neste documento. Para informações sobre como implementar um dispositivo de caneta com feedback háptico, consulte o Guia de Implementação da Caneta Háptica.

Implementação do Protocolo de Háptica para Dispositivos de Entrada

É necessária uma boa compreensão do protocolo HID para poder compreender as informações aqui apresentadas. Consulte os seguintes recursos para obter informações sobre o protocolo HID:

O firmware do dispositivo de entrada com capacidade háptica só precisa de reportar os usos descritos neste tópico. O Windows usará o firmware e seus próprios drivers HID para habilitar o dispositivo e dar aos aplicativos do Windows acesso ao dispositivo.

Descritores de exemplo para cada classe de dispositivo suportada são fornecidos na secção de Descritores de Relatório de Exemplo abaixo.

Orientação Comum

Os itens desta secção aplicam-se a todas as classes de dispositivos hápticos de entrada.

Coleção HID Obrigatória

Funcionalidades relacionadas com háptica devem ser incluídas numa coleção HID SimpleHapticsController (Página 0xE, Uso 0x1).

Para dispositivos Touchpad Háptico, esta coleção deve ser uma subcoleção da coleção principal do Windows Precision Touchpad.

Para dispositivos de Rato Háptico, esta coleção deve ser uma coleção de nível superior e uma coleção irmã da coleção de nível superior do Rato.

Device-Initiated Feedback háptico

Um dispositivo de entrada com capacidade háptica pode, opcionalmente, suportar a iniciação do seu próprio feedback háptico, por exemplo, em resposta a um botão ser pressionado ou libertado.

Para touchpads hápticos, a secção "Orientação para Touchpad Háptico" abaixo descreve como o dispositivo pode escolher suportar os relatórios de SET_FEATURE, permitindo assim a personalização do comportamento pelo utilizador ao iniciar o feedback háptico.

Os ratos hápticos podem ativar feedback iniciado pelo dispositivo, mas o Windows não tem mecanismo para configurar este comportamento.

Host-Initiated Feedback háptico

Um dispositivo de entrada com capacidade háptica pode suportar feedback háptico iniciado pelo hospedeiro, que pode ocorrer a qualquer momento após a enumeração.

Touchpads táteis e ratos hápticos podem opcionalmente suportar feedback iniciado pelo anfitrião. Para touchpads hápticos, se o feedback iniciado pelo host for suportado, ambos os relatórios SET_FEATURE para personalização de feedback iniciado pelo dispositivo também devem ser suportados.

O suporte para feedback háptico iniciado pelo host requer duas coletâneas filhas lógicas SimpleHapticsController (Página 0x0E, Uso 0x01). Estas coleções lógicas devem ser filhos da coleção principal SimpleHapticsController para a classe de dispositivo implementada (conforme documentado na secção "Required HID Collection" acima) e devem ser separadas da coleção usada para configurar a intensidade do feedback háptico iniciado pelo dispositivo para touchpads. Uma destas coleções filhas lógicas deve definir um relatório GET_FEATURE usado pelo anfitrião para consultar as formas de onda suportadas e as suas durações. A outra coleção lógica de filhos deve definir um relatório de saída usado pelo host para acionar manualmente os hápticos.

O dispositivo NÃO deve declarar suporte para hápticos acionados automaticamente e o dispositivo NÃO deve suportar quaisquer formas de onda contínuas.

Formas de onda

A tabela seguinte define as formas de onda suportadas pelo host para dispositivos de entrada com capacidade háptica. As formas de onda suportadas por um dispositivo estão associadas a um ordinal. O uso e a duração da forma de onda são fornecidos ao host através do relatório de recurso de informações de forma de onda (veja abaixo). Ao acionar o feedback, o host fornece o ordinal da forma de onda desejada como o valor para o uso manual do gatilho.

Obrigatório e Opcional
Forma de onda Description Página ID Obrigatório/Opcional
Nenhum Não-op. Não deve afetar o estado de jogo das formas de onda em curso 0x0E 0x1001 Mandatory
Parar Interrompe a reprodução de formas de onda em curso 0x0E 0x1002 Mandatory
Passe o cursor Um pulso de luz usado para indicar, pairar e sinalizar o potencial para uma próxima ação 0x0E 0x1008 Mandatory
Colisão Um pulso suave usado para indicar colisões com limites de tela ou as extremidades de controles deslizantes e barras de rolagem 0x0E 0x1012 Mandatory
Align Um pulso nítido que confirma o alinhamento do objeto durante interações de arrastar, dimensionar ou girar com guias ou bordas de tela 0x0E 0x1013 Mandatory
Step Um pulso firme usado para percorrer itens em controles deslizantes, listas ou lavadores 0x0E 0x1014 Mandatory
Crescer Um pulso dinâmico que transmite movimento, transições ou atividade inteligente do sistema 0x0E 0x1015 Mandatory
Pressionar O sinal háptico acionado pelo dispositivo quando determina que o botão de superfície foi pressionado. Se suportado, Release também deve ser suportado. 0x0E 0x1006 Opcional
Release O sinal háptico acionado pelo dispositivo quando determina que o botão de superfície foi liberado. Se suportado, Pressione também deve ser suportado. 0x0E 0x1007 Opcional
Sucesso Forte sinal háptico para alertar o usuário de uma ação foi bem-sucedida 0x0E 0x1009 Opcional
Erro Sinal háptico forte para alertar o usuário de que uma ação falhou ou ocorreu um erro 0x0E 0x100A Opcional
Proibido

As seguintes formas de onda NÃO DEVEM ser suportadas.

Forma de onda ID Observações
Clique em 0x1003 Causaria confusão com o feedback háptico existente para pressionar botões.
Buzz Contínuo 0x1004 Não devem ser suportadas formas de onda contínuas.
Rumble Contínuo 0x1005 Não devem ser suportadas formas de onda contínuas.
Tinta Contínua 0x100B Aplicável apenas a canetas.
Lápis Contínuo 0x100C Aplicável apenas a canetas.
Marcador Contínuo 0x100D Aplicável apenas a canetas.
Marcador de cinzel contínuo 0x100E Aplicável apenas a canetas.
Escova Contínua 0x100F Aplicável apenas a canetas.
Borracha Contínua 0x1010 Aplicável apenas a canetas.
Brilho Contínuo 0x1011 Aplicável apenas a canetas.

Relatório de recursos de informações de forma de onda

O host emitirá esse relatório de GET_FEATURE ao consultar o dispositivo para suas formas de onda suportadas. Este relatório de recurso deve ter um ID de relatório dedicado.

A coleção lógica deve ter duas coleções lógicas filhas, uma para a lista de forma de onda e outra para a lista de duração. Essas coleções devem definir um intervalo de uso na página Ordinal (0x0A), que permite ao host consultar a forma de onda e a duração associadas a cada ordinal.

Usos Obrigatórios e Opcionais
Membro Description Página ID Obrigatório/Opcional
Lista de formas de onda Coleção lógica contendo uma lista ordenada de formas de onda háptica suportadas pelo dispositivo 0x0E 0x10 Mandatory
Lista de Duração Coleção lógica contendo uma lista ordenada de durações para formas de onda na Lista de Formas de Onda 0x0E 0x11 Mandatory
Lista de Formas de Onda (Obrigatório)

Esta coleção fornece o mapeamento entre ordinais e as formas de onda correspondentes. Os ordinais 1 e 2 correspondem a WAVEFORM_NONE e WAVEFORM_STOP implicitamente e não precisam de ser declarados no descritor. Portanto, o valor mínimo do intervalo de utilização da coleção pode ser 3, e o valor máximo de utilização deve ser suficientemente grande para atribuir ordinais a todas as formas de onda suportadas.

Se o máximo de uso for maior do que o número de formas de onda suportadas pelo dispositivo, o dispositivo deve relatar WAVEFORM_NONE para os ordinais não suportados.

O intervalo lógico do intervalo de uso deve incluir todos os usos de forma de onda suportados. A gama física e as unidades devem ser 0.

Lista de Duração (Obrigatório)

Esta coleção fornece as durações das formas de onda definidas na lista de formas de onda. O mínimo e o máximo de uso do intervalo de uso da coleção devem ser idênticos aos da lista de formas de onda.

As formas de onda discretas devem ter uma duração diferente de zero. WAVEFORM_NONE e WAVEFORM_STOP, se especificados, devem ter uma duração zero.

O mínimo lógico do intervalo de uso deve ser zero, e o máximo lógico deve ser pelo menos tão grande quanto a duração da forma de onda discreta mais longa. O host tratará os valores lógicos como milissegundos. O intervalo físico deve ser zero ou idêntico ao intervalo lógico. Se o intervalo físico e o intervalo lógico corresponderem, as unidades devem ser milissegundos.

Relatório de saída de gatilho manual

O anfitrião emitirá este relatório quando acionar um feedback háptico discreto. Este relatório de saída deve ter um ID de relatório dedicado.

Usos Obrigatórios e Opcionais
Membro Description Página ID Obrigatório/Opcional
Gatilho manual Forma de onda para disparar como comando explícito do host 0x0E 0x21 Mandatory
Intensidade Intensidade do feedback 0x0E 0x23 Mandatory
Número de repetições Número de vezes para repetir o feedback após o jogo inicial 0x0E 0x24 Opcional
Período de regatilho Duração do tempo de espera antes de acionar novamente o feedback ao repetir 0x0E 0x25 Opcional
Tempo de corte da forma de onda Tempo máximo em que o feedback pode ser reproduzido antes de ser cortado 0x0E 0x28 Opcional
Usos Proibidos
Usage ID Observações
Gatilho automático 0x20 Não suportado pelo anfitrião.
Controlo Associado ao Gatilho Automático 0x22 Não suportado pelo anfitrião.
Gatilho Manual (Obrigatório)

Este uso contém o ordinal da forma de onda, conforme definido a partir do relatório de recurso de informações da forma de onda, que foi solicitado para ser reproduzido pelo host. Quando um relatório de saída contendo um ordinal diferente de WAVEFORM_NONE é enviado para o dispositivo, ele deve começar imediatamente a reproduzir a forma de onda especificada com as propriedades adicionais incluídas no relatório de saída (Intensidade, Contagem de Repetição, Período de Reacionamento, Tempo de Corte, se suportado). O dispositivo só deve honrar ordinais para formas de onda discretas, WAVEFORM_NONE e WAVEFORM_STOP. Se o ordinal corresponder a WAVEFORM_STOP, qualquer reprodução de forma de onda discreta em curso deve ser interrompida. Se o ordinal corresponder a WAVEFORM_NONE, nenhuma ação deve ser executada e o feedback háptico contínuo deve continuar a ser reproduzido.

O intervalo lógico deve incluir todos os ordinais possíveis, incluindo os ordinais implícitos 1 (WAVEFORM_NONE) e 2 (WAVEFORM_STOP). A gama física e as unidades devem ser 0.

Intensidade (Obrigatório)

Este uso representa a percentagem de intensidade máxima a aplicar à forma de onda solicitada, com o máximo lógico a representar a intensidade máxima e o mínimo lógico a representar nenhum feedback.

O mínimo lógico deve ser zero, e o máximo lógico deve ser selecionado com base nas capacidades do dispositivo – por exemplo, se o dispositivo suporta quatro níveis de intensidade, o máximo lógico deve ser quatro. Se o dispositivo suporta intensidade mais granular, o máximo lógico pode ser maior, mas não deve exceder 100. O dispositivo deve suportar pelo menos quatro níveis de intensidade, de modo que o máximo lógico mínimo é quatro. Uma intensidade de zero indica que nenhum feedback deve ser jogado – o anfitrião só usará este valor para WAVEFORM_STOP.

A gama física e as unidades devem ser 0.

Repetir contagem (opcional)

Este uso representa o número de vezes para repetir a forma de onda após a reprodução inicial. Um valor zero indica que a forma de onda só deve ser tocada uma vez.

Se esse uso for suportado, o período de regatilho e os usos de tempo de corte também devem ser suportados.

O mínimo lógico deve ser zero e o máximo lógico deve ser maior que zero. O máximo lógico deve ser limitado a um pequeno valor (por exemplo, 10). A gama física e as unidades devem ser 0.

Período de reacionamento (opcional)

Este uso representa a duração entre os regatilhos da forma de onda, medida a partir da hora de início do gatilho anterior. Um valor de zero deve ser interpretado como idêntico à duração padrão para a forma de onda, de modo que o regatilho ocorre imediatamente após a conclusão da anterior. Valores inferiores à duração padrão para a forma de onda devem interromper a forma de onda e reiniciá-la.

Se esse uso for suportado, a contagem de repetições e os usos de tempo de corte também deverão ser suportados.

O host tratará os valores lógicos como milissegundos. O mínimo lógico deve ser zero e o máximo lógico deve ser pelo menos 1000 (representando um segundo). O intervalo físico deve ser zero ou idêntico ao intervalo lógico. Se o intervalo físico for diferente de zero, as unidades devem ser milissegundos.

Tempo de corte da forma de onda (opcional)

Esse uso representa a quantidade máxima de tempo que um único gatilho pode resultar em reprodução, levando em conta a contagem de repetições e o período de reacionamento.

Se esse uso for suportado, a contagem de repetições e os usos de regatilho também deverão ser suportados.

O host tratará os valores lógicos como milissegundos. O mínimo lógico deve ser pelo menos tão grande quanto a duração da forma de onda discreta mais longa, multiplicada pelo máximo lógico do uso da contagem repetida. O intervalo físico deve ser zero ou idêntico ao intervalo lógico. Se o intervalo físico for diferente de zero, as unidades devem ser milissegundos.

Orientação com Touchpad Háptico

Os itens desta secção aplicam-se apenas a touchpads táteis.

Device-Initiated Feedback háptico

Um touchpad háptico é responsável por acionar o feedback háptico quando determina que o botão de superfície do touchpad foi pressionado ou liberado. Ele pode optar por oferecer suporte a relatórios SET_FEATURE para permitir a personalização do usuário de seu comportamento ao fazer isso:

  • A intensidade do feedback háptico
  • A força necessária para acionar um botão pressionado

Ambos os relatórios de recursos são obrigatórios se o touchpad também suportar feedback háptico iniciado pelo host. Cada relatório deve usar um ID de relatório distinto, não usado com qualquer outro uso.

Durante a enumeração, o host avaliará o intervalo lógico e físico suportado a partir do descritor e calculará as opções expostas para a interface do usuário de configurações, incluindo os padrões. O anfitrião deve emitir o SET_FEATURE para comunicar o valor especificado pelo utilizador ao dispositivo; Essa emissão pode ocorrer a qualquer momento, mas deve ocorrer sempre que a configuração for alterada, ocorrer uma troca de usuário e quando o dispositivo for enumerado ou reiniciado.

Relatório de recursos de intensidade háptica

Este relatório de SET_FEATURE especifica a preferência do usuário pela intensidade do feedback háptico para pressionar e soltar botões. Ele NÃO se aplica à intensidade de qualquer feedback iniciado pelo host, se suportado pelo dispositivo. Para dar suporte a essa configuração, o dispositivo deve definir uma coleção filha lógica SimpleHapticsController (0x0E de Página, 0x01 de Uso) na coleção de nível superior do Windows Precision Touchpad, contendo o uso de Intensidade Háptica (Página 0x0E, 0x23 de Uso) como um relatório de recurso com uma ID de relatório dedicada. Essa coleção filho não deve conter os usos Gatilho Automático (0x0E de Página, 0x20 de Uso) ou Gatilho Manual (0x0E de Página, 0x21 de Uso).

O mínimo lógico deve ser igual a zero. A preferência do usuário será dimensionada linearmente para o intervalo lógico, com zero indicando que nenhum feedback deve ser acionado para pressionar e soltar botões.

Relatório de recursos de limite de pressionamento de botão

Este relatório SET_FEATURE especifica a preferência do usuário pela quantidade de força necessária para acionar um botão pressionado. Para dar suporte a essa configuração, o dispositivo deve definir o uso do Button Press Threshold (0x0D de Página, 0xB0 de Uso) como um relatório de recurso com uma ID de relatório dedicada na coleção de nível superior do Windows Precision Touchpad.

O intervalo lógico deve ser mapeado linearmente para o intervalo físico de valores e ser uniformemente espaçado e centrado em torno do valor padrão. Ao adquirir o intervalo lógico, o padrão será calculado usando a seguinte fórmula:

Diagrama mostrando a fórmula para calcular o limite de pressão do botão padrão em unidades lógicas

O Mínimo Lógico, o Padrão e o Máximo Lógico corresponderão a 3 níveis distintos de força de pressão do botão expostos a um usuário por meio da interface do usuário de configurações do Windows (suportando "Baixo", "Médio" e "Alto", respectivamente).

O intervalo físico recomendado para o Button Press Threshold é cobrir, pelo menos, o intervalo entre 110g e 190g, correspondendo aos valores mínimo e máximo, respectivamente. Para um descritor de exemplo utilizando um Máximo Físico de 190g e Mínimo Físico de 110g (assim, com base na fórmula acima, o padrão seria 150g), consulte Descritores de Relatório de Amostra.

Exemplos de Descritores de Relatório HID

Exemplo de Descritor do Touchpad Háptico

O descritor a seguir suporta todos os usos obrigatórios e opcionais. Ele declara suporte para cinco formas de onda, com a mais longa tendo uma duração de 50ms.

Todos os intervalos lógicos devem ser atualizados com base no suporte ao dispositivo. Para suportar um número diferente de formas de onda:

  • O intervalo lógico do uso do Gatilho Manual deve ser atualizado
  • Os intervalos de uso e a contagem de relatórios para Lista de Formas de Onda e Lista de Duração devem ser atualizados

Para suportar um comprimento máximo de forma de onda diferente, os seguintes intervalos lógicos devem ser atualizados:

  • Período de regatilho (saída)
  • Tempo de corte da forma de onda (saída)
  • Lista de Duração (Destaque)
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()

O descritor acima foi gerado através do seguinte arquivo 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'

Exemplo de Descrição de Rato Háptico

O descritor a seguir suporta todos os usos obrigatórios e opcionais. Declara suporte para oito formas de onda, sendo a mais longa com uma duração de 200ms.

Todos os intervalos lógicos devem ser atualizados com base no suporte ao dispositivo. Para suportar um número diferente de formas de onda:

  • O intervalo lógico do uso do Gatilho Manual deve ser atualizado
  • Os intervalos de uso e a contagem de relatórios para Lista de Formas de Onda e Lista de Duração devem ser atualizados

Para suportar um comprimento máximo de forma de onda diferente, os seguintes intervalos lógicos devem ser atualizados:

  • Período de regatilho (saída)
  • Tempo de corte da forma de onda (saída)
  • Lista de Duração (Destaque)
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()

O descritor acima foi gerado através do seguinte arquivo 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'