键盘和鼠标类驱动程序的配置

注意

本主题适用于正在配置键盘和鼠标类驱动程序的开发人员。 如果要修复鼠标或键盘,请参阅:

非 HID 键盘和鼠标可以通过多个旧式总线进行连接,但仍使用相同的类驱动程序。 本部分包含有关类驱动程序本身的详细信息。 以下部分详细介绍了控制器。

本主题介绍 Microsoft Windows 2000 及更高版本中键盘和鼠标设备的典型物理配置。

下图显示了使用单个键盘和单个鼠标的两个常见配置。

说明使用单个键盘和单个鼠标的两个配置的关系图。

左侧的图显示了通过独立控制器连接到系统总线的键盘和鼠标。 典型的配置包括通过 i8042 控制器操作的 PS/2 样式键盘和通过串行端口控制器操作的串行样式鼠标。

以下附加信息对于键盘和鼠标制造商非常重要:

  • 出于安全原因,操作系统堆栈以独占模式打开键盘
  • Windows 支持同时连接多个键盘和鼠标设备。
  • Windows 不支持客户端对每台设备进行独立访问。

类驱动程序功能

本主题介绍以下 Microsoft Windows 2000 及更高版本系统类驱动程序的功能:

  • Kbdclass,适用于GUID_CLASS_KEYBOARD设备类的设备的类驱动程序

  • Mouclass,GUID_CLASS_MOUSE设备类的设备的类驱动程序

Kbdclass 实现 Kbdclass 服务,其可执行映像 kbdclass.sys。

Mouclass 实现 Mouclass 服务,其可执行映像 mouclass.sys。

Kbdclass 和 Mouclass 每个功能:

  • 设备类的泛型和与硬件无关的操作。

  • 即插即用、电源管理和 Windows Management Instrumentation (WMI) 。

  • 旧设备的操作。

  • 同时操作多个设备。

  • 服务回调例程 的连接,函数驱动程序使用该例程将数据从设备的输入数据缓冲区传输到类驱动程序的数据缓冲区。

设备对象的配置

