1. 使用.Net Framework的库函数

SendKeys.SendWait("123{TAB}abc");

namespace System.Windows.Forms命名空间下的SendKeys是.Net提供的模拟键盘输入的工具类。其中有Send()SendWait()这两个方法,都可以发送按键消息。区别在于SendWait()是会等待按键消息被处理完成才返回的,而Send()则不用。这就类似于SendMessagePostMessage的关系。
上面代码中的{TAB}代表Tab键。键盘上一些特殊的按键都有对应的代码,具体的对照表可以参照微软MSDN上的介绍:SendKeys Class

当然,还可以使用Windows API,API原型如下:

        /// <summary>/// 合成一次击键事件/// </summary>/// <param name="bVk">定义一个虚拟键码。键码值必须在1~254之间</param>/// <param name="bScan">定义该键的硬件扫描码</param>/// <param name="dwFlags">定义函数操作的各个方面的一个标志位集。应用程序可使用如下一些预定义常数的组合设置标志位</param>/// <param name="dwExtraInfo">定义与击键相关的附加的32位值</param>[DllImport("user32")]public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags,
uint dwExtraInfo);

甚至用SendMessagePostMessage也是可以做到的。

但以上这些实现方法都是在Windows消息层面的,对于像记事本等常规应用程序是没问题的。但是对于一些游戏、QQ登录框、网银登录框等则无效。这是因为这些程序不是从Windows消息中获取按键信息的,而是直接从底层驱动层面获取按键信息的

在一篇关于研究游戏外挂的博文里看到博主描述了这个问题:

引自:https://blog.csdn.net/zdrl/article/details/12707835

在解释更详细的原理之前,我们先来抓出幕后黑手,看看是哪个给游戏撑腰?让它有胆子违抗Windows消息命令。究竟是判断了真实键盘信息,还是有其他原因。结果在DirectX编程中发现了DirectInput这个API。就是它绕过了Windows的消息机制,它的目的是为了让游戏的实时性控制更好、更快。Windows消息是队列形式的,在传递过程中会有延时,比如格斗类游戏对实时性控制要求是非常高的,Window消息机制不能满足这个需求。而DirectInput直接和键盘驱动程序打交道,效率当然要高出一大截。我认为大部分游戏不响应消息的真正的原因在这里,而不是故意写了反作弊系统。

2. 使用WinIO.dll

由于上述方法只能模拟Windows消息层面的按键,以至于对一些应用程序无效,所以下面就采用直接在驱动层面模拟按键的方法。
这里需要用到一个组件,那就是使用WinIO.dll,这是是国外大佬开发的一个dll。

引自百度百科:https://baike.baidu.com/item/winio/2877240?fr=aladdin

WinIO程序库允许在32位的Windows应用程序中直接对I/O端口和物理内存进行存取操作。通过使用一种内核模式的设备驱动器和其它几种底层编程技巧,它绕过了Windows系统的保护机制。

使用此组件的环境要求:

  • 系统Win7或Win10均可。
  • 需要PS/2键盘(老式的针孔插头的键盘),USB键盘不行。
  • 正规使用的话需要官方授权签名,否则就得将Windows开启测试模式。
  • 使用此组件的应用程序需要以管理员的身份启动。
  • 此组件还有32位和64位的区分。
  • 与dll配套的还有个.sys的文件,要跟dll放在同一目录下。

Windows开启测试模式的方法:
以管理员身份打开cmd,输入开启测试模式的命令并执行。然后重启电脑,看到桌面右下角出现“测试模式”字样即可。

开启测试模式的命令:

bcdedit /set testsigning on

关闭测试模式的命令:

bcdedit /set testsigning off

开启测试模式成功:

