SendKeys.Send()仅向当前焦点窗口发送按键,需确保目标窗体已激活并避免辅助功能干扰;多数场景应直接操作控件属性或方法而非模拟输入。

用 SendKeys.Send() 发送简单按键,但注意焦点问题
直接调用 SendKeys.Send() 是最轻量的方式,适合向当前活动窗口发送按键,比如模拟回车、Tab 或字母。但它不控制目标控件,只发给「正在获得输入焦点」的那个窗口——如果目标窗体被遮挡、最小化,或焦点在别的程序上,就完全没反应。
常见错误现象:SendKeys.Send("{ENTER}") 执行后毫无反应,其实只是因为你的 WinForm 窗口没激活,或者调试时焦点在 Visual Studio 的代码编辑器里。
- 确保目标窗体已激活:调用
form.Activate()或form.Focus()(后者不一定生效,优先用Activate()) - 加短延时让系统完成激活:
Thread.Sleep(100)再发键 - 避免在构造函数或
Load事件中立即调用,此时窗体可能尚未完成绘制和焦点分配
keybd_event() 和 SendInput() 谁更可靠?选后者
keybd_event() 是旧 API,Win10/Win11 下容易被拦截(尤其带安全软件时),且不支持 Unicode 字符;SendInput() 是推荐替代,能模拟物理级按键、支持多键组合、兼容性更好,但要用 P/Invoke 声明。
使用场景:需要绕过焦点限制(比如向后台窗口发键)、模拟 Ctrl+C、Alt+Tab,或确保按键被游戏/全屏应用识别。
- 必须用
INPUT_KEYBOARD类型结构体,设置wVk(虚拟键码)或wScan(扫描码) - 按下和释放要成对调用,漏掉
KEYEVENTF_KEYUP会导致键被“卡住” - 模拟中文需先切换输入法并用
SendInput发送 Unicode 字符(通过wScan+KEYEVENTF_UNICODE)
向特定控件发键不用模拟全局输入,改用 Control.Invoke() + PerformClick() 或 Text 赋值
90% 的“模拟键盘输入”需求,其实根本不需要模拟真实按键——比如填表单、点按钮、设文本框内容。强行用 SendKeys 或 SendInput 反而引入焦点、时序、兼容性问题。
例如想让 TextBox tb 显示 “hello”,直接写 tb.Text = "hello";想触发按钮逻辑,调用 btn.PerformClick();如果按钮点击逻辑依赖 KeyDown 事件,那就手动调用对应事件处理函数,或把业务逻辑抽离出来单独调用。
- WinForms 中控件方法大多线程不安全,跨线程访问需用
control.Invoke() - 某些第三方控件(如 DevExpress)重写了输入逻辑,直接赋值
Text可能不触发验证,此时查文档看是否有SetValue()或PostValue()方法 - 自动化测试中,优先走控件接口而非模拟按键,稳定性高一个数量级
调试时 SendKeys 失效?关掉“粘滞键”和屏幕阅读器
Windows 系统级辅助功能会劫持键盘消息,导致 SendKeys 发出的键被吞掉或转义。典型表现是:程序运行正常,但按键不生效;或按一次却触发两次(粘滞键把 Shift 键状态锁住了)。
- 检查是否启用了粘滞键(按 5 次 Shift)、筛选键(连续按右 Shift 8 秒)、讲述人(Win+Ctrl+Enter)
- 临时关闭:进入「设置 > 辅助功能 > 键盘」,关掉所有开关
- 企业环境若策略强制开启,需用
SendInput()并配合SetForegroundWindow()抢占前台,但仍有被拦截风险
真正难的不是发键,而是判断该不该发——多数时候,直接操作控件属性和方法,比模拟人手敲键盘更稳、更快、更可测。











