Partilhar via


Desenvolvendo drivers de cliente HID de teclado e mouse

Observação

Este artigo é para desenvolvedores que estão criando drivers para clientes HID de teclado e mouse. Se pretende corrigir um rato ou teclado, consulte:

Este artigo discute drivers HID de cliente para teclado e rato. Teclados e mouses representam o primeiro conjunto de clientes HID que foram padronizados nas tabelas de uso HID e implementados em sistemas operacionais Windows.

Controladores de cliente HID de teclado e rato são implementados na forma de controladores de mapeamento HID. Um driver de mapeador HID é um driver de filtro de modo kernel que fornece uma interface bidirecional para solicitações de E/S entre um driver de classe não-HID e o driver de classe HID. O driver do mapeador mapeia as solicitações de E/S e os protocolos de dados de um para o outro.

O Windows fornece drivers de mapeador HID fornecidos pelo sistema para dispositivos de teclado HID e mouses HID.

Arquitetura e visão geral

A figura a seguir ilustra as pilhas de drivers fornecidas pelo sistema para dispositivos de teclado, rato e touchpad USB.

Diagrama da pilha de drivers de teclado e mouse mostrando os drivers do mapeador de classe HID para teclados e mouses.

A figura mostra os seguintes componentes:

  • KBDHID.sys: Driver do mapeador de cliente HID para teclados. Converte utilizações HID em códigos de varredura para interagir com o driver de classe de teclado existente.
  • MOUHID.sys: Driver do mapeador de cliente HID para ratos e touchpads. Converte utilizações HID em comandos do rato (X/Y, botões, roda) para interagir com o driver de classe de teclado existente.
  • KBDCLASS.sys: O driver de classe de teclado fornece funcionalidade para todos os teclados e painéis de teclas no sistema de forma segura.
  • MOUCLASS.sys: O driver de classe de mouse fornece funcionalidade para todos os mouses e touchpads no sistema. O driver suporta dispositivos apontadores absolutos e relativos. MOUCLASS.sys não é o driver do Windows para telas sensíveis ao toque.
  • HIDCLASS.sys: O controlador da classe HID. O driver HID Class é a ligação entre os clientes HID KBDHID.sys e MOUHID.sys e vários meios de transporte, como USB, Bluetooth, entre outros.

O sistema cria a pilha de drivers da forma seguinte:

  • A pilha de transporte cria um objeto de dispositivo físico (DOP) para cada dispositivo HID conectado e carrega o driver de transporte HID apropriado, que, por sua vez, carrega o driver de classe HID.
  • O driver de classe HID cria um PDO para cada coleção de nível superior (TLC) de teclado ou mouse. Dispositivos HID complexos (mais de um TLC) são expostos como múltiplos PDOs gerados pelo controlador da classe HID. Por exemplo, um teclado com um mouse integrado pode ter uma coleção para os controles de teclado padrão e uma coleção diferente para o mouse.
  • Os drivers do mapeador de cliente HID para teclado ou mouse são carregados no objeto de dispositivo funcional (FDO) apropriado.
  • Os drivers do mapeador HID criam FDOs para teclado e mouse e carregam os drivers de classe.

Observações importantes

  • Os drivers de fornecedor não são necessários para teclados e ratos compatíveis com as utilizações HID suportadas e coleções principais.
  • Os fornecedores podem fornecer drivers de filtro na pilha do HID para alterar ou melhorar a funcionalidade destes TLC específicos.
  • Os fornecedores devem criar TLCs separados, específicos do fornecedor, para trocar dados proprietários entre seu cliente HID e o dispositivo. Evite usar controladores de filtro, a menos que seja absolutamente necessário.
  • O sistema abre todas as coleções de teclado e mouse para seu uso exclusivo.
  • O sistema impede a desativação/ativação de um teclado.
  • O sistema fornece suporte para rodas horizontais/verticais com capacidades de rolagem suave.

Orientação do condutor

