キーボードおよびマウス クラス ドライバーの構成

Note

このトピックは、キーボードおよびマウス クラス ドライバーを構成している開発者向けです。 マウスまたはキーボードを修正する場合は、次のトピックを参照してください。

HID 以外のキーボードとマウスは、複数のレガシ バス経由で接続できますが、同じクラス ドライバーを引き続き使用します。 このセクションでは、クラス ドライバー自体の詳細について説明します。 その後のセクションでは、コントローラーの詳細について説明します。

このトピックでは、Microsoft Windows 2000 以降でのキーボードおよびマウス デバイスの一般的な物理構成について説明します。

次の図は、1 つのキーボードと 1 つのマウスを使用する 2 種類の一般的な構成を示したものです。

Diagram illustrating two configurations that employ a single keyboard and a single mouse.

左側の図は、独立したコントローラーを介してシステム バスに接続されたキーボードとマウスを示しています。 一般的な構成は、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 を介して機能デバイス オブジェクト (FDO) にアタッチされる上位レベルのクラス フィルター デバイス オブジェクト (フィルター DO) を作成します。 上位レベルのデバイス フィルター ドライバーは、上位レベルのデバイス フィルター DO を作成します。 I8042prt は、機能 DO を作成し、ルート バス ドライバーによって作成された物理デバイス オブジェクト (PDO) にアタッチします。

Diagram illustrating the configuration of device objects for a plug and play ps/2-style keyboard and mouse device.

PS/2 キーボード

キーボード ドライバー スタックは、次の要素で構成されます。

  • Kbdclass: 上位レベルのキーボード クラス フィルター ドライバー
  • 1 つ以上のオプションの上位レベルのキーボード フィルター ドライバー
  • I8042prt: 機能ドライバー

PS/2 マウス

マウス ドライバー スタックは、次の要素で構成されます。

  • Mouclass: 上位レベルのマウス クラス フィルター ドライバー
  • 1 つ以上のオプションの上位レベルのマウス フィルター ドライバー
  • I8042prt: 機能ドライバー

KbdclassMouclass は、2 つの異なるモードで複数のデバイスをサポートできます。 1 対 1 モードでは、各デバイスは独立したデバイス スタックを持ちます。 クラス ドライバーは、独立したクラス DO を作成して各デバイス スタックにアタッチします。 各デバイス スタックは、独自の制御状態と入力バッファーを持ちます。 Microsoft Win32 サブシステムは、一意のファイル オブジェクトを介して各デバイスからの入力にアクセスします。

グランドマスター モードでは、クラス ドライバーは次のようにすべてのデバイスを操作します。

  • クラス ドライバーは、すべてのデバイスを表すグランドマスター クラス DO と、各デバイスの下位クラス DO の両方を作成します。

    クラス ドライバーは、下位クラス DO を各デバイス スタックにアタッチします。 下位クラス DO の下のデバイス スタックは、1 対 1 モードで作成されたものと同じです。

  • グランドマスター クラス DO は、すべての下位 DO の操作を制御します。

  • Win32 サブシステムは、グランドマスター クラス デバイスを表すファイル オブジェクトを介して、すべてのデバイス入力にアクセスします。

  • すべてのデバイス入力は、グランドマスターのデータ キューにバッファーされます。

  • グランドマスターは、単一のグローバルなデバイスの状態を維持します。

レジストリ エントリ値 ConnectMultiplePorts が 0x00 に設定されている場合、Kbdclass と Mouclass は 1 対 1 モードで動作します (キー HKLM\Services\CurrentControlSet\<class service>\Parameters の下で、クラス サービスは Kbdclass または Mouclass です)。 それ以外の場合、Kbdclass と Mouclass はグランドマスター モードで動作します。

クラス ドライバーを使用して開閉する

Microsoft Win32 サブシステムは、すべてのキーボード デバイスとマウス デバイスを排他的に使用するために開きます。 各デバイス クラスについて、Win32 サブシステムは、すべてのデバイスからの入力を、その入力が 1 つの入力デバイスから送信されたもののように扱います。 アプリケーションは、ある特定のデバイスからの入力だけを受信するように要求することはできません。

