キーボード動作確認したいと思ったこと
いつの頃からか、中古ラップトップが定期的に舞い込んでくる。リフレッシュして依頼主に納品すると、再生品として市場に再投入されることになる。近年は春から夏にかけての恒例行事のようになっている。
リフレッシュ作業
Windowsラップトップをリフレッシュするとき、まずはカバーの類を外し、ブロワで埃を飛ばし、クロスで全身隈なく磨き、液晶ディスプレイは特に丁寧に丁寧に長年の功績を剥ぎ取るように拭き上げする。
HDDはWipe-outで一掃し、本体から取り外す。BIOSで接続デバイスが認識されているかどうかの確認はするのだが、できればキーボードの動作確認はしておきたいところ。
都合のいいパートナー
軽量で素早く起動し、手軽にプログラムが動かせる環境は巷に溢れている。USBブートするLinuxはどれを選べばいいかわからないほどだ。
しかし、私はリフレッシュPCにWindowsをセットアップし、ドライバやプリインストールアプリケーションも入れてしまいたい。
なので、お馴染みの Windows PE の出番となる。USBブートできて軽量な必要最小限のシェルを提供してくれるうえ、DISMコマンドが使えるWinPEは私にとって最高に都合のいいパートナーなのである。
キーボードチェックに挑戦
WinPEのセッティングやらオリジナルアプリのセッティングやらは、また別の機会に披露することとして、今回はキーボードチェックの要求を満たすことに集中する。
WinPE の仕様については基本的にWindowsと同じなのだが、依存関係を極めて少なく構成しなければならないのでVB、C#、.NET、MPF、WPFといったランタイムライブラリを多用するものは採用できなさそうだ。
なので、今回も Embarcadero C++Builder の出番です。
窓から投げ込まれる伝言
OSはロミオ。私はジュリエット。
【ジュリエット】「Oh ロミオ。私はキーボードが押されたことを知りたいの!」
【ロミオ】「Ohジュリエット。あなたの想いに応えましょう!!」
【ジュリエット】「できればLowLevelでお願いね。」
【ロミオ】「無問題!!」
といった感じでメッセージのやり取りをするのがメッセージ処理。
今回はWH_KEYBOARD_LLというメッセージフックを実践する。
詳しいことは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
よろしければサポートお願いします!いただいたサポートは、クリエイターとしての活動費にいつ買わせていただきます!