您的位置:首页 > 其它

基于WinIO 3.0实现驱动级键盘模拟输入

2014-11-14 09:25 417 查看

基于WinIO 3.0实现驱动级键盘模拟输入

一个业务场景需要使用驱动级的键盘模拟,折腾了2天,总结一下,为后人节省时间。

限制条件:

1.需要真实PC机,虚拟机不行

2.仅支持PS/2 键盘(指外接键盘,笔记本直接使用是没问题的)

实现:

关于WinIO没啥好说的,自行查阅吧。

直接上可执行代码,注意红色注释部分,网上很多资料这几个不对导致不能有正确结果

测试程序里扣出来的,请先行初始化调用InitializeWinIo();

#define KBC_CMD 0x64
#define KBC_DATA 0x60

void KBCWait4IBE()
{
DWORD dwVal=0;

do
{
GetPortVal(KBC_CMD,&dwVal,1);
}
while(dwVal & 0x00000002); //其他条件均不正确

}

void KEY_DOWN(int vk_in)
{
bool bRet = false;
unsigned int myscancode;
myscancode=MapVirtualKey(BYTE(vk_in),0);
KBCWait4IBE();
bRet = SetPortVal(KBC_CMD,0xD2,1);
KBCWait4IBE();
bRet = SetPortVal(KBC_DATA,0xE2,1);
KBCWait4IBE();
bRet = SetPortVal(KBC_CMD,0xD2,1);
KBCWait4IBE();
bRet = SetPortVal(KBC_DATA,myscancode,1);
}

void KEY_UP(int vk_in)
{
bool bRet = false;
unsigned myscancode;
myscancode=MapVirtualKey(BYTE(vk_in),0);
KBCWait4IBE();
bRet = SetPortVal(KBC_CMD,0xD2,1);
KBCWait4IBE();
bRet = SetPortVal(KBC_DATA,0xE0,1);
KBCWait4IBE();
bRet = SetPortVal(KBC_CMD,0xD2,1);
KBCWait4IBE();

bRet = SetPortVal(KBC_DATA,(myscancode|0x80),1); //此处需要与上0x80
}

void Key_Press(int vk_in)
{
// sti() ;

KEY_DOWN(vk_in);
Sleep(150);
KEY_UP(vk_in);
Sleep(150);
}

void InputString(CString &strInput)
{
int nLen = strInput.GetLength();

for (int i = 0; i < nLen; i++)
{
short nKey = VkKeyScan(strInput.GetAt(i)); //注:由ASCII码转成按键码
bool bShift = (nKey & 0x100); //shift键是否按下检查

long n = GetKeyState(VK_CAPITAL); //Caps键是否按下检查

Key_Press(nKey);
}

}

void CWinIOTestDlg::OnButton1()
{
// TODO: Add your control notification handler code here

CString strInput;

CWnd* pWnd =
GetDlgItem( IDC_EDIT1 );

pWnd->GetWindowText(strInput);

Sleep(4000); //可以不用,我测试时留时间给自己切换窗口用的

InputString(strInput);

}

void CWinIOTestDlg::OnCancel()
{
// TODO: Add extra cleanup here
ShutdownWinIo();
CDialog::OnCancel();
}

另WinIO 3.0的32位系统代码有点问题,在某些密码输入控件下输入会抛特权指令异常(privileged instruction)

解决方法也很简单(自己找解决办法搞了一天),修改WinIO代码为如下所示,重新编译生成DLL即可

Port32.cpp

// ---------------------------------------------------- //
// WinIo v3.0 //
// Direct Hardware Access Under Windows //
// Copyright 1998-2010 Yariv Kaplan //
// http://www.internals.com //
// ---------------------------------------------------- //

#include <windows.h>
#include <winioctl.h>
#include <conio.h>
#include "port32.h"
#include "..\drv\winio_nt.h"
#include "winio.h"

bool _stdcall GetPortVal(WORD wPortAddr, PDWORD pdwPortVal, BYTE bSize)
{
if (!IsWinIoInitialized)
{
return false;
}

#ifdef _WIN64
tagPortStruct PortStruct;
DWORD dwBytesReturned;

PortStruct.bSize = bSize;
PortStruct.wPortAddr = wPortAddr;

return DeviceIoControl(hDriver, IOCTL_WINIO_READPORT, &PortStruct, sizeof(PortStruct),
pdwPortVal, sizeof(DWORD), &dwBytesReturned, NULL);

#elif _WIN32
// If this is a 64 bit OS, we must use the driver to access I/O ports even if the application is 32 bit
//if (g_Is64BitOS)
{
tagPortStruct PortStruct;
DWORD dwBytesReturned;

PortStruct.bSize = bSize;
PortStruct.wPortAddr = wPortAddr;

return DeviceIoControl(hDriver, IOCTL_WINIO_READPORT, &PortStruct, sizeof(PortStruct),
pdwPortVal, sizeof(DWORD), &dwBytesReturned, NULL);
}

#endif

return true;
}

bool _stdcall SetPortVal(WORD wPortAddr, DWORD dwPortVal, BYTE bSize)
{
if (!IsWinIoInitialized)
{
return false;
}

#ifdef _WIN64
tagPortStruct PortStruct;
DWORD dwBytesReturned;

PortStruct.bSize = bSize;
PortStruct.dwPortVal = dwPortVal;
PortStruct.wPortAddr = wPortAddr;

return DeviceIoControl(hDriver, IOCTL_WINIO_WRITEPORT, &PortStruct, sizeof(PortStruct),
NULL, 0, &dwBytesReturned, NULL);
#elif _WIN32
// If this is a 64 bit OS, we must use the driver to access I/O ports even if the application is 32 bit
//if (g_Is64BitOS)
{
tagPortStruct PortStruct;
DWORD dwBytesReturned;

PortStruct.bSize = bSize;
PortStruct.dwPortVal = dwPortVal;
PortStruct.wPortAddr = wPortAddr;

return DeviceIoControl(hDriver, IOCTL_WINIO_WRITEPORT, &PortStruct, sizeof(PortStruct),
NULL, 0, &dwBytesReturned, NULL);
}

#endif

return true;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: