1.使用.Net Framework的库函数
SendKeys.SendWait("123{TAB}abc");
System.Windows.Forms命名空间下的
SendKeys是用于模拟.Net提供的键盘输入的工具。有两种方法,Send()和SendWait(),这两种方法都可以发送关键消息。不同之处在于,SendWait()将在返回之前等待关键消息的处理,而Send()则不会。这类似于SendMessage和PostMessage之间的关系。
上面的代码中的
{TAB}表示Tab键。键盘上的一些特殊键具有相应的代码,具体的比较表可以参考Microsoft MSDN上的介绍:SendKeys类
当然,您也可以使用Windows API,该API原型如下:
///
/// 合成一次击键事件
///
/// 定义一个虚拟键码。键码值必须在1~254之间
/// 定义该键的硬件扫描码
/// 定义函数操作的各个方面的一个标志位集。应用程序可使用如下一些预定义常数的组合设置标志位
/// 定义与击键相关的附加的32位值
[DllImport("user32")]
public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags,
uint dwExtraInfo);
甚至可以使用SendMessage和PostMessage完成。
但是,以上实现方法都是Windows消息级别的,对于常规应用程序(如记事本)而言,这没有问题。但这对于某些游戏,QQ登录框,网上银行登录框等无效。这是因为这些程序不是从Windows消息中获取关键信息,而是直接从底层驱动程序级别获取关键信息。
在有关研究游戏插件的博客文章中,我看到博客描述了此问题:

引用自:
在更详细地解释该原理之前,让我们抓住幕后黑手,看看哪个人在支持这场比赛?让它有胆量违抗Windows message命令。是否判断实际的键盘信息还是有其他原因?结果,我在DirectX编程中找到了DirectInput API。它绕过了Windows消息机制,其目的是使游戏的实时控制更好,更快。 Windows消息以队列的形式出现,并且传输过程中会有延迟。例如,格斗游戏对实时控制有很高的要求,而窗口消息机制不能满足这一要求。而且DirectInput直接与键盘驱动程序打交道,当然,效率要高得多。我认为大多数游戏不响应消息的真正原因是在这里,而不是故意编写反作弊系统。
2.使用WinIO.dll
由于上述方法只能模拟Windows消息级别的按钮,因此对于某些应用程序无效,因此下面使用在驱动程序级别直接模拟按钮的方法。
这里需要使用一个组件,即WinIO.dll,它是由外国大亨开发的dll。
引自百度百科:
WinIO库允许直接访问32位Windows应用程序中的I / O端口和物理内存。通过使用内核模式设备驱动程序和其他几种低级编程技术,它可以绕开Windows系统的保护机制。
使用此组件的环境要求:
如何在Windows中打开测试模式:
以管理员身份打开cmd,输入命令以打开测试模式并执行它。然后重新启动计算机,并在桌面的右下角看到“测试模式”字样。
打开测试模式的命令:

bcdedit /set testsigning on
关闭测试模式的命令:
bcdedit /set testsigning off
成功打开测试模式:
成功打开测试模式
调用WinIO6 4. 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;
}
else
MessageBox.Show("Load WinIO Failed!");
}
public static void Shutdown()
{
if (IsInitialize)
ShutdownWinIo();
IsInitialize = false;
}
private static bool IsInitialize { get; set; }
///等待键盘缓冲区为空
private static void KBCWait4IBE()