64位Win8系统下WinIO的使用 VS2010 驱动级模拟按键

因为项目的需求,我和我的同学需要编写代码进行计算机键盘的模拟按键程序。一开始我们使用Windows API keybd_event进行软件的按键模拟,但是发现这样做产生的按键消息仅对一些例如记事本、IE等的程序有操控能力,而对赛车游戏无效,即无法通过虚拟按键模拟控制像赛车游戏这样的应用程序。问了问老师,老师也没能给出个明确的答案。我们就猜想可能是游戏的制作者为了防外挂而做了某些处理。

     后来经过查资料得知,原来某些游戏的开发利用了微软提供的DirectX,从而绕过了Windows操作系统的消息封装机制:这些使用DirectX接口的游戏程序,它们在读取键盘操作时绕过了windows的消息机制,而使用DirectInput.这是因为有些游戏对实时性控制的要求比较高,比如赛车游戏,要求以最快速度响应键盘输入。而windows消息由于是队列形式的,消息在传递时会有不少延迟,有时1秒钟也就传递十几条消息,这个速度达不到游戏的要求。而DirectInput则绕过了windows消息,直接与键盘驱动程序打交道,效率当然提高了不少。因此也就造成,对这样的程序无论用PostMessage或者是keybd_event都不会有反应,因为这些函数都在较高层。对于这样的程序,只好用直接读写键盘端口的方法来模拟硬件事件了。要用这个方法来模拟键盘,需要先了解一下键盘编程的相关知识。在DOS时代,当用户按下或者放开一个键时,就会产生一个键盘中断(如果键盘中断是允许的),这样程序会跳转到BIOS中的键盘中断处理程序去执行。打开windows的设备管理器,可以查看到键盘控制器由两个端口控制。其中&H60是数据端口,可以读出键盘数据,而&H64是控制端口,用来发出控制信号。也就是,从&H60号端口可以读此键盘的按键信息,当从这个端口读取一个字节,该字节的低7位就是按键的扫描码,而高1位则表示是按下键还是释放键。当按下键时,最高位为0,称为通码,当释放键时,最高位为1,称为断码。既然从这个端口读数据可以获得按键信息,那么向这个端口写入数据就可以模拟按键了!

       明白了原理,就开始想办法实现了。一开始我想用汇编语言直接控制硬件键盘控制器,通过向键盘端口写入按键数据从而在底层模拟按键消息。我想在C++代码中嵌入这些汇编语句。但是后来通过查资料得知这是行不通的,因为我们一般编写的应用程序是运行在用户态的,而读写硬件这样的操作要运行在核心态。要实现读写硬件的功能,可能要自己开发驱动程序。

      那么,不通过写驱动程序,能不能实现这样的功能呢?当然可以了!用WinIo就可以!不过,WinIO使用起来比较麻烦,但不是说他本身提供的函数难以理解,而是将它嵌入到自己的程序之中编译通过,没有问题的运行特别不好搞。

   什么是WINIO?WINIO是一个全免费的、无需注册的、含源程序的WINDOWS2000端口操作驱动程序组件(可以到http://www.internals.com/上去下载)。它不仅可以操作端口,还可以操作内存;不仅能在C++下用,还可以在DELPHI、C#等其它环境下使用,性能特别优异。下载该组件,经过各种版本的下载,我最后得到了正确的版本,那就是WinIo - Version 3.0,解压缩后可以看到几个文件夹,将Binaries文件夹下的WinIo64.sys,WinIo32.dll复制到自己程序的Debug目录下:64位Win8系统下WinIO的使用 <wbr>VS2010 <wbr>驱动级模拟按键

然后修改WinIo64.sys的数字签名:

cmd->bcdedit /set testsigning on

然后修改WinIo64.sys的测试签名

1.打开 WinIO64.sys的属性框,翻到“数字签名”选项卡,点击“详细信息”
2.在新出来的对话框中点击“查看证书”
3.在又新出来的对话框中点击“安装证书”
4.点击“下一步”,然后选择“将所有的证书放入下列存储”
5.点击浏览,选择“受信任的根证书发布机构”

WinIo64.sys必须是64位的,我想因为我的操作系统是64的,而dll是32位的是因为开发的程序是32位的(我尝试了32位和64位的各种组合,最后发现只有这两种组合可以使应用程序正常运行,不信的话你可以到Binaries目录下,此目录下有两个应用程序实例exe以及程序能正常运行所

依赖的文件dll和sys,你可以删除任意一组sys和dll的组合,最终可能出和我一样的结论:WinIo64.sys,WinIo32.dll两个文件是64位系统下32位应用程序所需要的   64位Win8系统下WinIO的使用 <wbr>VS2010 <wbr>驱动级模拟按键

       然后可从网上下载WinIo.lib或在WinIo\Source\Dll下找到WinIo.sln用VS打开、编译得WinIO.lib,放到工作目录下,然后将其引入到程序中:选择项目属性->连接器->常规,将WinIO.lib所在的目录填到附加目录中,再选择连接器->输入,将WinIO.lib填入附加依赖项。好了,开发环境基本设置好了。

     然后在WinIo\Source目录及其子目录下找到WinIO.h、winio_nt.h,并添加到工程中(注意:要手动在winio_nt.h中包含Windows.h头文件)。以下是我写的类:

#pragma once
#include "WinIo.h"
#define KBC_CMD 0x64
#define KBC_DATA 0x60

class CHdio
{
public:
 CHdio(void);
 ~CHdio(void);
 void KBCWait4IBE();
 void MyKeyDown(DWORD KCode);
 void MyKeyUp(DWORD KCode);
};

 

#include "StdAfx.h"
#include "Hdio.h"


CHdio::CHdio(void)
{
 InstallWinIoDriver((PWSTR)"WinIo64.sys",0);
 LoadLibrary(L"WinIo32.dll");
 while(!InitializeWinIo())
 {
  system("close.exe");
 }
}


CHdio::~CHdio(void)
{

  ShutdownWinIo();
}

void CHdio::KBCWait4IBE()
{
 DWORD dwVal=0;
 do
 {
  GetPortVal(KBC_CMD,&dwVal,1);
 }while((&dwVal)&&(0x2)==0);
}

void CHdio::MyKeyDown(DWORD KCode)    
   
    Sleep(20);    //休息2秒         
    KBCWait4IBE(); //等待键盘缓冲区为空    
    SetPortVal( 0X64, 0xD2, 1 ); //发送键盘写入命令    
    Sleep(10);    
    KBCWait4IBE();    
    SetPortVal( 0X60, MapVirtualKey(KCode, 0), 1 ); //写入按键信息,按下键    
   
         
void CHdio::MyKeyUp(DWORD KCode)    
   
    Sleep(10);    
    KBCWait4IBE(); //等待键盘缓冲区为空    
    if (SetPortVal(0X64, 0xD2, 1 )) //发送键盘写入命令    
    Sleep(10);    
    KBCWait4IBE();    
    SetPortVal(0X60, (MapVirtualKey(KCode, 0) | 0x80), 1);//写入按键信息,释放键    
   

 

#include "stdafx.h"
#include "Hdio.h"

int _tmain(int argc, _TCHAR* argv[])
{
 CHdio m;
 while(1)
 {
  m.MyKeyDown(VK_LSHIFT);
  m.MyKeyUp(VK_LSHIFT);
 }
 return 0;
}

 

此程序会一直模拟按下shift键。注意,在类的初始化函数中,有一个while循环,当初始化Winio库不成功是会一直循环直到成功。关于winio初始化失败的原因我查资料查了一下午,各种方法都没成功。最后看到这篇文章有了灵感:http://hi.baidu.com/luckily513/item/e3df432c7e64ff9ab73263b0

64位Win8系统下WinIO的使用 <wbr>VS2010 <wbr>驱动级模拟按键

于是我将这个删除WINIO程序写成了close.exe放在Debug目录下调用(写成子函数无效!),结果成功了!只是有时程序关闭后,键盘会不能用了!这时只要再次运行一下程序就好了。

    经过第二天的调试及思考,我发现,只要注释掉InstallWinIoDriver((PWSTR)"WinIo64.sys",0);然后InitializeWinIo()函数就可以初始化成功而且不必编写close的子程序,我想可能是InitializeWinIo()函数内部调用了InstallWinIoDriver()函数所以到时服务在InitializeWinIo()函数调用之前就存在了。64位Win8系统下WinIO的使用 <wbr>VS2010 <wbr>驱动级模拟按键


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值