下图显示了即插即用 PS/2 样式键盘和鼠标设备的设备对象的配置。 每个类驱动程序创建一个高级类 筛选器设备对象 , (筛选器 DO) ,该对象通过可选的上层设备筛选器 DO 附加到函数设备对象 (FDO) 。 上层设备筛选器驱动程序创建上层设备筛选器 DO。 I8042prt 创建函数 DO,并将其附加到根总线驱动程序创建的 PDO) (物理设备对象。

说明即插即用 ps/2 样式键盘和鼠标设备的设备对象的配置的示意图。

PS/2 键盘

键盘驱动程序堆栈包括以下内容。

  • Kbdclass,上层键盘类筛选器驱动程序
  • 一个或多个可选的上层键盘筛选器驱动程序
  • I8042prt,函数驱动程序

PS/2 鼠标

鼠标驱动程序堆栈由以下内容组成。

  • Mouclass,上层鼠标类筛选器驱动程序
  • 一个或多个可选的上层鼠标筛选器驱动程序
  • I8042prt,函数驱动程序

KbdclassMouclass 可以在两种不同模式下支持多个设备。 在 一对一模式下,每个设备都有一个独立的设备堆栈。 类驱动程序创建独立的类 DO 并将其附加到每个设备堆栈。 每个设备堆栈都有自己的控制状态和输入缓冲区。 Microsoft Win32 子系统通过唯一的文件对象访问来自每个设备的输入。

grandmaster 模式下,类驱动程序按以下方式操作所有设备:

  • 类驱动程序同时创建表示所有设备的 grandmaster 类 DO 和每个设备的 从属类 DO

    类驱动程序将一个从属类 DO 附加到每个设备堆栈。 在从属类 DO 下,设备堆栈与在一对一模式下创建的堆栈相同。

  • grandmaster 类 DO 控制所有从属 DO 的操作。

  • Win32 子系统通过表示 grandmaster 类设备的文件对象访问所有设备输入。

  • 所有设备输入都在主数据库的数据队列中缓冲。

  • 主管理员维护单个全局设备状态。

如果 Kbdclass 和 Mouclass 的注册表项值 ConnectMultiplePorts 设置为在键 HKLM\Services\CurrentControlSet<\class service>\Parameters 下0x00 (,则其注册表项值 ConnectMultiplePorts 在一对一模式下运行,其中 类服务 为 Kbdclass 或 Mouclass) 。 否则,Kbdclass 和 Mouclass 在 grandmaster 模式下运行。

通过类驱动程序打开和关闭

Microsoft Win32 子系统可打开所有键盘和鼠标设备供其独占使用。 对于每个设备类,Win32 子系统将来自所有设备的输入视为输入来自单个输入设备。 应用程序无法请求仅接收来自一个特定设备的输入。

Win32 子系统在收到来自即插即用管理器即插即用启用GUID_CLASS_KEYBOARD或GUID_CLASS_MOUSE设备接口的通知后动态打开输入设备。 Win32 子系统在收到已打开接口被禁用的通知后关闭即插即用设备。 Win32 子系统还按名称 (打开旧设备,例如“\Device\KeyboardLegacyClass0”) 。 请注意,Win32 子系统成功打开旧设备后,它无法确定设备后来是否以物理方式删除。

Kbdclass 和 Mouclass 收到创建请求后,会针对即插即用和旧操作执行以下操作:

  • 即插即用操作

    如果设备处于即插即用启动状态,则类驱动程序会将IRP_MJ_CREATE请求发送到驱动程序堆栈。 否则,类驱动程序完成请求,而不将请求发送到驱动程序堆栈。 类驱动程序设置对设备具有读取访问权限的受信任文件。 如果有主设备,则类驱动程序会将创建请求发送到与从属类设备关联的所有端口。

  • 旧操作

    类驱动程序将内部设备控制请求发送到端口驱动程序以启用设备。

将服务回调连接到设备

类驱动程序必须先将其类服务连接到设备,然后才能打开设备。 类驱动程序在将类 DO 附加到设备堆栈后连接其类服务。 函数驱动程序使用类服务回调将输入数据从设备传输到设备的类数据队列。 设备的函数驱动程序的 ISR 调度完成例程调用类服务回调。 Kbdclass 提供类服务回调 KeyboardClassServiceCallback,Mouclass 提供类服务回调 MouseClassServiceCallback

供应商可以通过为设备安装上层筛选器驱动程序来修改类服务回调的操作。 示例键盘筛选器驱动程序 Kbfiltr 定义 KbFilter_ServiceCallback 回调,示例鼠标筛选器驱动程序 Moufiltr 定义 MouFilter_ServiceCallback 回调。 可以将示例筛选器服务回调配置为修改从设备的端口输入缓冲区传输到类数据队列的输入数据。 例如,筛选器服务回调可以删除、转换或插入数据。

类和筛选器服务回调按以下方式连接:

  • 类驱动程序在设备堆栈 (IOCTL_INTERNAL_KEYBOARD_CONNECT或IOCTL_INTERNAL_MOUSE_CONNECT) 发送内部设备连接请求。 类连接数据由CONNECT_DATA结构指定,该结构包括指向类设备对象的指针和指向类服务回调的指针。

  • 筛选器驱动程序收到连接请求后,会保存类连接数据的副本,并将请求的连接数据替换为筛选器连接数据。 筛选器连接数据指定指向筛选器设备对象的指针和指向筛选器驱动程序服务回调的指针。 然后,筛选器驱动程序将筛选的连接请求发送到函数驱动程序。

类和筛选器服务回调按以下方式调用:

  • 函数驱动程序使用筛选器连接数据对筛选器服务回调进行初始回调。

  • 筛选输入数据后,筛选器服务回调使用它保存的类连接数据对类服务回调。

查询和设置键盘设备

I8042prt 支持以下内部设备控制请求来查询有关键盘设备的信息,并在键盘设备上设置参数:

IOCTL_KEYBOARD_QUERY_ATTRIBUTES

IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION

IOCTL_KEYBOARD_QUERY_INDICATORS

IOCTL_KEYBOARD_QUERY_TYPEMATIC

IOCTL_KEYBOARD_SET_INDICATORS

IOCTL_KEYBOARD_SET_TYPEMATIC

有关所有键盘设备控制请求的详细信息,请参阅 人机接口设备参考

扫描键盘的代码映射器

在 Microsoft Windows 操作系统中,输入设备提供的 PS/2 兼容扫描代码将转换为虚拟密钥,这些代码以 Windows 消息的形式通过系统传播。 如果设备为某个密钥生成了不正确的扫描代码,则会发送错误的虚拟密钥消息。 可以通过编写筛选器驱动程序来解决此问题,该驱动程序分析固件生成的扫描代码,并将不正确的扫描代码修改为系统理解的扫描代码。 但是,这是一个繁琐的过程,如果内核级筛选器驱动程序中存在错误,有时可能会导致严重问题。

Windows 2000 和 Windows XP 包含新的扫描代码映射器,它提供了一种允许映射扫描代码的方法。 Windows 的扫描代码映射存储在以下注册表项中:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout

注意 还有一个 键盘布局 键 (注意复数形式) 在 Control 键下,但不应修改该键。

“键盘布局” 键中,必须添加 “扫描代码映射 ”值。 此值的类型REG_BINARY (little Endian 格式) ,具有下表中指定的数据格式。

起始偏移量 ((以字节) 为单位) 大小(以字节为单位) 数据
0 4 标头:版本信息
4 4 标头:标志
8 4 标头:映射数
12 4 单个映射
... ... ...
最后 4 个字节 4 null 终止符 (0x00000000)

第一个和第二个 DWORDS 存储标头信息,对于当前版本的扫描代码映射器,应设置为所有零。 第三个 DWORD 条目包含接下来的映射总数,包括 null 终止映射。 因此,最小计数为 1 () 未指定映射。 各个映射遵循 标头。 每个映射的长度为一个 DWORD,并分为两个 WORD 长度字段。 每个 WORD 字段存储要映射的密钥的扫描代码。

将映射存储在注册表中后,必须重新启动系统才能使映射生效。 请注意,如果在 keypress 上需要映射扫描代码,则会在将扫描代码转换为虚拟密钥之前,在用户模式下执行该步骤。 在用户模式下执行此转换可能会存在某些限制,例如在终端服务下运行时映射无法正常工作。

若要删除这些映射,请删除 Scancode 映射注册表值并重新启动。

示例 1

下面提供了一个示例。 若要将左侧 CTRL 键与 CAPS LOCK 键交换,请使用注册表编辑器 (最好 Regedt32.exe) 使用以下值修改 Scancode Map 键:

00000000 00000000 03000000 3A001D00 1D003A00 00000000

下表包含分解为 DWORD 字段和交换的字节的这些条目。

:解释

0x00000000:标头:版本。 设置为所有零。

0x00000000:标头:标志。 设置为所有零。

0x00000003:映射中的三个条目 (包括 null 条目) 。

0x001D003A:左 CTRL 键 --> CAPS LOCK (0x1D --> 0x3A) 。

0x003A001D:CAPS LOCK --> 左 Ctrl 键 (0x3A --> 0x1D) 。

0x00000000:Null 终止符。

示例 2

还可以添加键盘上未正式提供的键或删除从未使用的键。 以下示例演示 了 Scancode Map 中存储的值,该值用于删除右 Ctrl 键并更改右 Alt 键的功能以用作静音键:

00000000 00000000 03000000 00001DE0 20E038E0 00000000

下表包含分解为 DWORD 字段和交换的字节的这些条目。

:解释

0x00000000:标头:版本。 设置为所有零。

0x00000000:标头:标志。 设置为所有零。

0x00000003:映射中的三个条目 (包括 null 条目) 。

0xE01D0000:删除右 ctrl 键 (0xE01D -> 0x00) 。

0xE038E020:右 ALT 键 --> 静音键 (0xE038 --> 0xE020) 。

0x00000000:Null 终止符。

生成必要的数据后,可以通过多种方式将其插入注册表中。

  • 可以生成 .reg 文件,该文件可以使用注册表编辑器轻松合并到系统注册表中。
  • 还可以使用包含要添加的注册表信息的 [AddReg] 节创建 .inf 文件。
  • Regedt32.exe 可用于手动将信息添加到注册表。

扫描代码映射器有几个优点和缺点。

优点包括:

  • 映射器可用作更正固件错误的简易修复程序。
  • 可以通过修改注册表中的映射,将常用键添加到键盘。 例如,不经常使用的键 (右 CTRL 键) 可以映射到 null, (删除) 或交换其他键。
  • 可以轻松更改关键位置。 用户可以轻松自定义常用密钥的位置,以使其受益。

可识别到以下缺点:

  • 将映射存储在注册表中后,需要重新启动系统才能激活它。
  • 存储在注册表中的映射在系统级别工作,并应用于所有用户。 这些映射不能设置为以不同的方式工作,具体取决于当前用户。
  • 当前实现限制映射的功能,以便映射始终应用于连接到系统的所有键盘。 目前无法基于每个键盘创建映射。

查询鼠标设备

I8042prt 支持以下内部设备控制请求来查询有关鼠标设备的信息:

IOCTL_MOUSE_QUERY_ATTRIBUTES

有关所有鼠标设备控制请求的详细信息,请参阅 人机接口设备参考

与鼠标类驱动程序关联的注册表设置

下面是与鼠标类驱动程序关联的注册表项的列表。

[Key: HKLM\SYSTEM\CurrentControlSet\Services\Mouclass\Parameters]

  • MaximumPortsServiced - 不在 Windows XP 及更高版本上使用。 仅适用于 Windows NT4。
  • PointerDeviceBaseName - 指定由鼠标类设备驱动程序创建的设备对象的基名称
  • ConnectMultiplePorts – 确定每个类设备对象是有一个还是多个端口设备对象。 此项主要由设备驱动程序使用。
  • MouseDataQueueSize - 指定由鼠标驱动程序缓冲的鼠标事件数。 它还用于计算非分页内存池中鼠标驱动程序的内部缓冲区的大小。

绝对指向设备

对于 GUID_CLASS_MOUSE 类型的设备,设备的功能驱动程序:

  • 处理特定于设备的输入。

  • 创建 MouseClassServiceCallback 所需的MOUSE_INPUT_DATA结构。

  • 通过在 ISR 调度完成例程中调用 MouseClassServiceCallback ,将MOUSE_INPUT_DATA结构传输到 Mouclass 数据队列。

对于绝对指向设备,设备的函数驱动程序必须按以下方式设置MOUSE_INPUT_DATA结构的 LastXLastYFlags 成员:

  • 除了将设备输入值除以设备的最大功能之外,驱动程序还会按以下0xFFFF缩放设备输入值:

    LastX = ((device input x value) * 0xFFFF ) / (Maximum x capability of the device)
    LastY = ((device input y value) * 0xFFFF ) / (Maximum y capability of the device)
    
  • 驱动程序在 Flags 中设置MOUSE_MOVE_ABSOLUTE标志。

  • 如果窗口管理器应将输入映射到整个虚拟桌面,驱动程序会在 Flags 中设置MOUSE_VIRTUAL_DESKTOP标志。 如果未设置MOUSE_VIRTUAL_DESKTOP标志,则窗口管理器仅将输入映射到主监视器。

下面按设备类型指定如何实现绝对指向设备的这些特殊要求:

  • HID 设备:

    适用于 HID 鼠标设备的 Windows 函数驱动程序 Mouhid 会自动实现这些特殊要求。

  • PS/2 样式设备:

    需要上层筛选器驱动程序。 筛选器驱动程序提供 IsrHook 回调和类服务回调。 I8042prt 调用 IsrHook 来处理原始设备输入,并调用筛选器类服务回调来筛选输入。 筛选器类服务回调反过来调用 MouseClassServiceCallback。 IsrHook 回调和类服务回调的组合处理特定于设备的输入,创建所需的MOUSE_INPUT_DATA结构,缩放设备输入数据,并设置MOUSE_MOVE_ABSOLUTE标志。

  • 即插即用 Serenum 枚举的 COM 端口设备:

    需要即插即用函数驱动程序。 函数驱动程序创建所需的MOUSE_INPUT_DATA结构,缩放设备输入数据,并在调用 MouseClassServiceCallback 之前设置MOUSE_MOVE_ABSOLUTE标志。

  • 非即插即用 COM 端口设备:

    需要特定于设备的函数驱动程序。 函数驱动程序创建所需的MOUSE_INPUT_DATA结构,缩放设备输入数据,并在调用 MouseClassServiceCallback 之前设置MOUSE_MOVE_ABSOLUTE标志。

  • 不受支持的总线上的设备:

    需要特定于设备的函数驱动程序。 函数驱动程序创建所需的MOUSE_INPUT_DATA结构,缩放设备输入数据,并在调用 MouseClassServiceCallback 之前设置MOUSE_MOVE_ABSOLUTE标志。