Win32 サブシステムは、GUID_CLASS_KEYBOARD または GUID_CLASS_MOUSE デバイス インターフェイスが有効になっているという通知をプラグ アンド プレイ マネージャーから受け取ると、プラグ アンド プレイ入力デバイスを動的に開きます。 Win32 サブシステムは、開いているインターフェイスが無効になっているという通知を受け取ると、プラグ アンド プレイデバイスを閉じます。 Win32 サブシステムは、レガシ デバイスも名前で開きます (例: "\Device\KeyboardLegacyClass0")。 Win32 サブシステムがレガシ デバイスを正常に開いた後は、そのデバイスが後で物理的に削除されたかどうかを判断できないことに注意してください。

Kbdclass と Mouclass は作成要求を受け取ると、プラグ アンド プレイ操作およびレガシ操作に対して次の操作を行います。

  • プラグ アンド プレイ操作

    デバイスがプラグ アンド プレイ開始状態の場合、クラス ドライバーはドライバー スタックに IRP_MJ_CREATE 要求を送信します。 それ以外の場合は、ドライバー スタックに要求を送信せずに完了します。 クラス ドライバーは、デバイスへの読み取りアクセス権を持つ信頼されたファイルを設定します。 グランドマスター デバイスがある場合、クラス ドライバーは下位クラス デバイスに関連付けられているすべてのポートに作成要求を送信します。

  • レガシ操作

    クラス ドライバーは、デバイスを有効にするために、ポート ドライバーに内部デバイス制御要求を送信します。

サービス コールバックをデバイスに接続する

クラス ドライバーは、クラス サービスをデバイスに接続しなければデバイスを開くことができません。 クラス ドライバーは、クラス DO をデバイス スタックにアタッチした後で、クラス サービスを接続します。 ファンクション ドライバーは、クラス サービス コールバックを使用して、デバイスからデバイスのクラス データ キューに入力データを転送します。 デバイスのファンクション ドライバーの ISR ディスパッチ完了ルーチンは、クラス サービス コールバックを呼び出します。 Kbdclass はクラス サービス コールバック KeyboardClassServiceCallback を提供し、Mouclass はクラス サービス コールバック MouseClassServiceCallback を提供します。

ベンダーは、デバイスの上位レベルのフィルター ドライバーをインストールすることで、クラス サービス コールバックの操作を変更できます。 サンプル キーボード フィルター ドライバー KbfiltrKbFilter_ServiceCallback コールバックを定義し、サンプル マウス フィルター ドライバー MoufiltrMouFilter_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 キーの下位には Keyboard Layouts キー (複数形に注意してください) もありますが、このキーは変更しないでください。

Keyboard Layout キーでは、Scancode Map の値を追加する必要があります。 この値は REG_BINARY 型 (リトル エンディアン形式) であり、次の表で指定されているデータ形式を持ちます。

開始オフセット (バイト単位) サイズ (バイト単位) データ​​
0 4 ヘッダー: バージョン情報
4 4 ヘッダー: フラグ
8 4 ヘッダー: マッピングの数
12 4 個々のマッピング
... ... ...
最後の 4 バイト 4 Null 終端記号 (0x00000000)

1 番目と 2 番目の DWORD はヘッダー情報を格納し、現在のバージョンのスキャン コード マッパーでは、すべてゼロに設定する必要があります。 3 番目の DWORD エントリは、null 終端マッピングを含めた後続のマッピングの合計数のカウントを保持します。 したがって、最小カウントは 1 になります (マッピングは指定されません)。 個々のマッピングはヘッダーの後に続きます。 各マッピングは長さ 1 の DWORD フィールドであり、2 WORD 長のフィールドに分割されます。 各 WORD フィールドには、マップするキーのスキャン コードが格納されます。

マップがレジストリに格納されたら、マッピングを有効にするためにシステムを再起動する必要があります。 キー押下時にスキャン コードのマッピングが必要な場合は、スキャン コードが仮想キーに変換される直前に、このステップがユーザー モードで実行されることに注意してください。 この変換をユーザー モードで実行すると、ターミナル サービスで実行しているときにマッピングが正しく機能しないなど、特定の制限が発生する可能性があります。

これらのマッピングを削除するには、Scancode Map レジストリ値を削除して再起動します。

例 1

