MacBookのBootcamp Windowsで内蔵キーボード「だけ」を対象としてALT(option)とWindows(command)キーを入れ替えるドライバを書いてインストールする手順

#◆要するに何？#

MacBookのBootcamp Windows10x64環境で内蔵キーボード「だけ」を対象とした
「左Alt(option)、左Win(command)、右Win(command)キー」を
「左Win(option)、左Alt(command)、右Altキー(command)」にするキーボードフィルタドライバを記述して
インストールする手順。

#◆読むと幸せになれそうな人#

- iOSアプリビルドの為に~~~仕方なく~~~MacBookを使っているが、普段はBootcampでWindowsを使っている
- 普段は外付けWindowsキーボードとモニタを使っている
- 出先でMacBookのキーボードを使った際、頻繁にALTとWindowsキーを押し間違えキーボードを叩き割りたくなる

※尚、ctrlキーはsysinternalsのctrl2capでmac~~~やx68k~~~側に寄せてるのでこの記事では入れ替えていません。

#◆注意#

　カーネルモードデバイスドライバなのでミスると文字が入力出来なくなる、
　BlueScreenOfDeathに陥るなど、割と面倒な事態になるのでその点には留意しておいてください。

　イメージバックアップ、復元ポイントの作成、セーフモードで起動出来るように予めbcdeditしておくなど、
　事前準備は忘れずに。

　とは言え、大掛りなミスをしなければ影響範囲は内蔵キーボードのみなので外付けキーボードがあればどうにでもなります。


#◆環境#
- MacBookPro2017 15inch
- Windows10 Pro x64 1809 / 1903

