鍵盤和滑鼠 HID 用戶端驅動程式
本文討論鍵盤和滑鼠 HID 用戶端驅動程式。 鍵盤和滑鼠代表在 HID 使用數據表中標準化並在 Windows 作業系統中實作的第一組 HID 用戶端。
鍵盤和滑鼠 HID 用戶端驅動程式是以 HID 對應程式驅動程式的形式實作。 HID 對應程式驅動程式是內核模式 WDM 篩選驅動程式,可為非 HID 類別驅動程式與 HID 類別驅動程式之間的 I/O 要求提供雙向介面。 對應程式驅動程式會將其中一個的 I/O 要求和數據通訊協議對應到另一個要求。
Windows 為 HID 鍵盤和 HID 滑鼠裝置提供系統提供的 HID 對應程式驅動程式。
架構和概觀
下圖說明 USB 鍵盤、滑鼠和觸控板裝置的系統提供的驅動程式堆疊。
下圖顯示下列元件:
- KBDHID.sys:適用於鍵盤的 HID 用戶端對應程式驅動程式。 將 HID 使用方式轉換成掃描代碼,以與現有的鍵盤類別驅動程式介面。
- MOUHID.sys:適用於滑鼠/觸控板的 HID 用戶端對應器驅動程式。 將 HID 使用方式轉換成滑鼠命令(X/Y、按鈕、滾輪)以與現有的鍵盤類別驅動程式介面。
- KBDCLASS.sys:鍵盤類別驅動程式以安全的方式為系統上的所有鍵盤和鍵盤提供功能。
- MOUCLASS.sys:滑鼠類別驅動程式提供系統上所有滑鼠和觸控板的功能。 驅動程式同時支持絕對和相對指向裝置。 MOUCLASS.sys不是觸摸屏的 Windows 驅動程式。
- HIDCLASS.sys:HID 類別驅動程式。 HID 類別驅動程式是KBDHID.sys和MOUHID.sys HID 用戶端與各種傳輸之間的黏附,例如 USB、藍牙等等。
系統會建置驅動程式堆疊,如下所示:
- 傳輸堆疊會為每個連結的 HID 裝置建立實體裝置物件 (PDO),並載入適當的 HID 傳輸驅動程式,進而載入 HID 類別驅動程式。
- HID 類別驅動程式會為每個鍵盤或滑鼠 TLC 建立 PDO。 複雜的 HID 裝置 (多個 TLC) 會公開為 HID 類別驅動程式所建立的多個 PDO。 例如,具有整合式滑鼠的鍵盤可能有一個標準鍵盤控件的集合,以及滑鼠的不同集合。
- 鍵盤或滑鼠 HID 用戶端對應程式驅動程式會載入適當的 FDO。
- HID 對應程式驅動程式會建立鍵盤和滑鼠的 FDO,並載入類別驅動程式。
重要注意
- 符合支援的 HID 使用方式和最上層集合的鍵盤和滑鼠不需要廠商驅動程式。
- 廠商可以選擇性地在 HID 堆疊中提供篩選驅動程式,以改變/增強這些特定 TLC 的功能。
- 廠商應建立個別的廠商特定 TLC,以在其 HID 用戶端與裝置之間交換專屬數據。 除非重要,否則請避免使用篩選驅動程式。
- 系統會開啟所有鍵盤和滑鼠集合供其獨佔使用。
- 系統會防止停用/啟用鍵盤。
- 系統支援具有平滑捲動功能的水準/垂直方向盤。
驅動程式指引
Microsoft針對撰寫驅動程序的 IHD 提供此指引:
允許驅動程式開發人員以篩選驅動程式或新的 HID 用戶端驅動程式的形式新增更多驅動程式。
篩選驅動程式:驅動程式開發人員應確保其加值驅動程式是篩選驅動程式,而且不會取代輸入堆疊中現有的 Windows HID 驅動程式(或用來取代)。
- 在這些案例中允許篩選驅動程式:
- 做為 kbdhid/mouhid 的上層篩選
- 做為 kbdclass/mouclass 的上層篩選
- 不建議使用篩選驅動程式作為HIDCLASS與HID傳輸迷你驅動程式之間的篩選
- 在這些案例中允許篩選驅動程式:
函式驅動程式:或者廠商可以建立函式驅動程式(而不是篩選驅動程式),但僅適用於廠商特定的 HID PDO(如有必要,使用使用者模式服務)。
在這些案例中允許函式驅動程式:
- 僅在特定廠商的硬體上載入
傳輸驅動程式:Windows 小組不建議建立較複雜的 HID 傳輸迷你驅動程式來撰寫和維護。 如果合作夥伴正在建立新的 HID 傳輸迷你驅動程式,特別是在 SoC 系統上,建議您進行詳細的架構檢閱,以瞭解推理,並確保驅動程式已正確開發。
驅動程式開發人員應該使用驅動程序架構 (KMDF 或 UMDF),而不是依賴 WDM 作為篩選驅動程式。
驅動程式開發人員應減少其服務與驅動程式堆疊之間的核心用戶轉換數目。
驅動程式開發人員應確保能夠透過鍵盤和觸控板功能喚醒系統(可由使用者(設備管理器)或計算機製造商調整)。 除了 SoC 系統上,這些裝置必須能夠在系統處於運作的 S0 狀態時,從較低的電源狀態喚醒自己。
驅動程式開發人員應確保其硬體有效率地受到管理。
- 裝置可在裝置閑置時進入其最低電源狀態。
- 當系統處於低電源狀態(例如待命(S3)或連線待命時,裝置處於最低電源狀態。
鍵盤配置
鍵盤配置會完整描述Microsoft Windows 2000 和更新版本的鍵盤輸入特性。 例如,鍵盤配置會指定語言、鍵盤類型和版本、修飾詞、掃描代碼等等。
如需鍵盤配置的相關信息,請參閱下列資源:
Windows 驅動程式開發工具包 (DDK) 中的鍵盤頭檔 kdb.h,其中記載鍵盤版面配置的一般資訊。
範例鍵盤 配置。
若要將特定鍵盤的配置可視化,請參閱 Windows 鍵盤配置。
如需鍵盤配置的詳細資訊,請流覽 控制台\Clock、Language 和 Region\Language。
滑鼠上支持的按鈕和方向盤
下表識別 Windows 作業系統不同用戶端版本所支援的功能。
功能 | Windows XP | Windows Vista | Windows 7 | Windows 8 和更新版本 |
---|---|---|---|---|
按鈕 1-5 | 支援 (P/2 和 HID) | 支援 (PS/2 和 HID) | 支援 (PS/2 和 HID) | 支援 (PS/2 和 HID) |
垂直滾動輪 | 支援 (PS/2 和 HID) | 支援 (PS/2 和 HID) | 支援 (PS/2 和 HID) | 支援 (PS/2 和 HID) |
水平滾動輪 | 不支援 | 支援(僅限 HID) | 支援(僅限 HID) | 支援(僅限 HID) |
平滑滾動輪支援 (水平和垂直) | 不支援 | 部分支援 | 支援 (僅限 HID) | 支援 (僅限 HID) |
在 PS/2 老鼠上啟動按鈕 4-5 和滾輪
Windows 用來啟動新的四個和五個按鈕和滾輪模式的方法,是用來在 IntelliMouse 兼容滑鼠中啟動第三個按鈕和滾輪的方法延伸:
滑鼠會設定為三按鈕滾輪模式,方法是將報表速率設定為每秒 200 個報表,然後設定為每秒 100 個報表,然後設定為每秒 80 份報告。 然後,從滑鼠讀取標識碼。 當此序列完成時,滑鼠應該會報告 3 的識別碼。
然後滑鼠會設定為五按鈕滾輪模式,方法是將報表速率設定為每秒 200 個報表,再設定為每秒 200 份報告,再設定為每秒 80 份報告。 然後,從滑鼠讀取標識碼。 序列完成後,五鍵滾輪滑鼠應該報告標識碼為 4(而 IntelliMouse 相容的三按鈕滾輪滑鼠仍會報告標識元為 3)。
這個方法僅適用於 PS/2 小鼠,不適用於 HID 小鼠。 HID 滑鼠必須在報表描述元中報告正確的使用方式。
標準 PS/2 相容的滑鼠資料封包格式 (兩個按鈕)
Byte | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | 註解 |
---|---|---|---|---|---|---|---|---|---|
1 | Yover | Xover | Ysign | Xsign | 標籤 | 月 | R | 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 相容的滑鼠資料封包格式 (三個按鈕 + 垂直方向盤)
Byte | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | 註解 |
---|---|---|---|---|---|---|---|---|---|
1 | 0 | 0 | Ysign | Xsign | 1 | 月 | R | 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 相容的滑鼠資料封包格式 (五個按鈕 + 垂直方向盤)
Byte | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | 註解 |
---|---|---|---|---|---|---|---|---|---|
1 | 0 | 0 | Ysign | Xsign | 1 | 月 | R | 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 相容三按鈕滾輪模式中使用的 8 位。 由於輪子通常無法在任何指定的插斷期間產生超出範圍 +7/-8 的值,因此可能會降低這個值。 當滑鼠處於五按鈕滾輪模式時,Windows 滑鼠驅動程式會簽署擴充四個 Z/滾輪數據位,而當滑鼠以三按鈕方向盤模式運作時,則完整的 Z/滾輪數據位元組。
上的按鈕 4 和 5 會對應至WM_APPCOMMAND訊息,並對應至App_Back和App_Forward。
不需要廠商驅動程式的裝置
下列裝置不需要廠商驅動程式:
- 符合 HID Standard 的裝置。
- 由系統提供的非 HIDClass 驅動程式操作的鍵盤、滑鼠或遊戲埠裝置。
Kbfiltr 範例
Kbfiltr 與 Kbdclass 搭配使用,這是鍵盤裝置的系統類別驅動程式,以及 PS/2 樣式鍵盤的函式驅動程式 I8042prt。 Kbfiltr 示範如何篩選 I/O 要求,以及如何新增回呼例程,以修改 Kbdclass 和 I8042prt 的作業。
如需 Kbfiltr 作業的詳細資訊,請參閱:
Kbfiltr IO 控制代碼
Kbfiltr 會使用下列 IOCTLs。
IOCTL_INTERNAL_I8042_HOOK_KEYBOARD
IOCTL_INTERNAL_I8042_HOOK_KEYBOARD要求:
- 將初始化回呼例程新增至 I8042prt 鍵盤初始化例程。
- 將ISR回呼例程新增至I8042prt鍵盤ISR。
初始化和ISR回呼是選擇性的,由 PS/2 樣式鍵盤裝置的上層篩選驅動程式提供。
在 I8042prt 收到 IOCTL_INTERNAL_KEYBOARD_CONNECT 要求之後,它會將同步 IOCTL_INTERNAL_I8042_HOOK_KEYBOARD 要求傳送至鍵盤裝置堆疊頂端。
在 Kbfiltr 收到勾點鍵盤要求之後,Kbfiltr 會以下列方式篩選要求:
- 儲存傳遞至 Kbfiltr 的上層資訊,其中包括上層裝置對象的內容、初始化回呼的指標,以及 ISR 回呼的指標。
- 以自己的資訊取代上層資訊。
- 將 I8042prt 的內容和指標儲存至 Kbfiltr ISR 回呼可以使用的回呼。
IOCTL_INTERNAL_KEYBOARD_CONNECT
IOCTL_INTERNAL_KEYBOARD_CONNECT要求會將 Kbdclass 服務連線到鍵盤裝置。 Kbdclass 會在開啟鍵盤裝置之前,先將此要求傳送到鍵盤裝置堆疊。
在 Kbfiltr 收到鍵盤連線要求之後,Kbfiltr 會以下列方式篩選連線要求:
- 儲存 Kbdclass CONNECT_DATA (Kbdclass) 結構的複本,該結構會由 Kbdclass 傳遞至篩選驅動程式。
- 以自己的連接資訊取代類別驅動程式連接資訊。
- 將IOCTL_INTERNAL_KEYBOARD_CONNECT要求向下傳送裝置堆疊。
如果要求未成功,Kbfiltr 會以適當的錯誤狀態完成要求。
Kbfiltr 提供篩選服務回呼例程的範本,可補充 KeyboardClassServiceCallback、Kbdclass 類別服務回呼例程的作業。 篩選服務回呼可以篩選從裝置輸入緩衝區傳輸到類別數據佇列的輸入數據。
IOCTL_INTERNAL_KEYBOARD_DISCONNECT
IOCTL_INTERNAL_KEYBOARD_DISCONNECT要求已完成,狀態為 STATUS_NOT_IMPLEMENTED。 隨插即用 管理員可以新增或移除 隨插即用 鍵盤。
對於所有其他裝置控制要求,Kbfiltr 會略過目前的 IRP 堆疊,並將要求傳送至裝置堆疊,而不需要進一步處理。
Kbfiltr 所實作的回呼例程
Kbfiltr 會實作下列回呼例程。
KbFilter_InitializationRoutine
請參閱 PI8042_KEYBOARD_INITIALIZATION_ROUTINE
如果鍵盤的 I8042prt 預設初始化已足夠,則不需要KbFilter_InitializationRoutine。
I8042prt 會在初始化鍵盤時呼叫 KbFilter_InitializationRoutine 。 預設鍵盤初始化包含下列作業:
- 重設鍵盤
- 設定類型速率和延遲
- 設定發光二氧化碳 (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
請參閱 PI8042_KEYBOARD_ISR。 如果 I8042prt 的預設作業已足夠,則不需要此回呼。
I8042prt 鍵盤 ISR 會在驗證中斷並讀取掃描碼之後呼叫KbFilter_IsrHook 。
KbFilter_IsrHook會在 I8042prt 鍵盤的 IRQL 核心模式中執行。
/*
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 搭配使用,這是與 Windows 2000 和更新版本搭配使用的滑鼠裝置的系統類別驅動程式,以及 I8042prt,這是搭配 Windows 2000 和更新版本使用的 PS/2 樣式滑鼠函式驅動程式。 Moufiltr 示範如何篩選 I/O 要求,並新增可修改 Mouclass 和 I8042prt 作業的回呼例程。
如需 Moufiltr 作業的詳細資訊,請參閱下列資源:
Moufiltr IO 控制代碼
Mufiltr 會使用下列 IOCTLs。
IOCTL_INTERNAL_I8042_HOOK_MOUSE
IOCTL_INTERNAL_I8042_HOOK_MOUSE要求會將ISR回呼例程新增至I8042prt 滑鼠 ISR。 ISR 回呼是選擇性的,由上層滑鼠篩選驅動程式提供。
I8042prt 會在收到 IOCTL_INTERNAL_MOUSE_CONNECT 要求之後傳送此要求。 I8042prt 會將同步 IOCTL_INTERNAL_I8042_HOOK_MOUSE 要求傳送至滑鼠裝置堆疊頂端。
在 Moufiltr 收到攔截滑鼠要求之後,它會以下列方式篩選要求:
- 儲存傳遞至 Moufiltr 的上層資訊,其中包含上層裝置對象的內容,以及 ISR 回呼的指標。
- 以自己的資訊取代上層資訊。
- 將 I8042prt 的內容和指標儲存至 Moufiltr ISR 回呼可以使用的回呼。
IOCTL_INTERNAL_MOUSE_CONNECT
IOCTL_INTERNAL_MOUSE_CONNECT要求會將 Mouclass 服務連線到滑鼠裝置。
IOCTL_INTERNAL_MOUSE_DISCONNECT
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
);
如果 I8042prt 的預設作業已足夠,則不需要MouFilter_IsrHook回呼。
I8042prt 滑鼠 ISR 會在驗證中斷之後呼叫 MouFilter_IsrHook 。
若要重設滑鼠,I8042prt 會經歷一連串的作業子狀態。 MOUSE_RESET_SUBSTATE列舉值會識別每個子專案。 如需 I8042prt 如何重設滑鼠和對應滑鼠重設子狀態的詳細資訊,請參閱 ntdd8042.h 中MOUSE_RESET_SUBSTATE的檔。
MouFilter_IsrHook在 I8042prt 滑鼠 ISR 的 IRQL 核心模式中執行。
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
);
I8042prt 的 ISR DPC 會呼叫 MouFilter_ServiceCallback,然後呼叫 MouseClassServiceCallback。 篩選服務回呼可以設定為修改從裝置輸入緩衝區傳輸到類別數據佇列的輸入數據。 例如,回呼可以刪除、轉換或插入數據。