いくつかのキーをリダイレクトするための単純なグローバルキーボードフックプログラムを作成しようとしています。たとえば、プログラムの実行時にキーボードの「a」を押すと、プログラムはそれを無効にして「b」クリックをシミュレートできます。グラフィックUIは必要ありません。コンソールだけで十分です(実行し続けます)
私の計画は、グローバルフックを使用してキー入力をキャッチし、keybd_eventを使用してキーボードをシミュレートすることです。しかし、私にはいくつかの問題があります。
最初の問題は、プログラムが「A」を正しくブロックできることですが、キーボードで「A」を1回押すと、コールバック関数のprintfとkeybd_eventが2回実行されます。したがって、txtファイルを開いて、「A」を1回クリックすると、「B」の入力が2つあります。何故ですか?
2番目の質問は、WH_KEYBOARD_LLを使用するフックがdllなしで他のプロセスで機能できる理由です。この例を書くまでは、dllを使用してグローバルフックを作成する必要があると思いました...
#include "stdafx.h"
#include <Windows.h>
#define _WIN32_WINNT 0x050
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
BOOL fEatKeystroke = FALSE;
if (nCode == HC_ACTION)
{
switch (wParam)
{
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
case WM_KEYUP:
case WM_SYSKEYUP:
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam;
if (fEatKeystroke = (p->vkCode == 0x41)) { //redirect a to b
printf("Hello a\n");
keybd_event('B', 0, 0, 0);
keybd_event('B', 0, KEYEVENTF_KEYUP, 0);
break;
}
break;
}
}
return(fEatKeystroke ? 1 : CallNextHookEx(NULL, nCode, wParam, lParam));
}
int main()
{
// Install the low-level keyboard & mouse hooks
HHOOK hhkLowLevelKybd = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, 0, 0);
// Keep this app running until we're told to stop
MSG msg;
while (!GetMessage(&msg, NULL, NULL, NULL)) { //this while loop keeps the hook
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(hhkLowLevelKybd);
return(0);
}
どうもありがとう!
最初のものは簡単です。 1つはキーダウン用、もう1つはキーアップ用です。 :)
DLL-それはグローバルフックであるためです。スレッド固有のフックとは異なり、キーボードイベントが発生したプロセスではなく、独自のプロセスで実行されます。これは、フックをインストールしたスレッドへのメッセージ送信を介して行われます。そのため、ここでメッセージループが必要になります。これがないと、着信メッセージをリッスンする人がいないため、フックを実行できません。
DLLは、別のプロセスのコンテキストで呼び出されるため、スレッド固有のフックに必要です。これを機能させるには、DLLをに注入する必要があります。そのプロセス。ここではそうではありません。
WM_KEYDOWN
とWM_KEYUP
のため、コールバック関数は2回実行されます。キーボードのキーを押すと、WindowsはWM_KEYDOWN
メッセージでコールバック関数を呼び出し、キーを離すと、WindowsはWM_KEYUP
メッセージでコールバック関数を呼び出します。そのため、コールバック関数は2回実行されます。
Switchステートメントを次のように変更する必要があります。
switch (wParam)
{
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
case WM_KEYUP:
case WM_SYSKEYUP:
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam;
if (fEatKeystroke = (p->vkCode == 0x41)) //redirect a to b
{
printf("Hello a\n");
if ( (wParam == WM_KEYDOWN) || (wParam == WM_SYSKEYDOWN) ) // Keydown
{
keybd_event('B', 0, 0, 0);
}
else if ( (wParam == WM_KEYUP) || (wParam == WM_SYSKEYUP) ) // Keyup
{
keybd_event('B', 0, KEYEVENTF_KEYUP, 0);
}
break;
}
break;
}
2番目の質問については、@ IvanDanilovの回答からすでに得ていると思います。
システムはこの関数を呼び出します。新しいキーボード入力イベントがスレッド入力キューにポストされるたびに。 このメッセージは特殊なケースです。他のメッセージの実際のグローバルフックを作成するには、DLL)も必要です。