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

基于user32.dll的键鼠宏无法在《使命召唤4:现代战争》中生效

问题描述

我开发了一款热键触发的后台键鼠录放程序,在Windows系统、Chrome浏览器、《守望先锋》《火箭联盟》等场景下均能正常工作,但在《使命召唤:现代战争(2007)》中,仅鼠标移动位置捕获(GetCursorPos有效),键鼠输入的捕获与回放全部失效。

已尝试的无效实现方式

输入回放类

基于user32.dll的两种键盘模拟方式,在其他场景生效,但该游戏内无响应:

keybd_event((byte)Key, 0, KEYEVENTF_KEYDOWN, UIntPtr.Zero);
// 或
SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(Input)));

鼠标移动模拟同样无效:

mouse_event(MOUSEEVENTF_MOVE, movementX, movementY, 0, UIntPtr.Zero);

输入捕获类

  • GetAsyncKeyState始终返回0:
[DllImport("user32.dll")]
static extern short GetAsyncKeyState(Keys vKey);
// 调用逻辑
GetAsyncKeyState(key)
  • 全局低级键盘钩子(WH_KEYBOARD_LL)完全无响应:
private static ListBox lb1;
public Form1()
{
    InitializeComponent();
    lb1 = listBox1;
    InstallHook();
}

private const int WH_KEYBOARD_LL = 13;
public delegate int KeyboardHookProc(int code, int wParam, ref KeyboardHookStruct lParam);

public struct KeyboardHookStruct
{
    public int vkCode;
    public int scanCode;
    public int flags;
    public int time;
    public int dwExtraInfo;
}

[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, KeyboardHookProc lpfn, IntPtr hMod, uint dwThreadId);

[DllImport("user32.dll", SetLastError = true)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);

[DllImport("user32.dll", SetLastError = true)]
private static extern int CallNextHookEx(IntPtr hhk, int nCode, int wParam, ref KeyboardHookStruct lParam);

private static IntPtr hookHandle = IntPtr.Zero;
private static KeyboardHookProc hookProc = hookProcFunc;

public static void InstallHook()
{
    hookHandle = SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, IntPtr.Zero, 0);
}

public static void UninstallHook()
{
    UnhookWindowsHookEx(hookHandle);
}

private static int hookProcFunc(int code, int wParam, ref KeyboardHookStruct lParam)
{
    if (code >= 0)
    {
        lb1.Items.Add("Keystroke: " + lParam.vkCode);
    }
    return CallNextHookEx(hookHandle, code, wParam, ref lParam);
}

关键参考信息

AHK(AutoHotkey)和罗技HUB宏可在该游戏中正常工作。

核心疑问

  1. 问题是否出在我的输入捕获/触发方法上?
  2. 能否用user32.dll实现通用键鼠宏?
  3. 若不行,有哪些更通用的替代方案(支持非C#语言如C)?

解答

问题根源

《使命召唤:现代战争(2007)》这类老DirectX游戏,未通过Windows消息队列处理输入,而是直接读取硬件输入端口或使用DirectInput API绕过了user32层的输入模拟/捕获逻辑。你使用的user32.dll接口均基于Windows消息机制,自然会被游戏忽略。

关于user32.dll实现通用宏的可能性

user32.dll的接口(SendInput、各类钩子等)仅能覆盖基于Windows消息的输入场景,对直接读取硬件的游戏无能为力,无法实现真正意义上的通用键鼠宏。

替代方案

1. 硬件级输入模拟(推荐)

这类方案直接模拟键鼠的USB/HID信号,游戏无法区分真实输入与模拟输入,AHK和罗技宏本质就是采用了类似逻辑。

  • C/C++实现:使用libusb或Windows原生HIDClass驱动API,构造HID报告直接发送到系统。
  • C#实现:借助SharpHID或HIDSharp库,封装HID设备的模拟逻辑。
  • 注意:需以管理员权限运行,部分系统可能需要禁用驱动签名验证。

2. 游戏进程注入(针对DirectInput场景)

若游戏采用DirectInput读取输入,可将代码注入游戏进程,HookDirectInput8Create或IDirectInputDevice8::GetDeviceState接口,实现输入的捕获与模拟。

  • 工具:用MinHook或EasyHook实现API钩子,在进程内替换输入读取结果。
  • 风险:部分反作弊系统会检测进程注入,老游戏一般无反作弊,但需注意兼容性。

3. 优化SendInput参数适配老游戏

部分老DirectX游戏支持SendInput的扫描码(Scan Code)模拟,而非虚拟键码(VK Code)。修改你的SendInput实现,优先使用扫描码:

INPUT input = new INPUT();
input.type = INPUT_KEYBOARD;
input.mkhi.ki.wScan = (ushort)MapVirtualKey((uint)key, MAPVK_VK_TO_VSC); // 转换VK到扫描码
input.mkhi.ki.dwFlags = KEYEVENTF_SCANCODE; // 指定用扫描码模拟
SendInput(1, ref input, Marshal.SizeOf(typeof(INPUT)));

该方法不一定对所有老游戏生效,但可优先尝试。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 05:35:34