C#中SendInput无法正常模拟键盘事件的问题排查
问题分析与修复方案
核心错误:SendInput的cbSize参数错误
你的代码调用SendInput时传入的cbSize是Marshal.SizeOf(union),但根据Win32 API规范,该参数必须是单个INPUT结构体的大小,而非InputUnion的大小。这是导致SendInput返回0(调用失败)的直接原因。
其他潜在问题
- 仅模拟按键按下,未释放:多数程序需要完整的"按下+释放"事件才会响应单个按键操作,仅模拟按下可能无法触发预期行为。
- wVk赋值不规范:直接用
(ushort)'A'虽能得到A键的虚拟键码0x41,但更稳妥的方式是直接使用虚拟键码值(如0x41),避免字符编码差异引发问题。 - 未初始化冗余字段:
KEYBDINPUT的wScan、time、dwExtraInfo字段未显式初始化,内存中的垃圾值可能干扰API执行。
修复后的代码示例
修正SendInput调用逻辑
// 传入INPUT结构体的大小作为cbSize参数 uint result = SendInput(1, input, Marshal.SizeOf(typeof(INPUT))); Console.WriteLine(result); Console.WriteLine(Marshal.GetLastWin32Error());
完整的A键模拟(按下+释放)
// 构造按下事件 KEYBDINPUT keyDown = new KEYBDINPUT(); keyDown.wVk = 0x41; // A键的虚拟键码 keyDown.dwFlags = (uint)KeyEventFlags.KEYDOWN; keyDown.wScan = 0; keyDown.time = 0; keyDown.dwExtraInfo = IntPtr.Zero; // 构造释放事件 KEYBDINPUT keyUp = new KEYBDINPUT(); keyUp.wVk = 0x41; keyUp.dwFlags = (uint)(KeyEventFlags.KEYUP); keyUp.wScan = 0; keyUp.time = 0; keyUp.dwExtraInfo = IntPtr.Zero; InputUnion unionDown = new InputUnion(); unionDown.ki = keyDown; InputUnion unionUp = new InputUnion(); unionUp.ki = keyUp; INPUT[] inputs = new INPUT[2]; inputs[0].type = (uint)InputTypes.KEYBOARD; inputs[0].U = unionDown; inputs[1].type = (uint)InputTypes.KEYBOARD; inputs[1].U = unionUp; // 执行模拟 uint result = SendInput(2, inputs, Marshal.SizeOf(typeof(INPUT))); Console.WriteLine($"成功发送的输入数:{result}"); Console.WriteLine($"错误码:{Marshal.GetLastWin32Error()}");
额外说明
- 若需模拟Unicode字符,需设置
dwFlags = KeyEventFlags.KEYDOWN | KeyEventFlags.UNICODE,同时将wVk设为0,wScan赋值为目标Unicode字符的代码值。 - 模拟前确保目标窗口处于激活状态,否则键盘事件可能无法被捕获。
内容的提问来源于stack exchange,提问作者Han Han
相关产品推荐
相关产品推荐

