Поделиться через


Разработка драйверов клиентов HID клавиатуры и мыши

Замечание

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

В этой статье рассматриваются драйверы клиентов HID с клавиатуры и мыши. Клавиатуры и мыши представляют первый набор клиентов HID, которые были стандартизированы в таблицах использования HID и реализованы в операционных системах Windows.

Драйверы клиентов HID с клавиатурой и мышью реализованы в виде драйверов mapper HID. Драйвер mapper HID — это драйвер фильтра в режиме ядра, который предоставляет двунаправленный интерфейс для запросов ввода-вывода между драйвером класса, отличным от HID, и драйвером класса HID. Сопоставляющий драйвер сопоставляет запросы ввода-вывода и протоколы данных одного с другим.

Windows предоставляет драйверы сопоставления HID, предоставляемые системой, для HID-клавиатуры и HID-мышей.

Архитектура и обзор

На следующем рисунке показаны системные стеки драйверов для USB-клавиатуры, мыши и сенсорной панели.

Схема стека драйверов клавиатуры и мыши, показывающая драйверы сопоставления класса HID для клавиатур и мышей.

На рисунке показаны следующие компоненты:

  • KBDHID.sys: драйвер сопоставления клиента HID для клавиатур. Преобразует коды использования HID в коды сканирования для взаимодействия с существующим драйвером класса клавиатуры.
  • MOUHID.sys: драйвер соответствия клиента HID для мышей и сенсорных панелей. Преобразует использование HID в команды мыши (X/Y, кнопки, колесо) для интерфейса с существующим драйвером класса клавиатуры.
  • KBDCLASS.sys: драйвер класса клавиатуры предоставляет функциональные возможности для всех клавиатур и клавиатур на системе безопасным образом.
  • MOUCLASS.sys: драйвер класса мыши предоставляет функциональные возможности для всех мышей и сенсорной панели в системе. Драйвер поддерживает как абсолютные, так и относительные указатели устройств. MOUCLASS.sys не является драйвером Windows для сенсорных экранов.
  • HIDCLASS.sys: драйвер класса HID. Драйвер класса HID обеспечивает связь между клиентами HID KBDHID.sys и MOUHID.sys и различными интерфейсами, такими как USB, Bluetooth и т. д.

Система создает стек драйверов следующим образом:

  • Стек транспорта создает объект физического устройства (PDO) для каждого подключенного устройства HID и загружает соответствующий драйвер транспорта HID, который, в свою очередь, загружает драйвер класса HID.
  • Драйвер класса HID создает PDO для каждой клавиатуры или коллекции верхнего уровня мыши (TLC). Сложные устройства HID (более одного TLC) предоставляются в виде нескольких объектов PDO, созданных драйвером класса HID. Например, клавиатура с встроенной мышью может иметь одну коллекцию для стандартных элементов управления клавиатуры и другой коллекции для мыши.
  • Драйверы карты клиента HID или клавиатуры или мыши загружаются на соответствующий функциональный объект устройства (FDO).
  • Драйверы HID mapper создают FDO для клавиатуры и мыши и загружают классовые драйверы.

Важные заметки

  • Драйверы поставщиков не требуются для клавиатур и мышей, совместимых с поддерживаемыми сценариями использования HID и коллекциями верхнего уровня.
  • Поставщики при необходимости предоставляют драйверы фильтров в стеке HID для изменения и улучшения функциональности этих конкретных TLC.
  • Поставщики должны создавать отдельные, специфичные для них TLCs для обмена собственными данными между клиентом HID и устройством. Избегайте использования драйверов фильтров, если это не критически важно.
  • Система открывает все коллекции клавиатуры и мыши для своего эксклюзивного использования.
  • Система предотвращает отключение и включение клавиатуры.
  • Система обеспечивает поддержку горизонтальных или вертикальных колес с плавной прокруткой.

Инструкция для водителя

