You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

开发类似ReWASD程序:C++中如何基于窗口句柄阻止键鼠输入?

目标应用专属键鼠输入拦截方案

针对你开发类似ReWASD工具的需求,BlockInput()全局拦截的特性无法满足“仅针对目标应用”的要求,而SetWindowsHookEx()若用全局钩子会影响所有程序,下面是几个精准拦截的可行方案:

1. LowLevel全局钩子+窗口进程过滤

利用WH_KEYBOARD_LL和WH_MOUSE_LL低级别钩子(无需注入目标进程),在钩子回调中判断当前活动窗口所属进程是否为目标应用,是则拦截输入:

实现步骤

  • 预先获取目标应用的进程ID(targetPid),可通过FindWindow+GetWindowThreadProcessId或CreateToolhelp32Snapshot枚举进程得到
  • 注册低级别钩子:
HHOOK hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardLowLevelProc, GetModuleHandle(NULL), 0);
HHOOK hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseLowLevelProc, GetModuleHandle(NULL), 0);
  • 钩子回调中做进程过滤:
LRESULT CALLBACK KeyboardLowLevelProc(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode >= 0) {
        DWORD currentPid;
        GetWindowThreadProcessId(GetForegroundWindow(), &currentPid);
        if (currentPid == targetPid) {
            // 拦截键盘输入,返回非0值跳过后续处理
            return 1;
        }
    }
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

LRESULT CALLBACK MouseLowLevelProc(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode >= 0) {
        DWORD currentPid;
        GetWindowThreadProcessId(GetForegroundWindow(), &currentPid);
        if (currentPid == targetPid) {
            // 拦截鼠标输入
            return 1;
        }
    }
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}
  • 注意:需要保持消息循环运行,钩子才能持续生效;若程序退出,钩子自动失效。

2. 原始输入(Raw Input)拦截

通过注册原始输入设备,接收物理键鼠的原始输入消息,在窗口过程中针对目标应用拦截:

实现步骤

  • 注册原始输入设备(需在窗口创建后执行):
RAWINPUTDEVICE rid[2];
// 注册键盘输入,指定接收消息的窗口句柄hWnd
rid[0].usUsagePage = 0x01;
rid[0].usUsage = 0x06;
rid[0].dwFlags = RIDEV_INPUTSINK;
rid[0].hwndTarget = hWnd;
// 注册鼠标输入
rid[1].usUsagePage = 0x01;
rid[1].usUsage = 0x02;
rid[1].dwFlags = RIDEV_INPUTSINK;
rid[1].hwndTarget = hWnd;

RegisterRawInputDevices(rid, 2, sizeof(RAWINPUTDEVICE));
  • 在窗口过程中处理WM_INPUT消息:
case WM_INPUT: {
    UINT dataSize = 0;
    GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dataSize, sizeof(RAWINPUTHEADER));
    LPBYTE rawBuffer = new BYTE[dataSize];
    if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, rawBuffer, &dataSize, sizeof(RAWINPUTHEADER)) == dataSize) {
        RAWINPUT* pRawInput = (RAWINPUT*)rawBuffer;
        // 判断输入类型为键盘或鼠标
        if (pRawInput->header.dwType == RIM_TYPEKEYBOARD || pRawInput->header.dwType == RIM_TYPEMOUSE) {
            DWORD currentPid;
            GetWindowThreadProcessId(GetForegroundWindow(), &currentPid);
            if (currentPid == targetPid) {
                // 拦截输入,不传递给目标应用
                delete[] rawBuffer;
                return 0;
            }
        }
    }
    delete[] rawBuffer;
    break;
}
  • 优势:直接获取硬件原始输入,避免被其他钩子干扰;无需注入目标进程。

3. 目标进程线程钩子(需DLL注入)

针对目标应用的特定线程设置钩子(WH_KEYBOARD/WH_MOUSE),仅拦截该线程的输入,精准度最高:

实现步骤

  • 编写包含钩子回调函数的DLL,回调中直接拦截输入:
extern "C" __declspec(dllexport) LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode >= 0) {
        // 拦截当前线程的键盘输入
        return 1;
    }
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}
  • 在主程序中获取目标应用的线程ID(通过EnumProcessThreads枚举目标进程的所有线程):
DWORD targetThreadId;
// 枚举目标进程线程逻辑,将目标线程ID赋值给targetThreadId
  • 设置线程钩子:
HMODULE hHookDll = LoadLibrary(L"HookDll.dll");
HOOKPROC pKeyboardProc = (HOOKPROC)GetProcAddress(hHookDll, "KeyboardProc");
HHOOK hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, pKeyboardProc, hHookDll, targetThreadId);
  • 注意:钩子DLL会被注入到目标进程空间,需处理32/64位兼容性问题;若目标进程退出,钩子自动失效。

内容的提问来源于stack exchange,提问作者user21327761

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 23:20:37