見出し画像

キーボード動作確認したいと思ったこと

 いつの頃からか、中古ラップトップが定期的に舞い込んでくる。リフレッシュして依頼主に納品すると、再生品として市場に再投入されることになる。近年は春から夏にかけての恒例行事のようになっている。

リフレッシュ作業

 Windowsラップトップをリフレッシュするとき、まずはカバーの類を外し、ブロワで埃を飛ばし、クロスで全身隈なく磨き、液晶ディスプレイは特に丁寧に丁寧に長年の功績汚れの蓄積を剥ぎ取るように拭き上げする。
 HDDはWipe-outで一掃wipe outし、本体から取り外す。BIOSで接続デバイスが認識されているかどうかの確認はするのだが、できればキーボードの動作確認はしておきたいところ。

ハードディスク消去ツール「wipe-out」 - 超消わいぷたん

Dai ISHIJIMA

都合のいいパートナー

 軽量で素早く起動し、手軽にプログラムが動かせる環境は巷に溢れている。USBブートするLinuxはどれを選べばいいかわからないほどだ。
 しかし、私はリフレッシュPCにWindowsをセットアップし、ドライバやプリインストールアプリケーションも入れてしまいたい。
 なので、お馴染みの Windows PE の出番となる。USBブートできて軽量な必要最小限のシェルを提供してくれるうえ、DISMコマンドが使えるWinPEは私にとって最高に都合のいいパートナーなのである。

DISM の概要 | Microsoft Docs

Microsoft Docs

キーボードチェックに挑戦

 WinPEのセッティングやらオリジナルアプリのセッティングやらは、また別の機会に披露することとして、今回はキーボードチェックの要求を満たすことに集中する。
 WinPE の仕様については基本的にWindowsと同じなのだが、依存関係を極めて少なく構成しなければならないのでVB、C#、.NET、MPF、WPFといったランタイムライブラリを多用するものは採用できなさそうだ。
 なので、今回も Embarcadero C++Builder の出番です。

窓から投げ込まれる伝言

 OSはロミオ。私はジュリエット。
【ジュリエット】「Oh ロミオ。私はキーボードが押されたことを知りたいの!」
【ロミオ】「Ohジュリエット。あなたの想いに応えましょう!!」
【ジュリエット】「できればLowLevelでお願いね。」
【ロミオ】「無問題モーマンタイ!!」

 といった感じでメッセージのやり取りをするのがメッセージ処理。
 今回はWH_KEYBOARD_LLというメッセージフックを実践する。

Windows and Messages - Win32 apps | Microsoft Docs

Microsoft Docs

詳しいことはMicrosoft Docsで

 いつも通り、分からないことはGoogle先生に聞いたうえで、詳細はMicrosoft Docsで確認していくという定番のお作法。
 そんな定番のお作法はこの際省いて、書いてみる。

稚拙なSource Codeをお披露目

HHOOK g_hHook;

BOOL HookingNow() {
	HINSTANCE hInst;

	//アプリケーションインスタンスハンドルを取得
	hInst = (HINSTANCE)GetWindowLong(Handle, GWL_HINSTANCE);

	g_hHook = SetWindowsHookEx(
		WH_KEYBOARD_LL, //LowLevelキーボードフック
		(HOOKPROC)LowLevelKeyboardProc, //コールバック関数ポインタ
		hInst,
		0 //スレッドID
	);

	if ( g_hHook == NULL ){
		return FALSE;
	}
	return TRUE;
}

void UnhookingNow() {
	UnhookWindowsHookEx(g_hHook);
	return void;
}

LRESULT CALLBACK LowLevelKeyboardProc(int code, WPARAM wParam, LPARAM lParam) {
	if ( code < 0 ) {
		return CallNextHookEx(g_hHook, code, wParam, lParam);
	}

	KBDLLHOOKSTRUCT *lp = (KBDLLHOOKSTRUCT*)lParam;
	if (code == HC_ACTION) {
		if (wParam == WM_KEYDOWN) {
			switch (lp->vkCode) {
				case VK_LSHIFT:		//0xA0 [左shift]
					...
					break;
				case VK_RSHIFT:		//0xA1 [右shift]
					...
					break;
				case VK_LCONTROL:	//0xA2 [左ctrl]
					...
					break;
				case VK_RCONTROL:	//0xA3 [右ctrl]
					...
					break;
			}
			return TRUE;
		} else if (wParam == WM_SYSKEYDOWN) {
			switch (lp->vkCode) {
				case VK_LMENU:	 	//0xA4 [左alt]
					...
					break;
				case VK_RMENU:	 	//0xA5 [右alt]
					...
					break;
			}
			return TRUE;
		}

	}
}

実行結果

 結果はすこぶるる良好で、WM_KEYDOWNとWM_SYSKEYDOWNを受け取ったときは、TRUEを返すことで、その後のKEYDOWNイベントを無効にしてしまっているのは意図的であることを記しておく。

後日談

 プログラムをダイナミックリンクしない構成でコンパイルしたものをWinPEに搭載し動作確認したところ、何の問題もなく動作したことをここに記しておく。


今回の検証環境について

今回の検証に使用した環境を紹介。

DELL XPS 13 2-in-1(7390)
Windows 11 Pro(version 21H2 build 22000.556)
Programming reference for the Win32 API
Embarcadero C++Builder 10.4 Community Edition


よろしければサポートお願いします!いただいたサポートは、クリエイターとしての活動費にいつ買わせていただきます!