Корпорация Майкрософт предоставляет это руководство для независимых поставщиков оборудования (IHV) для написания драйверов:

  1. Разработчики драйверов могут добавлять дополнительные драйверы в виде драйвера фильтра или нового драйвера клиента HID.

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

      • Драйверы фильтров разрешены в следующих сценариях:
        • В качестве верхнего фильтра для kbdhid/mouhid
        • Как верхний фильтр для kbdclass/mouclass
      • Драйверы фильтров не рекомендуются в качестве промежуточного слоя между HIDCLASS и миндрайверами HID.
    2. Драйверы функций. Кроме того, поставщики могут создавать драйвер функции (вместо драйвера фильтра), но только для конкретных поставщиков HID PDOS (при необходимости с службой пользовательского режима).

      Драйверы функций разрешены в следующих сценариях:

      • Загружайте только на оборудование конкретного поставщика
    3. Водители транспортных средств: команда Windows не рекомендует создавать дополнительные минидрайверы транспортного уровня HID, так как они сложны для написания и сопровождения. Если партнер разрабатывает новый минидрайвер транспорта HID, особенно для систем SoC, мы рекомендуем провести подробный обзор архитектуры, чтобы понять цели и убедиться, что драйвер разработан правильно.

  2. Разработчики драйверов должны использовать платформы драйверов (KMDF или UMDF) и не полагаться на WDM для драйверов фильтров.

  3. Разработчики драйверов должны сократить количество переходов между службой ядра и стеком драйверов.

  4. Разработчики драйверов должны обеспечить возможность пробуждения системы с помощью функции клавиатуры и сенсорной панели (настраиваемая конечным пользователем (диспетчером устройств) или производителем пк). В дополнение к системам SoC эти устройства должны иметь возможность пробуждения из состояния с пониженным энергопотреблением, пока система находится в рабочем состоянии S0.

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

    • Устройство может перейти в минимальное состояние питания, когда устройство неактивно.
    • Устройство находится в самом низком состоянии питания, когда система находится в состоянии низкой мощности (например, в режиме ожидания (S3) или подключенном режиме ожидания.

Раскладка клавиатуры

Макет клавиатуры полностью описывает входные характеристики клавиатуры для Microsoft Windows 2000 и более поздних версий. Например, раскладка клавиатуры указывает язык, тип клавиатуры и версию, модификаторы, коды сканирования и т. д.

Дополнительные сведения о раскладках клавиатуры см. в следующих ресурсах:

  • Файл заголовка клавиатуры kdb.h в пакете средств разработки драйверов Windows (DDK), который содержит общие сведения о раскладках клавиатуры.
  • Примеры раскладок клавиатуры.

Чтобы визуализировать макет определенной клавиатуры, см. статью "Макеты клавиатуры Windows".

Дополнительные сведения о макете клавиатуры см. в панели управления в разделе "Часы, язык и регион" -> "Язык".

Поддерживаемые кнопки и колеса на мышах

Этот список определяет функции мыши, поддерживаемые Windows:

  • Кнопки 1-5
  • Вертикальное колесо прокрутки
  • Горизонтальное колесо прокрутки
  • Поддержка плавной прокрутки (горизонтальная и вертикальная)

Активация кнопок 4-5 и колесика на мышах PS/2

Метод, используемый Windows для активации новых четырех и пяти кнопок и режима колесика является расширением метода, используемого для активации третьей кнопки и колеса в мышах, совместимых с IntelliMouse:

  • Мышь переводится в режим колесика с тремя кнопками, задав частоту отчетов в 200 отчетов в секунду; затем 100 отчетов в секунду, затем 80 отчетов в секунду. Затем считывание идентификатора с мыши. При завершении этой последовательности мышь должна сообщить идентификатор 3.

  • Затем мышь устанавливается в режим колесика с пятью кнопками, установив скорость отчета сначала в 200 отчетов в секунду, затем снова в 200 отчетов в секунду, а затем в 80 отчетов в секунду. Затем считывание идентификатора с мыши. После завершения последовательности мышь с колесиком и пятью кнопками должна выдавать идентификатор 4 (в то время как совместимые с IntelliMouse трёхкнопочные мыши будут по-прежнему выдавать идентификатор 3).

Этот метод применим только к мышам PS/2, а не к мышам HID. Мыши HID должны сообщать точные сведения об использовании в дескрипторе отчета.

Стандартный формат данных PS/2-совместимой мыши (две кнопки)

Байт D7 D6 D5 D4 D3 D2 D1 D0 Комментарий
1 Yover Xover Ysign Xsign Тег M Р L Переполнение и знаки X/Y, кнопки
2 X7 X6 x5 x4 x3 X2 X1 X0 Байт данных X
3 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 Байты данных Y

Замечание

Драйверы мыши Windows не проверяют биты переполнения. Если есть переполнение, мышь должна отправить максимальное значение смещения со знаком.

Стандартный формат пакетов данных с мышью, совместимый с PS/2 (три кнопки + вертикальное колесо)

Байт D7 D6 D5 D4 D3 D2 D1 D0 Комментарий
1 0 0 Ysign Xsign 1 M Р L Знаки X/Y и кнопки R/L/M
2 X7 X6 x5 x4 x3 X2 X1 X0 Байт данных X
3 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 Байты данных Y
4 Z7 Z6 Z5 Z4 Z3 Z2 Z1 Z0 Байт данных Z/wheel

Стандартный формат пакетов данных мыши с совместимостью PS/2 (пять кнопок + вертикальное колесо)

Байт D7 D6 D5 D4 D3 D2 D1 D0 Комментарий
1 0 0 Ysign Xsign 1 M Р L Знаки X/Y и кнопки R/L/M
2 X7 X6 x5 x4 x3 X2 X1 X0 Байт данных X
3 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 Байты данных Y
4 0 0 B5 B4 Z3 Z2 Z1 Z0 Данные z/wheel и кнопки 4 и 5

Это важно

Данные Z/wheel для колесика с пятью кнопками сокращаются до четырех битов вместо восьми битов, используемых в режиме колесика, совместимого с IntelliMouse с тремя кнопками. Это сокращение возможно тем, что колесо обычно не может генерировать значения за пределами диапазона +7/-8 в течение любого заданного периода прерывания. Драйверы мыши Windows расширяют знаковый бит для четырех битов данных Z/колеса, если мышь работает в режиме пяти кнопок. Они расширяют полный байт данных Z/wheel, когда мышь работает в режиме трех кнопки колесика.

Кнопки 4 и 5 привязаны к сообщениям WM_APPCOMMAND и соответствуют App_Back и App_Forward.

Устройства, не требующие драйверов поставщиков

Драйверы поставщиков не требуются для следующих устройств:

  • Устройства, соответствующие стандарту HID.
  • Устройства клавиатуры, мыши или игровые порты, управляемые драйверами, предоставляемыми системой и не относящимися к HIDClass.

Пример Kbfiltr

Kbfiltr используется с Kbdclass, системным драйвером класса для клавиатурных устройств и I8042prt, драйвером функций для клавиатуры в стиле PS/2. Kbfiltr демонстрирует фильтрацию запросов ввода-вывода и добавление подпрограмм обратного вызова, которые изменяют операцию Kbdclass и I8042prt.

Дополнительные сведения об операции Kbfiltr см. в следующем разделе:

  • Файл заголовка ntddkbd.h WDK.

  • Пример исходного кода Kbfiltr .

Коды управления ввода-вывода Kbfiltr

Следующие IOCTL используются kbfiltr.

IOCTL_INTERNAL_I8042_HOOK_KEYBOARD

Запрос типа IOCTL_INTERNAL_I8042_HOOK_KEYBOARD:

  • Добавляет подпрограмму обратного вызова к процедуре инициализации клавиатуры I8042prt.
  • Добавляет подпрограмму обратного вызова ISR для клавиатурного ISR I8042prt.

Обратные вызовы инициализации и ISR являются необязательными и предоставляются драйвером фильтра верхнего уровня для устройства клавиатуры в стиле PS/2.

После того как I8042prt получает запрос IOCTL_INTERNAL_KEYBOARD_CONNECT, он отправляет синхронный запрос IOCTL_INTERNAL_I8042_HOOK_KEYBOARD в верхнюю часть стека устройств клавиатуры.

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

  • Сохраняет сведения верхнего уровня, передаваемые в Kbfiltr, который включает контекст объекта устройства верхнего уровня, указатель на обратный вызов инициализации и указатель на обратный вызов ISR.
  • Заменяет сведения верхнего уровня собственными.
  • Сохраняет контекст I8042prt и указателей на обратные вызовы, которые может использовать обратный вызов ISR Kbfiltr.

IOCTL_INTERNAL_KEYBOARD_CONNECT

Запрос IOCTL_INTERNAL_KEYBOARD_CONNECT подключает службу Kbdclass к устройству клавиатуры. Kbdclass отправляет этот запрос вниз стек устройства клавиатуры перед открытием устройства клавиатуры.

После получения запроса подключения к клавиатуре Kbfiltr фильтрует запрос подключения следующим образом:

  • Сохраняет копию структуры CONNECT_DATA (Kbdclass), которую Kbdclass передаёт драйверу фильтра.
  • Заменяет информацию о подключении драйвера класса на собственную.
  • Отправляет запрос IOCTL_INTERNAL_KEYBOARD_CONNECT вниз стеку устройств.

Если запрос не выполнен успешно, Kbfiltr завершает запрос с соответствующим состоянием ошибки.

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

IOCTL_INTERNAL_KEYBOARD_DISCONNECT

Запрос IOCTL_INTERNAL_KEYBOARD_DISCONNECT завершен с состоянием STATUS_NOT_IMPLEMENTED. Диспетчер Plug and Play может добавлять или удалять клавиатуру Plug and Play.

Для всех других запросов на управление устройствами Kbfiltr пропускает текущий стек IRP и отправляет запрос вниз стека устройства без дальнейшей обработки.

Рутины обработки обратного вызова, реализованные в Kbfiltr

Kbfiltr реализует следующие колбэк-функции.

KbFilter_InitializationRoutine

См . PI8042_KEYBOARD_INITIALIZATION_ROUTINE

KbFilter_InitializationRoutine не требуется, если инициализация клавиатуры по умолчанию i8042prt является достаточной.

I8042prt вызывает KbFilter_InitializationRoutine при инициализации клавиатуры. Инициализация клавиатуры по умолчанию включает следующие операции:

  • сброс настроек клавиатуры
  • Установка скорости и задержки повторной печати
  • настройте светодиоды
/*
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

См. PI8042_KEYBOARD_ISR. Этот обратный вызов не требуется, если стандартная работа драйвера I8042prt достаточна.

Обработчик прерываний клавиатуры I8042prt вызывает KbFilter_IsrHook после проверки прерывания, а затем считывает код сканирования.

KbFilter_IsrHook выполняется в режиме ядра на уровне IRQL клавиатуры 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

См. PSERVICE_CALLBACK_ROUTINE.

Подпрограмма завершения отправки ISR драйвера функции вызывает KbFilter_ServiceCallback, которая затем вызывает реализацию драйвера класса клавиатуры PSERVICE_CALLBACK_ROUTINE. Поставщик может реализовать обратный вызов службы фильтра для изменения входных данных, передаваемых из входного буфера устройства в очередь данных класса. Например, обратный вызов может удалять, преобразовывать или вставлять данные.

/*
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
);

Пример Moufiltr

Moufiltr работает с Mouclass, системным драйвером классового уровня для устройств мыши. Он также работает с I8042prt, функциональным драйвером для мыши в стиле PS/2. Оба драйвера используются с Windows 2000 и более поздними версиями. Moufiltr демонстрирует, как фильтровать запросы ввода-вывода и добавлять подпрограммы обратного вызова, которые изменяют операцию Mouclass и I8042prt.

Дополнительные сведения об операции Moufiltr см. в следующих ресурсах:

  • Файл заголовка ntddmou.h WDK.

  • Пример исходного кода Moufiltr .

Коды управления ввода-вывода Moufiltr

Следующие ioCTLs используются Moufiltr.

IOCTL_INTERNAL_I8042_HOOK_MOUSE

Запрос IOCTL_INTERNAL_I8042_HOOK_MOUSE добавляет подпрограмму обратного вызова ISR в ISR мыши I8042prt. Обратный вызов ISR является необязательным и предоставляется драйвером фильтра мыши верхнего уровня.

I8042prt отправляет этот запрос после получения запроса IOCTL_INTERNAL_MOUSE_CONNECT . I8042prt отправляет синхронный запрос IOCTL_INTERNAL_I8042_HOOK_MOUSE в начало стека устройств мыши.

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

  • Сохраняет сведения верхнего уровня, передаваемые в Moufiltr, которая включает контекст объекта устройства верхнего уровня и указатель на обратный вызов ISR.
  • Заменяет сведения верхнего уровня собственными.
  • Сохраняет контекст I8042prt и указатели на функции обратного вызова, которые могут использоваться функциями ISR Moufiltr.

IOCTL_INTERNAL_MOUSE_CONNECT

Запрос IOCTL_INTERNAL_MOUSE_CONNECT подключает службу Mouclass к устройству мыши.

IOCTL_INTERNAL_MOUSE_DISCONNECT (Внутреннее отключение мыши через IOCTL)

Moufiltr завершает запрос IOCTL_INTERNAL_MOUSE_DISCONNECT с состоянием ошибки STATUS_NOT_IMPLEMENTED.

Для всех других запросов Moufiltr пропускает текущий стек IRP и отправляет запрос вниз по стеку устройств без дополнительной обработки.

Подпрограммы обратного вызова для Moufiltr

MouFiltr реализует следующие функции обратного вызова.

MouFilter_IsrHook

См. 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
);

Обратный вызов MouFilter_IsrHook не нужен, если операция по умолчанию I8042prt достаточна.

I8042prt мышь ISR вызывает MouFilter_IsrHook после проверки прерывания.

Чтобы сбросить мышь, I8042prt проходит через последовательность этапов операционной деятельности. Значение перечисления MOUSE_RESET_SUBSTATE определяет каждое подсостояние. Дополнительные сведения о том, как I8042prt сбрасывает мышь и соответствующие подстатки сброса мыши, см. в документации по MOUSE_RESET_SUBSTATE в ntdd8042.h.

MouFilter_IsrHook выполняется в режиме ядра в IRQL мыши I8042prt ISR.

MouFilter_ServiceCallback

См. 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
);

DPC ISR I8042prt вызывает MouFilter_ServiceCallback, которая затем вызывает MouseClassServiceCallback. Обратный вызов службы фильтра можно настроить для изменения входных данных, передаваемых из входного буфера устройства в очередь данных класса. Например, обратный вызов может удалять, преобразовывать или вставлять данные.