调用WinIO64.dll的示例代码:

    public class WinIO64{private const int KBC_KEY_CMD = 0x64;private const int KBC_KEY_DATA = 0x60;#region WinIo64.dll[DllImport("WinIo64.dll")]public static extern bool InitializeWinIo();[DllImport("WinIo64.dll")]public static extern bool GetPortVal(IntPtr wPortAddr, out int pdwPortVal,
byte bSize);[DllImport("WinIo64.dll")]public static extern bool SetPortVal(uint wPortAddr, IntPtr dwPortVal, byte
bSize);[DllImport("WinIo64.dll")]public static extern byte MapPhysToLin(byte pbPhysAddr, uint dwPhysSize,
IntPtr PhysicalMemoryHandle);[DllImport("WinIo64.dll")]public static extern bool UnmapPhysicalMemory(IntPtr PhysicalMemoryHandle,
byte pbLinAddr);[DllImport("WinIo64.dll")]public static extern bool GetPhysLong(IntPtr pbPhysAddr, byte pdwPhysVal);[DllImport("WinIo64.dll")]public static extern bool SetPhysLong(IntPtr pbPhysAddr, byte dwPhysVal);[DllImport("WinIo64.dll")]public static extern void ShutdownWinIo();#endregion[DllImport("user32.dll")]public static extern int MapVirtualKey(uint Ucode, uint uMapType);private WinIO64(){IsInitialize = true;}public static void Initialize(){if (InitializeWinIo()){KBCWait4IBE();IsInitialize = true;}elseMessageBox.Show("Load WinIO Failed!");}public static void Shutdown(){if (IsInitialize)ShutdownWinIo();IsInitialize = false;}private static bool IsInitialize { get; set; }///等待键盘缓冲区为空private static void KBCWait4IBE(){int dwVal = 0;do{bool flag = GetPortVal((IntPtr)0x64, out dwVal, 1);}while ((dwVal & 0x2) > 0);}/// 模拟键盘标按下public static void KeyDown(Keys vKeyCoad){if (!IsInitialize) return;int btScancode = 0;btScancode = MapVirtualKey((uint)vKeyCoad, 0);KBCWait4IBE();SetPortVal(KBC_KEY_CMD, (IntPtr)0xD2, 1);KBCWait4IBE();SetPortVal(KBC_KEY_DATA, (IntPtr)0x60, 1);KBCWait4IBE();SetPortVal(KBC_KEY_CMD, (IntPtr)0xD2, 1);KBCWait4IBE();SetPortVal(KBC_KEY_DATA, (IntPtr)btScancode, 1);}/// 模拟键盘弹出public static void KeyUp(Keys vKeyCoad){if (!IsInitialize) return;int btScancode = 0;btScancode = MapVirtualKey((uint)vKeyCoad, 0);KBCWait4IBE();SetPortVal(KBC_KEY_CMD, (IntPtr)0xD2, 1);KBCWait4IBE();SetPortVal(KBC_KEY_DATA, (IntPtr)0x60, 1);KBCWait4IBE();SetPortVal(KBC_KEY_CMD, (IntPtr)0xD2, 1);KBCWait4IBE();SetPortVal(KBC_KEY_DATA, (IntPtr)(btScancode | 0x80), 1);}}}

3. 使用WinRing0x64.dll

这里还有另外一个组件WinRing0x64.dll,可以实现同样的效果。不需要授权签名,不需要开启测试模式,使用起来要方便很多。

使用此组件的环境要求:

  • 系统Win7或Win10均可。
  • 需要PS/2键盘(老式的针孔插头的键盘),USB键盘不行。
  • 使用此组件的应用程序需要以管理员的身份启动。
  • 与dll配套的还有个.sys的文件,要跟dll放在同一目录下。
  • 此组件应该也是区分32位和64位的,只是我只找到64位的,没再去管32位的。

调用此组件的示例代码有点长,这里就懒得贴了。

对于2和3这两种方式,我写了一个完整、可行的Demo,放在GitHub上了。包括需要的组件都在里面。
链接:
模拟键盘输入的Demo
URL地址:https://github.com/Zzz2333/TestKeyboard

