假设我们无法控制的应用程序安装了某种全局键盘或鼠标挂钩。是否可以阻止这些事件到达此应用程序?
如果您只是想阻止使用 LowLevelKeyboard(或鼠标)的应用程序的输入,那么钩子相当简单。
但是,如果您想阻止输入进入游戏或许多应用程序,则必须编写一个过滤驱动程序。大多数游戏不使用钩子,而是使用 API,例如 DirectInput 或 XInput,我相信它们直接与 HID 驱动程序对话。 我知道有 2 个项目已经做到了这一点,HidHide 和 HidGuardian。
至于阻止钩子,我编写了一个快速程序来做到这一点。 它的工作原理是安装自己的键盘钩子,检查要阻止输入的应用程序是否是前台窗口,然后如果是前台窗口,则钩子返回而不是调用下一个钩子。 修改它也很容易包括鼠标输入。 我认为只有在您希望阻止的应用程序之前运行该程序才有效,但这似乎并不重要。
这种方法存在一些问题。如果它不适用于大多数应用程序,或者仅部分适用于某些应用程序,请不要感到惊讶。 我还使用 WinForms 编写了一个测试应用程序来测试阻塞,它将控件文本设置为当前按下的键。它成功阻止了这一点,但它并没有阻止文本框接收其输入。
阻塞发生在
LowLevelKeyboardProc_cb,
,剩下的只是设置代码来获取句柄并设置挂钩。
LRESULT CALLBACK LowLevelKeyboardProc_cb(
_In_ int nCode,
_In_ WPARAM wParam,
_In_ LPARAM lParam)
{
HWND fWnd = GetForegroundWindow();
//hBlock is the handle to the process's main window
if (fWnd != hBlock || nCode < 0)
return CallNextHookEx(hookId, nCode, wParam, lParam);
else
return 0; //Block
}
#include <iostream>
#include <stdlib.h>
#include <Windows.h>
#include <tlhelp32.h>
void SetHook();
void UninstallHook();
DWORD GetProcessIdFromName(const char* name);
HWND FindTopWindow(DWORD pid);
HWND hBlock;
HHOOK hookId;
DWORD pidBlock;
int main(int argc, char* argv[])
{
char* processName = argv[1];
printf("Searching for process \"%s\"...\n", processName);
while (pidBlock == 0)
{
pidBlock = GetProcessIdFromName(processName);
}
std::cout << "Found\n";
//Allow window to initialize.
Sleep(1000);
std::cout << "Searching for main window handle...\n";
hBlock = FindTopWindow(pidBlock);
if (hBlock == 0)
{
std::cout << "Could not find Window Handle\n";
return 0;
}
std::cout << "Found\n";
std::cout << "Installing Hook...\n";
SetHook();
std::cout << "Blocking...";
MSG msg;
while (GetMessage(&msg, NULL, NULL, NULL))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
LRESULT CALLBACK LowLevelKeyboardProc_cb(
_In_ int nCode,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
HWND fWnd = GetForegroundWindow();
if (fWnd != hBlock || nCode < 0)
return CallNextHookEx(hookId, nCode, wParam, lParam);
else
return 0; //Block
}
void SetHook()
{
HANDLE hProcess = GetCurrentProcess();
HMODULE hModule = GetModuleHandle(NULL);
hookId = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc_cb, hModule, 0);
CloseHandle(hProcess);
}
void UninstallHook()
{
if (hookId == 0)
return;
std::cout << "Uninstalling Hook.\n";
UnhookWindowsHookEx(hookId);
hookId = 0;
}
DWORD GetProcessIdFromName(const char* name)
{
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (Process32First(snapshot, &entry) == TRUE)
{
while (Process32Next(snapshot, &entry) == TRUE)
{
size_t nChars;
char szExeFile[64];
wcstombs_s(&nChars, szExeFile, entry.szExeFile, sizeof(szExeFile));
if (_stricmp(szExeFile, name) == 0)
{
DWORD pid = entry.th32ProcessID;
CloseHandle(snapshot);
return pid;
}
}
}
CloseHandle(snapshot);
return 0;
}
HWND FindTopWindow(DWORD pid)
{
std::pair<HWND, DWORD> params = { 0, pid };
// Enumerate the windows using a lambda to process each window
BOOL bResult = EnumWindows([](HWND hwnd, LPARAM lParam) -> BOOL
{
auto pParams = (std::pair<HWND, DWORD>*)(lParam);
DWORD processId;
if (GetWindowThreadProcessId(hwnd, &processId) && processId == pParams->second)
{
// Stop enumerating
SetLastError(-1);
pParams->first = hwnd;
return FALSE;
}
// Continue enumerating
return TRUE;
}, (LPARAM)¶ms);
if (!bResult && GetLastError() == -1 && params.first)
{
return params.first;
}
return 0;
}