A Microsoft fornece esta orientação para IHVs (fornecedores independentes de hardware) que escrevem drivers:

  1. Os desenvolvedores de drivers podem adicionar mais drivers na forma de um driver de filtro ou um novo driver de cliente HID.

    1. Drivers de filtro: os desenvolvedores de drivers devem garantir que seu driver com valor acrescentado seja um driver de filtro e não substitua (ou seja usado no lugar de) drivers HID do Windows existentes na pilha de entrada.

      • Os drivers de filtro são permitidos nestes cenários:
        • Como um filtro superior para kbdhid/mouhid
        • Como um filtro superior para kbdclass/mouclass
      • Os drivers de filtro não são recomendados como um filtro entre HIDCLASS e minidrivers de transporte HID
    2. Drivers de função: Como alternativa, os fornecedores podem criar um driver de função (em vez de um driver de filtro), mas apenas para PDOs HID específicos do fornecedor (com um serviço de modo de usuário, se necessário).

      Os drivers de função são permitidos nestes cenários:

      • Carregar apenas o hardware do fornecedor específico
    3. Minidrivers de transporte: a equipa do Windows não recomenda a criação de mais minidrivers de transporte HID, que são complicados de escrever e manter. Se um parceiro estiver criando um novo minidriver de transporte HID, especialmente em sistemas SoC, recomendamos uma revisão detalhada da arquitetura para entender o raciocínio e garantir que o driver seja desenvolvido corretamente.

  2. Os desenvolvedores de drivers devem usar estruturas de driver (KMDF ou UMDF) e não depender do WDM para seus drivers de filtro.

  3. Os desenvolvedores de drivers devem reduzir o número de transições de kernel-usuário entre os respetivos serviços e a pilha de drivers.

  4. Os desenvolvedores de drivers devem garantir a capacidade de despertar o sistema através da funcionalidade de teclado e touchpad (ajustável pelo usuário final (gerenciador de dispositivos) ou o fabricante do PC). Além disso, em sistemas SoC, esses dispositivos devem ser capazes de acordar de um estado de menor potência enquanto o sistema está em um estado S0 funcionando.

  5. Os desenvolvedores de drivers devem garantir que seu hardware seja gerenciado de forma eficiente.

    • O dispositivo pode entrar em seu estado de energia mais baixo quando o dispositivo está ocioso.
    • O dispositivo está no estado de energia mais baixo quando o sistema está em um estado de baixa energia (por exemplo, modo de espera (S3) ou modo de espera conectado).

Layout do teclado

Um layout de teclado descreve completamente as características de entrada de um teclado para o Microsoft Windows 2000 e versões posteriores. Por exemplo, um layout de teclado especifica o idioma, o tipo e a versão do teclado, modificadores, códigos de verificação e assim por diante.

Consulte estes recursos para obter informações sobre layouts de teclado:

  • Arquivo de cabeçalho do teclado, kdb.h, no Windows Driver Development Kit (DDK), que documenta informações gerais sobre layouts de teclado.
  • Exemplos de disposições de teclado.

Para visualizar o layout de um teclado específico, consulte Layouts de teclado do Windows.

Para obter mais detalhes sobre o layout do teclado, visite Painel de Controle\Relógio, Idioma e Região\Idioma.

Botões e rodas compatíveis em mouses

Esta lista identifica os recursos do mouse suportados pelo Windows:

  • Botões 1-5
  • Roda de rolagem vertical
  • Roda de rolagem horizontal
  • Suporte de roda de rolagem suave (horizontal e vertical)

Ativação dos botões 4-5 e da roda em ratos PS/2

O método usado pelo Windows para ativar o novo modo de quatro e cinco botões e roda é uma extensão do método usado para ativar o terceiro botão e a roda em mouses compatíveis com IntelliMouse:

  • O mouse é definido para o modo de roda de três botões, definindo a taxa de relatório para 200 relatórios por segundo, depois para 100 relatórios por segundo e, em seguida, para 80 relatórios por segundo. Em seguida, leia o ID do mouse. O rato deve reportar um ID 3 quando esta sequência for concluída.

  • O rato é então ajustado para o modo de roda de cinco botões, configurando a taxa de relatório inicialmente para 200 relatórios por segundo, e em seguida para 80 relatórios por segundo. Em seguida, leia o ID do mouse. Uma vez concluída a sequência, um rato de roda de cinco botões deve comunicar um ID de 4 (enquanto um rato de roda de três botões compatível com IntelliMouse ainda reporta um ID de 3).