次に例を示します。 左側の Ctrl キーと CAPS LOCK キーを入れ替えるには、レジストリ エディター (できれば Regedt32.exe) を使用して、Scancode Map キーを次の値に変更します。

00000000 00000000 03000000 3A001D00 1D003A00 00000000

次の表は、DWORD フィールドとスワップされたバイトに分割されたこれらのエントリを示したものです。

: 解釈

0x00000000: ヘッダー: バージョン。 すべてゼロに設定します。

0x00000000: ヘッダー: フラグ。 すべてゼロに設定します。

0x00000003: マップ内の 3 つのエントリ (null エントリを含む)。

0x001D003A: 左 Ctrl キー --> CAPSLOCK (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: マップ内の 3 つのエントリ (null エントリを含む)。

0xE01D0000: 右の Ctrl キーを削除します (0xE01D --> 0x00)。

0xE038E020: 右 Alt キー --> ミュート キー (0xE038 --> 0xE020)。

0x00000000: Null 終端記号。

必要なデータが生成されたら、複数の方法でレジストリに挿入できます。

  • レジストリ エディターを使用してシステム レジストリに簡単に組み込むことができる .reg ファイルを生成できます。
  • 追加するレジストリ情報が記述された [AddReg] セクションを持つ .inf ファイルを作成することもできます。
  • Regedt32.exe を使用して、レジストリに手動で情報を追加できます。

スキャン コード マッパーには、いくつかの長所と短所があります。

長所は次のとおりです。

  • マッパーは、ファームウェアのエラーを訂正するための簡単な修正手段として使用できます。
  • レジストリのマップを変更することで、頻繁に使用されるキーをキーボードに追加できます。 頻繁に使用されないキー (右 Ctrl キーなど) は、null にマップ (削除) したり、他のキーに入れ替えたりできます。
  • キーの場所は簡単に変更できます。 ユーザーは、頻繁に使用されるキーの場所を簡単にカスタマイズできるという利点を得ることができます。

短所は次のとおりです。

  • マップがレジストリに格納されたら、それをアクティブ化するためにシステムの再起動が必要になります。
  • レジストリに格納されているマッピングはシステム レベルで機能するため、すべてのユーザーに適用されます。 これらのマッピングは、ユーザーごとに異なる動作をするように設定することはできません。
  • 現在の実装では、マッピングが常にシステムに接続されているすべてのキーボードに適用されるように、マップの機能が制限されています。 現時点では、キーボードごとにマップを作成することはできません。

マウス デバイスに対してクエリを実行する

I8042prt では、マウス デバイスに関する情報を照会するために、次の内部デバイス制御要求がサポートされています。

IOCTL_MOUSE_QUERY_ATTRIBUTES

すべてのマウス デバイス制御要求の詳細については、「ヒューマン インターフェイス デバイス リファレンス」を参照してください。

マウス クラス ドライバーに関連付けられているレジストリ設定

マウス クラス ドライバーに関連付けられているレジストリ キーの一覧を次に示します。

[キー: HKLM\SYSTEM\CurrentControlSet\Services\Mouclass\Parameters]

  • MaximumPortsServiced – Windows XP 以降では使用されません。 Windows NT4 のみ。
  • PointerDeviceBaseName – マウス クラス デバイス ドライバーによって作成されたデバイス オブジェクトの基本名を指定します。
  • ConnectMultiplePorts – クラス デバイス オブジェクトごとに 1 つ以上のポート デバイス オブジェクトがあるかどうかを判断します。 このエントリは、主にデバイス ドライバーによって使用されます。
  • 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 フラグを設定します。

  • 入力を Window Manager によって仮想デスクトップ全体にマップする必要がある場合、ドライバーは Flags に MOUSE_VIRTUAL_DESKTOP フラグを設定します。 MOUSE_VIRTUAL_DESKTOP フラグが設定されていない場合、Window Manager は入力をプライマリ モニターのみにマップします。

次にデバイスの種類別に、絶対ポインティング デバイスに対するこれらの特別な要件を実装する方法を指定します。

  • HID デバイス:

    Mouhid (HID マウス デバイス用の Windows ファンクション ドライバー) は、これらの特別な要件を自動的に実装します。

  • 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 フラグを設定します。