#◆使った物#
- [WDK for Windows Ver 10.0.17763.1（for Win10 1809）](http://download.microsoft.com/download/1/4/0/140EBDB7-F631-4191-9DC0-31C8ECB8A11F/wdk/wdksetup.exe)[[出典]](https://github.com/MicrosoftDocs/windows-driver-docs/issues/878)
- 上記に対応したVS2017

　※WDKでググるとWin10 1903に対応した最新のWDKとそれに対応したVS2019のインストール手順(日本語)が
　　見つかるので多分それでもOKです（未検証）。
　　筆者はVS2017がインストール済みだった為、敢えてそれに対応した古いWDKを探してインストールしました。

#◆改変元のPS/2キーボードフィルタドライバのサンプルの入手#

　wdk sampleでググると、GitHubにMicrosoftのWDKの[サンプル一式](https://github.com/Microsoft/Windows-driver-samples)があるので、
　その中のinput\kbfilterフォルダをコピーして使います。

#◆ドライバCソースの変更#

　kbfilter.cの766 行目付近に KbFilter_ServiceCallback という名前の関数が定義されているので、
　ここにキーの入れ替え処理を書きます。
　[[参考記事]](https://blogs.msdn.microsoft.com/jpwdkblog/2014/07/31/keyboard-filter-driver/)
　※MakeCode(スキャンコード)はKeyMillと言うフリーソフトウェアで実際にキーを押して調べました。

　※kbfilterサンプルにPS/2キーボード固有のコードがある気がしますが触らぬ神に祟りなしという事で良しとします。

```c:kbfilter.c

VOID
KbFilter_ServiceCallback(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PKEYBOARD_INPUT_DATA InputDataStart,
    IN PKEYBOARD_INPUT_DATA InputDataEnd,
    IN OUT PULONG InputDataConsumed
    )
{
	PDEVICE_EXTENSION   devExt;
	WDFDEVICE   hDevice;

	hDevice = WdfWdmDeviceGetWdfDeviceHandle(DeviceObject);
	devExt = FilterGetData(hDevice);

	// ここにキーの入れ替えや無視処理を記述する
	PKEYBOARD_INPUT_DATA InputData = InputDataStart;
	while (InputData != InputDataEnd)
	{
		// BOOLEAN isRight = (InputData->Flags & KEY_E0);	// 右CTRL、右ALTならtrue
		// キーボードの入力信号である Make コードから入力キーを判断する
		switch (InputData->MakeCode)
		{
		  case 0x38:   // Macの左Optionキー
			InputData->MakeCode = 0x5b;	// 左Windowsキーのスキャンコードへ変更
			InputData->Flags |= KEY_E0; // Windowsキーは拡張フラグオン
			break;
		  case 0x5b:   // Macの左Command(Win)キー
			InputData->MakeCode = 0x38;	// Altキーへ変更
			InputData->Flags &= (0xFFFF^KEY_E0); // 左AltとCtrlは拡張フラグをオフ
			break;
		  case 0x5c:   // Macの右Command(Win)キー
			InputData->MakeCode = 0x38;	// Altキーへ変更
			InputData->Flags |= KEY_E0; // 右AltとCtrlは拡張フラグをオン
			break;
		  default:
			break;
		}
		++InputData;
	}

	(*(PSERVICE_CALLBACK_ROUTINE)(ULONG_PTR) devExt->UpperConnectData.ClassService)(
		devExt->UpperConnectData.ClassDeviceObject,
		InputDataStart,
		InputDataEnd,
		InputDataConsumed);
}
```

#◆MacBookのキーボードのVIDとPIDの調査#

　下記のフォルダにドライバ一式が格納されています。
　C:\Windows\System32\DriverStore\FileRepository\

　上記フォルダからkeyboard及びappleの含まれるフォルダを探すと以下の様なフォルダが該当します。
　applespikeyboard.inf_amd64_16進数

　そのフォルダ中の*.infファイル中のDeviceDescの「VID_05ac&PID_XXXX」が
　BootCampが想定している全てのMacBookのキーボードのベンターID(VID)とプロダクトID(PID)です。
　※VID 05acでググるとApple inc.であることが分かります。

　これはドライバのインストールの際に必要となるinfファイルの元となるinxの変更の際に必要です。

#◆前述のkbfiltr.inxをMacBookのキーボード向けに変更#

・MacBookのキーボードのみを対象にする

　下記でコメントアウトしてある「%kbfiltr.DeviceDesc% = kbfiltr, *PNP0BAAD」に
　一致する行（元のinxではコメントアウトされていません)を探し、コメントアウト後、
　それ以下に続く行を追記します。

　※デバイスマネージャで自分のMacBookのキーボードのVIDとPIDが調査済みであれば
　DeviceDescにはそれだけを書けばOKです。

　Needsの行は、そのままだとPS/2キーボード用のドライバが組み込まれてしまうので
　HID(USB) 106キーボード用に変更します。

　※inx(inf)のPS/2→HID(USB)化はググっても殆ど情報が出てこないので、
　ドライバの格納されている前述のフォルダの中から、
　特殊なボタン類のあるキーボードのinfファイルを参考にしました。

```perl:kbfiltr.inx

;%kbfiltr.DeviceDesc% = kbfiltr, *PNP0BAAD
%kbfiltr.DeviceDesc% = kbfiltr, HID\VID_05ac&PID_0272&MI_01
%kbfiltr.DeviceDesc% = kbfiltr, HID\VID_05ac&PID_0273&MI_01
%kbfiltr.DeviceDesc% = kbfiltr, HID\VID_05ac&PID_0275&MI_01
%kbfiltr.DeviceDesc% = kbfiltr, HID\VID_05ac&PID_0276&MI_01
%kbfiltr.DeviceDesc% = kbfiltr, HID\VID_05ac&PID_0277&MI_01
%kbfiltr.DeviceDesc% = kbfiltr, HID\VID_05ac&PID_0278&MI_01
%kbfiltr.DeviceDesc% = kbfiltr, HID\VID_05ac&PID_0279&MI_01
%kbfiltr.DeviceDesc% = kbfiltr, HID\VID_05ac&PID_0290&MI_01
%kbfiltr.DeviceDesc% = kbfiltr, HID\VID_05ac&PID_0291&MI_01

;Needs=STANDARD_Inst
Needs   = HID_106_Keyboard_Inst.NT

;Needs=STANDARD_Inst.Services
Nees=HID_106_Keyboard_Inst.NT.Services

;Needs=STANDARD_Inst.HW
Needs=HID_106_Keyboard_Inst.NT.HW
```

#◆供給元、製造元、ドライバ名、サービス名などを変更#

　※SvcDescは他と被りそうにないユニークな名前にする必要があります。
　他はデバイスマネージャマネージャに表示されるだけなので適当でOKです。

```perl:kbfiltr.inx
ProviderName = "Ippei Ito"
MfgName      = "Apple Inc."

kbfiltr.DeviceDesc = "HID キーボード デバイス(OPT/CMD入れ替え版)"
kbfiltr.SvcDesc = "Cmd and Opt Swapped Keyboard Filter Driver"
DiskId1 = "Cmd and Opt Swapped Keyboard Filter Install Disk"
```

#◆VSでのビルド#

1. kbfiltr.slnをVSで開く
2. ソリューション構成をRelease、ソリューションプラットフォームをx64に設定
3. CTRL+SHIFT+Bを押してビルド

　※一時話題になったSpectre脆弱性対策用のライブラリをVSへインストールしていない場合は、
　その旨のエラーが出るので、
　ソリューションエクスプローラの「kbftest」プロジェクトのプロパティを開き、
　構成プロパティ＞C/C++＞コード生成のSpectre軽減策を無効にする必要があります。
　（kbftest.exeは不要ですし）

#◆ドライバへの署名環境を整える(一度行えばOKです)#

　平たく言うと「個人の証明書」ストアへ「ドライバ署名用の証明書」を用意し、
　「ローカルコンピュータ」の「信頼されたルート証明機関」と「信頼された発行元」ストアにも
　それを追加して「ドライバ署名用の証明書」を信頼させる作業を行う。

　※但しMicrosoftによりクロス署名されていないので
　後述の「テスト証明書モード」を有効なままにしておかないと、
　このドライバが読み込まれず道連れで内蔵キーボードが使えなくなるので注意（外付けは使用可）
　[[参考記事]](https://codeday.me/jp/qa/20190123/186609.html)

**・ドライバテスト用証明書がWDKによってPCへインストールされているか確認**
　※筆者が使用したWDKではインストール時に信頼されていない状態のテスト用証明書が
　作成されて組み込まれていたので、それを信頼状態にして署名しました。

　Win+Rでcertmgr.mscを実行

- 証明書 - 現在のユーザー
    - 個人
        - 証明書
            - ここにWDKTestCert～が存在すればそれを使って署名する(無い場合は後述)

**・WDKTestCert～があった場合**

Win+Rでcertlm.mscを実行

- 証明書 - ローカルコンピュータ
    - 信頼されたルート証明機関
        - 証明書
            - ここにWDKTestCert～が存在するか確認

　「信頼されたルート証明機関」にWDKTestCert～が無い場合はここへ追加する必要があるので、
　個人の証明書のWDKTestCert～を右クリックして「すべてのタスク」「エクスポート」を選択。

　エクスポートダイアログが開くので次の様に操作。
　「次へ」「いいえ、秘密鍵をエクスポートしません」「DER encoded ～」「次へ」
　「wdk_publickey.cerなど適当なファイル名を入力」「次へ」「完了」

・Win+QでNativeと入力して以下を管理権限で起動
　VS 201X 用 x64 Native Tools コマンド プロンプト

・エクスポートした証明書を「ローカルコンピュータ」の「信頼されたルート証明機関」と「信頼された発行元」へ追加
　certmgr.exe -add wdk_publickey.cer -s -r localMachine root
　certmgr.exe -add wdk_publickey.cer -s -r localMachine trustedpublisher

**・WDKTestCert～がなかった場合**

・自己証明書を作成
　makecert -r -pe -ss my -n "CN=%username%" %username%.cer

・自己証明書を「ローカルコンピュータ」の「信頼されたルート証明機関」と「信頼された発行元」へ追加
　certmgr.exe -add %username%.cer -s -r localMachine root
　certmgr.exe -add %username%.cer -s -r localMachine trustedpublisher

#◆ドライバへの署名(ビルド毎に行う必要があります)#

・Win+QでNativeと入力して以下を管理権限で起動
　VS 201X 用 x64 Native Tools コマンド プロンプト

・署名したいドライバのあるフォルダへ移動
　(例)
　cd /d X:\input\kbfiltr\sys\x64\Release\kbfiltr

・（WDKTestCert～があった場合）テスト用証明書を使いドライバへ署名する
　signtool sign -v -s my -n "WDKTestCert" kbfiltr.sys

・（WDKTestCert～がなかった場合）自己証明書を使いドライバへ署名する
　signtool sign -v -s my -n %username% kbfiltr.sys

　※署名用の証明書名の指定は一部一致で良いようですが、一部一致で証明書が決定できない場合はエラーが出ます。
　その場合は、下記の様にsignの後に-aオプションを付けると適当に証明書を選択して署名してくれます。
　signtool sign -a -v -s my -n %username% kbfiltr.sys

　※毎回手動でやるのは面倒なので、バッチファイルを書いてVSのプロジェクトのプロパティのビルド後の処理に追加すると楽です。

#◆「テスト証明書モードを有効」に設定#

　Microsoftによってクロス署名されていない証明書で署名したドライバを利用出来るようにするため、
　ドライバをインストールしようとするPCの「テスト証明書モードを有効」にする必要があります。

・コマンドプロンプトを管理者権限で起動して以下を入力後、再起動する（右下にテストモードと表示されるようになります）
　bcdedit /set TESTSIGNING ON

　上記だけでインストール可能になるはずですがダメな場合、以下を設定すると良いかもしれません。

・UEFIセキュアブート無効化(MacBookの場合関係ありません)
・shutdown /r /o /t 0で再起動して「ドライバー署名の強制」を無効化
・SmartScreenの無効化

#◆ドライバのインストール手順#
　デバイスマネージャの

- キーボード
    - HIDキーボード
    - HIDキーボード(複数ある場合あり)

　の中の「詳細」タブの「デバイスインスタンスパス」が
　「MacBookのキーボードのVIDとPIDの調査」で調べた物と同じ物があるので、それを探します。

・MacBookPro2017 15inchの場合は、「HID\VID_05AC&PID_0278」が見つかります
　「ドライバ」タブで「ドライバの更新」ボタンを押し、
　「コンピューターを参照してドライバーソフトウェアを検索」
　「コンピュータ上の利用可能なドライバの一覧から選択」
　「ディスク使用」
　「参照」
　で、先ほど署名したドライバのフォルダを選択。
　「次へ」
　を押すと「互換性がどうのこうの」と表示されるが「はい」
　「署名がされていない」と表示された場合（署名が信頼されていればでないはず）も
　「インストールを続行」
　を選択。

#◆動作確認#

- 前述のKeyMillで、optionキーが左Windows、左右commandキーが左右ALTになっているかを確認。
- メモ帳等を開いて、ALTキーを押下したままにした際に"ファイル(F)"等に下線が付くか、ALT+F等が効くかを確認。

#◆最後に#

　bcdedit /set TESTSIGNING ON
　で「テスト証明書モードを無効」に設定したいところですが、
　前述の様にMicrosoftによってクロス署名されていない証明書で署名している為、
　これをやるとドライバが読み込まれなくなり内蔵キーボード自体が使えなくなります。

　このドライバをインストールしたまま1903へWindowsをアップデートしたところ、
　正式な署名がないせいかこのドライバだけ外されていました。再度、インストールすれば使える様になります。