Este método aplica-se apenas aos ratinhos PS/2 e não aos ratinhos HID. Os mouses HID devem reportar utilizações precisas no seu descritivo de relatório.

Formato de pacote de dados do mouse compatível com PS/2 padrão (dois botões)

byte D 7 D 6 D 5 D4 D 3 D 2 D 1 D0 Comentário
1 Yover Xover Ysign Xsign Etiqueta M R L X/Y transborda e sinais, botões
2 X7 X6 X5 X4 X3 X2 X1 X0 X byte de dados
3 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 Bytes de dados Y

Observação

Os drivers de mouse do Windows não verificam os bits de estouro. Se houver um transbordo, o mouse deve enviar o valor máximo de deslocamento assinado.

Formato de pacote de dados do mouse compatível com PS/2 padrão (três botões + roda vertical)

byte D 7 D 6 D 5 D4 D 3 D 2 D 1 D0 Comentário
1 0 0 Ysign Xsign 1 M R L Sinais X/Y e botões R/L/M
2 X7 X6 X5 X4 X3 X2 X1 X0 X byte de dados
3 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 Bytes de dados Y
4 Z7 Z6 Z5 Z4 Z3 Z2 Z1 Z0 Byte de dados Z/roda

Formato de pacote de dados do mouse compatível com PS/2 padrão (cinco botões + roda vertical)

byte D 7 D 6 D 5 D4 D 3 D 2 D 1 D0 Comentário
1 0 0 Ysign Xsign 1 M R L Sinais X/Y e botões R/L/M
2 X7 X6 X5 X4 X3 X2 X1 X0 X byte de dados
3 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 Bytes de dados Y
4 0 0 B5 B4 Z3 Z2 Z1 Z0 Dados do eixo Z/roda e botões 4 e 5

Importante

Os dados Z/wheel para um mouse de roda de cinco botões são reduzidos para quatro bits em vez dos oito bits usados no modo de roda de três botões compatível com IntelliMouse. Esta redução é possível pelo facto de a roda normalmente não conseguir gerar valores para além do intervalo +7/-8 durante um determinado período de interrupção. O sinal de drivers de mouse do Windows estende os quatro bits de dados Z/wheel quando o mouse está no modo de roda de cinco botões. Eles realizam a extensão de sinal do byte inteiro de dados Z da roda quando o rato opera no modo de roda com três botões.

Os botões 4 e 5 são mapeados para mensagens WM_APPCOMMAND e correspondem a "App_Back" e "App_Forward".

Dispositivos que não requerem drivers de fornecedor

Os drivers de fornecedor não são necessários para os seguintes dispositivos:

  • Dispositivos que estão em conformidade com o padrão HID.
  • Dispositivos de teclado, rato ou porta de jogo operados pelos controladores não-HIDClass fornecidos pelo sistema.

Amostra Kbfiltr

Kbfiltr é utilizado juntamente com Kbdclass, o driver de classe de sistema para dispositivos de teclado, e I8042prt, o driver de função para um teclado no estilo PS/2. Kbfiltr demonstra como filtrar solicitações de E/S e como adicionar rotinas de retorno de chamada que modificam a operação de Kbdclass e I8042prt.

Para obter mais informações sobre a operação do Kbfiltr, consulte:

Códigos de controlo Kbfiltr IO

As IOCTLs a seguir são usadas pelo Kbfiltr.

IOCTL_INTERNAL_I8042_HOOK_KEYBOARD

O IOCTL_INTERNAL_I8042_HOOK_KEYBOARD pedido:

  • Adiciona uma rotina de callback de inicialização à rotina de inicialização do teclado I8042prt.
  • Adiciona uma rotina de retorno de chamada ISR ao ISR do teclado I8042prt.

Os callbacks de inicialização e ISR são opcionais e são fornecidos por um driver de filtro superior para um teclado estilo PS/2.

Após o I8042prt receber um IOCTL_INTERNAL_KEYBOARD_CONNECT, ele envia uma solicitação síncrona IOCTL_INTERNAL_I8042_HOOK_KEYBOARD para o topo da pilha de dispositivos do teclado.

