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


    基于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 "..drvwinio_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;
    }

  • 相关阅读:
    使用libgdx及其中的box2d 2.1的注意事项
    Android.mk file syntax specification(ndkr8)
    NDK Note
    Problems of Android NDK
    Android.mk of NDK
    Android IM Note
    Regular Expression
    Some Efficient Algorithms
    libgdx use TexturePacker
    The Conversion Of JNI
  • 原文地址:https://www.cnblogs.com/honeynm/p/4096456.html
Copyright © 2020-2023  润新知