搜集的参考资料汇总:
爬虫应对银行安全控件
驱动级键盘模拟(C#)
C#模拟鼠标和键盘操作
Windows下对硬件端口的操作—WinIo库的使用
WinIo使用笔记

C# 驱动级模拟键盘输入相关推荐

  1. python模拟键盘输入字符_Python | 根据关键字符串遍历窗口 模拟键盘输入操作

    在自动化脚本测试某个程序的过程中,偶尔会因为文件读取操作弹出各种信息窗口,导致自动化脚本无法继续往下执行.为了解决这个问题,需要隔一段时间对信息窗口进行一次遍历,针对需要处理的窗口进行模拟键盘输入操作 ...

  2. python 模拟键盘_Python 模拟键盘输入 | 学步园

    Python 模拟键盘输入,留着备用. #coding=utf-8 import win32gui,win32api,win32con import time import threading def ...

  3. 模拟键盘输入的keycode

    今天有个弹出框的element一直找不到,换了种方法关掉,就是用模拟键盘输入,找到以下对应的keycode,先记录下来,说不定以后用得上/*--------------------edit by 20 ...

  4. php虚拟键盘输入,[问题] bash下如何模拟键盘输入

    你的位置: 问答吧 -> Shell -> 问题详情 [问题] bash下如何模拟键盘输入 我想要在bash下模拟键盘输入. 现在有两个实例. 1. 如果我在使用未配置sudo nopas ...

  5. python3模拟键盘输入_Python模拟键盘输入

    使用pynput库达到模拟键盘输入的目的(也可以进行鼠标模拟). 1.安装pynput库 pip install pynput 2.引入键盘所需类 from pynput.keyboard impor ...

  6. python如何模拟键盘输入_python 模拟键盘输入

    python 模拟键盘输入 一.PyUserInput安装 python3.5的PyMouse和PyKeyboard模块都集成到了PyUserInput模块中.在python3.5中,直接安装PyUs ...

  7. vc++6.0 模拟鼠标点击代码 木马程序的编写 VC 模拟键盘输入

    From: http://fengqing888.blog.163.com/blog/static/33011416201112124481/ MFC 工程 把以下代码放到你想要响应的函数里面就行 C ...

  8. 通过javascript在IE模拟键盘输入

    今天有个东西需要在浏览器中模拟键盘组合键,比如 Ctrl + M . 在网上搜索了一下,资料都不是我想要的. 后来想想,从安全性考虑浏览器应该不会提供这样的功能. 不过在网上找了两段代码,还是有点用处 ...

  9. python3模拟键盘输入_python 模拟键盘输入

    一.PyUserInput安装 python3.5的PyMouse和PyKeyboard模块都集成到了PyUserInput模块中.在python3.5中,直接安装PyUserInput模块即可 Py ...

  10. python 模拟键盘输入组合键_Python 模拟键盘输入

    Python 模拟键盘输入,留着备用. #coding=utf-8 import win32gui,win32api,win32con import time import threading def ...

最新文章

  1. 2021年中国工业互联网安全大赛核能行业赛道writeup之鱿鱼游戏
  2. 错误:wasm streaming compile failed: CompileError: AsyncCompile: Wasm decoding failed
  3. DBA(三):MySQL主从同步、复制模式
  4. 利用注解 + 反射消除重复代码,妙!
  5. linux下mysql数据库目录迁移_linux下mysql数据库目录迁移问题
  6. java 反射 int_Java 反射由浅入深 | 进阶必备
  7. 浏览器原生支持平滑滚动
  8. retinanet 部署_目标检测RetinaNet_飞桨-源于产业实践的开源深度学习平台
  9. 19【推荐系统18】MMoE-PosBias:多任务学习
  10. python训练手势分类器_从Scikit Learn中保存的训练分类器进行预测
  11. 计算机软件毕业论文教师指导记录,【毕业论文指导教师指导记录】论文指导记录16篇...
  12. Viterbi算法(维特比算法)
  13. seo好学吗?怎么学seo?
  14. 二维最大类间方差阈值分割的快速迭代算法
  15. 集成Cortex-M0内核-- Integration and Implementation Manual手册学习
  16. JavaScript知识点全面概括与总结(上)
  17. dell笔记本外接显示器_戴尔笔记本怎么连接外接显示器?
  18. CAD三维图自动生成三视图
  19. 魔兽DOTA高玩的自述
  20. HTTP与HTTPS,HTTPS更加安全。

热门文章

  1. 三元一次方程组步骤_怎样解三元一次方程组 50道三元一次方程组计算题及答案过程...
  2. 剩余电流动作继电器在浴室中的应用
  3. javaweb JSP JAVA 酒店预订系统j酒店管理系统民宿预订)酒店客房预订系统宾馆客房预订系统
  4. 【软件工具】之 TotalCommander
  5. TOM邮箱|国内适合商务人士的邮箱是什么邮箱
  6. Java进阶篇设计模式之五-----外观模式和装饰器模式
  7. UC Android官方下载,手机uc浏览器下载并安装-uc浏览器app最新版本v13.3.9.1119 安卓官方版 - 极光下载站...
  8. 2021高考数学成绩查询,2021八省联考成绩相继公布!数学平均60多分,八个省市本科录取率曝光...
  9. 《数据库系统概论》复习
  10. vue+element去重并且替换符号为英文分号