Depois que Kbfiltr recebe a solicitação de teclado de gancho, Kbfiltr filtra a solicitação da seguinte maneira:

  • Salva as informações de nível superior fornecidas ao Kbfiltr, que incluem o contexto de um objeto de dispositivo de nível superior, um ponteiro para um retorno de chamada de inicialização e um ponteiro para um retorno de chamada ISR.
  • Substitui as informações de nível hierárquico superior pelas suas.
  • Salva o contexto de I8042prt e ponteiros para callbacks que o callback ISR Kbfiltr pode usar.

IOCTL_INTERNAL_KEYBOARD_CONNECT

A solicitação IOCTL_INTERNAL_KEYBOARD_CONNECT conecta o serviço Kbdclass ao dispositivo de teclado. Kbdclass envia esta solicitação para baixo da pilha de dispositivos de teclado antes de abrir o dispositivo de teclado.

Depois que o Kbfiltr recebeu a solicitação de conexão do teclado, o Kbfiltr filtra a solicitação de conexão da seguinte maneira:

  • Salva uma cópia da estrutura CONNECT_DATA (Kbdclass) de Kbdclass que é passada para o driver de filtro por Kbdclass.
  • Substitui as suas próprias informações de conexão pelas informações de conexão do controlador de classe.
  • Envia a solicitação IOCTL_INTERNAL_KEYBOARD_CONNECT pela pilha de dispositivos.

Se a solicitação não for bem-sucedida, o Kbfiltr concluirá a solicitação com um status de erro apropriado.

Kbfiltr fornece um modelo para uma rotina de retorno de chamada de serviço de filtro que pode complementar a operação da KeyboardClassServiceCallback, que é a rotina de retorno de chamada de serviço da classe Kbdclass. O callback de serviço de filtro pode filtrar os dados de entrada transferidos do buffer de entrada do dispositivo para a fila de dados de classe.

IOCTL_INTERNAL_KEYBOARD_DISCONNECT

A solicitação de IOCTL_INTERNAL_KEYBOARD_DISCONNECT é concluída com um status de STATUS_NOT_IMPLEMENTED. O gestor Plug and Play pode adicionar ou remover um teclado Plug and Play.

Para todas as outras solicitações de controle de dispositivo, o Kbfiltr ignora a pilha de IRP atual e envia a solicitação para baixo da pilha de dispositivos sem processamento adicional.

Rotinas de retorno de chamada implementadas pelo Kbfiltr

O Kbfiltr implementa as seguintes rotinas de callback.

KbFilter_InitializationRoutine

Visualizar PI8042_KEYBOARD_INITIALIZATION_ROUTINE

O KbFilter_InitializationRoutine não é necessário se a inicialização padrão I8042prt de um teclado for suficiente.

I8042prt chama KbFilter_InitializationRoutine quando inicializa o teclado. A inicialização padrão do teclado inclui as seguintes operações:

  • Redefinir o teclado
  • definir a taxa tipomática e o atraso
  • definir os díodos emissores de luz (LED)
/*
Parameters
DeviceObject [in]
Pointer to the device object that is the context for this callback.

SynchFuncContext [in]
Pointer to the context for the routines pointed to by ReadPort and Writeport.

ReadPort [in]
Pointer to the system-supplied PI8042_SYNCH_READ_PORT callback that reads from the port.

WritePort [in]
Pointer to the system-supplied PI8042_SYNCH_WRITE_PORT callback that writes to the port.

TurnTranslationOn [out]
Specifies, if TRUE, to turn translation on. Otherwise, translation is turned off.

Return value
KbFilter_InitializationRoutine returns an appropriate NTSTATUS code.
*/

NTSTATUS KbFilter_InitializationRoutine(
  In  PDEVICE_OBJECT          DeviceObject,
  In  PVOID                   SynchFuncContext,
  In  PI8042_SYNCH_READ_PORT  ReadPort,
  In  PI8042_SYNCH_WRITE_PORT WritePort,
  Out PBOOLEAN                TurnTranslationOn
);

KbFilter_IsrHook

Ver PI8042_KEYBOARD_ISR. Este retorno de chamada não é necessário se a operação padrão do I8042prt for suficiente.

O teclado I8042prt ISR chama KbFilter_IsrHook após validar a interrupção e ler o código de varredura.

KbFilter_IsrHook é executado no modo kernel no IRQL do teclado I8042prt.

/*
Parameters
DeviceObject [in]
Pointer to the filter device object of the driver that supplies this callback.

CurrentInput [in]
Pointer to the input KEYBOARD_INPUT_DATA structure that is being constructed by the ISR.

CurrentOutput [in]
Pointer to an OUTPUT_PACKET structure that specifies the bytes that are being written to the hardware device.

StatusByte [in, out]
Specifies the status byte that is read from I/O port 60 when an interrupt occurs.

DataByte [in]
Specifies the data byte that is read from I/O port 64 when an interrupt occurs.

ContinueProcessing [out]
Specifies, if TRUE, to continue processing in the I8042prt keyboard ISR after this callback returns; otherwise, processing is not continued.

ScanState [in]
Pointer to a KEYBOARD_SCAN_STATE structure that specifies the keyboard scan state.

Return value
KbFilter_IsrHook returns TRUE if the interrupt service routine should continue; otherwise it returns FALSE.
*/

KbFilter_IsrHook KbFilter_IsrHook(
  In    PDEVICE_OBJECT       DeviceObject,
  In    PKEYBOARD_INPUT_DATA CurrentInput,
  In    POUTPUT_PACKET       CurrentOutput,
  Inout UCHAR                StatusByte,
  In    PUCHAR               DataByte,
  Out   PBOOLEAN             ContinueProcessing,
  In    PKEYBOARD_SCAN_STATE ScanState
);

KbFilter_ServiceCallback

Ver PSERVICE_CALLBACK_ROUTINE.

A rotina de conclusão de envio do ISR do driver de função chama KbFilter_ServiceCallback, que então chama a implementação de PSERVICE_CALLBACK_ROUTINE do driver de classe de teclado. Um fornecedor pode implementar um callback de serviço de filtro para modificar os dados de entrada que são transferidos do buffer de entrada do dispositivo para a fila de dados de classe. Por exemplo, o retorno de chamada pode excluir, transformar ou inserir dados.

/*
Parameters
DeviceObject [in]
Pointer to the class device object.

InputDataStart [in]
Pointer to the first keyboard input data packet in the input data buffer of the port device.

InputDataEnd [in]
Pointer to the keyboard input data packet that immediately follows the last data packet in the input data buffer of the port device.

InputDataConsumed [in, out]
Pointer to the number of keyboard input data packets that are transferred by the routine.

Return value
None
*/

VOID KbFilter_ServiceCallback(
  In    PDEVICE_OBJECT       DeviceObject,
  In    PKEYBOARD_INPUT_DATA InputDataStart,
  In    PKEYBOARD_INPUT_DATA InputDataEnd,
  Inout PULONG               InputDataConsumed
);

Amostra de Moufiltr

Moufiltr funciona com o Mouclass, o driver de classe do sistema para dispositivos de rato. Este também funciona com o I8042prt, o driver de função para um rato do tipo PS/2. Ambos os drivers são usados com o Windows 2000 e versões posteriores. Moufiltr demonstra como filtrar solicitações de E/S e adicionar rotinas de retorno de chamada que modificam a operação de Mouclass e I8042prt.

Para obter mais informações sobre a operação Moufiltr, consulte estes recursos:

Códigos de controlo I/O Moufiltr

Os seguintes IOCTLs são utilizados por Moufiltr.

IOCTL_INTERNAL_I8042_HOOK_MOUSE

A solicitação IOCTL_INTERNAL_I8042_HOOK_MOUSE adiciona uma rotina de retorno de chamada ISR ao ISR do mouse I8042prt. O _callback_ ISR é opcional e é fornecido por um driver de filtro de nível superior para o mouse.

I8042prt envia este pedido depois de receber um pedido de IOCTL_INTERNAL_MOUSE_CONNECT . I8042prt envia uma solicitação IOCTL_INTERNAL_I8042_HOOK_MOUSE síncrona para o topo da pilha de dispositivos do rato.

Depois que Moufiltr recebe a solicitação do mouse de gancho, ele filtra a solicitação da seguinte maneira:

  • Salva as informações de nível superior passadas para o Moufiltr, que incluem o contexto de um objeto de dispositivo de nível superior e um ponteiro para um callback ISR.
  • Substitui as informações de nível superior pelas suas.
  • Salva o contexto do I8042prt e os ponteiros para callbacks que os retornos de chamada ISR do Moufiltr podem utilizar.

IOCTL_INTERNAL_MOUSE_CONNECT

A solicitação de IOCTL_INTERNAL_MOUSE_CONNECT conecta o serviço Mouclass a um dispositivo de mouse.

Comando IOCTL_INTERNAL_MOUSE_DISCONNECT (desconexão interna do rato)

Moufiltr conclui a solicitação de IOCTL_INTERNAL_MOUSE_DISCONNECT com um status de erro de STATUS_NOT_IMPLEMENTED.

Para todas as outras solicitações, Moufiltr ignora a pilha IRP atual e envia a solicitação para baixo da pilha de dispositivos sem processamento adicional.

Rotinas de callback Moufiltr

MouFiltr implementa as seguintes rotinas de retorno de chamada.

MouFilter_IsrHook

Consulte PI8042_MOUSE_ISR.

/*
Parameters
DeviceObject
Pointer to the filter device object of the driver that supplies this callback.

CurrentInput
Pointer to the input MOUSE_INPUT_DATA structure being constructed by the ISR.

CurrentOutput
Pointer to the OUTPUT_PACKET structure that specifies the bytes being written to the hardware device.

StatusByte
Specifies a status byte that is read from I/O port 60 when the interrupt occurs.

DataByte
Specifies a data byte that is read from I/O port 64 when the interrupt occurs.

ContinueProcessing
Specifies, if TRUE, that the I8042prt mouse ISR continues processing after this callback returns. Otherwise, processing is not continued.

MouseState
Pointer to a MOUSE_STATE enumeration value, which identifies the state of mouse input.

ResetSubState
Pointer to MOUSE_RESET_SUBSTATE enumeration value, which identifies the mouse reset substate. See the Remarks section.

Return value
MouFilter_IsrHook returns TRUE if the interrupt service routine should continue; otherwise it returns FALSE.
*/

BOOLEAN MouFilter_IsrHook(
   PDEVICE_OBJECT        DeviceObject,
   PMOUSE_INPUT_DATA     CurrentInput,
   POUTPUT_PACKET        CurrentOutput,
   UCHAR                 StatusByte,
   PUCHAR                DataByte,
   PBOOLEAN              ContinueProcessing,
   PMOUSE_STATE          MouseState,
   PMOUSE_RESET_SUBSTATE ResetSubState
);

Um callback MouFilter_IsrHook não é necessário se a operação padrão do I8042prt for suficiente.

O ISR do mouse I8042prt chama MouFilter_IsrHook depois que ele valida a interrupção.

Para reinicializar um mouse, o I8042prt passa por uma sequência de subestados operacionais. Um valor de enumeração MOUSE_RESET_SUBSTATE identifica cada subestado. Para obter mais informações sobre como I8042prt redefine um mouse e os subestados de redefinição do mouse correspondentes, consulte a documentação do MOUSE_RESET_SUBSTATE em ntdd8042.h.

MouFilter_IsrHook é executado no modo kernel no IRQL do ISR do mouse I8042prt.

MouFilter_ServiceCallback

Visualizar PSERVICE_CALLBACK_ROUTINE

/*
Parameters
DeviceObject [in]
Pointer to the class device object.

InputDataStart [in]
Pointer to the first mouse input data packet in the input data buffer of the port device.

InputDataEnd [in]
Pointer to the mouse input data packet immediately following the last data packet in the port device's input data buffer.

InputDataConsumed [in, out]
Pointer to the number of mouse input data packets that are transferred by the routine.

Return value
None
*/

VOID MouFilter_ServiceCallback(
  _In_    PDEVICE_OBJECT    DeviceObject,
  _In_    PMOUSE_INPUT_DATA InputDataStart,
  _In_    PMOUSE_INPUT_DATA InputDataEnd,
  _Inout_ PULONG            InputDataConsumed
);

O ISR DPC de I8042prt chama MouFilter_ServiceCallback, que então chama MouseClassServiceCallback. Um callback de serviço de filtro pode ser configurado para modificar os dados de entrada que são transferidos do buffer de entrada do dispositivo para a fila de dados da classe. Por exemplo, o retorno de chamada pode excluir, transformar ou inserir dados.