很早以前写了一个刷卡程序,功能是定时监控读卡器,当发现有IC卡放到读卡器上后,自动识别出卡号,然后带着这个卡号搜索一个英文用户名和卡号的对照表,最后把英文用户名直接自动输入到当前光标所在的位置。本来程序一直用得好好的,可是最近遇到了一个新问题——因为用户名现在居然可以用中文了!所以这下麻烦大了……

原先实现英文的自动输入,用的是keybd_event函数,直接模拟键盘事件。但是要输入中文,貌似没有输入法还是不行,难道还要我先用keybd_event调出输入法,然后输入拼音?这个思路想想就很恐怖,所以赶紧就上网搜解决方案去了。可是搜了一圈下来,只有寥寥几篇提到解决方案,虽然网上搜索结果众多,但是基本上就是这几个版本贴来贴去,浪费了我好多时间。

不幸的事情还在后头,虽然有人提到SendInput函数可以输入中文,但是语焉不详,按照他提供的点滴的代码,我死活就是没有试出来。所以最后中文搜索的结果,除了认识了这个SendInput函数之外,没有更多的收获。后来不死心,换了英文搜索,还真找到了一个比较接近我需求的,老外写的VB版本的SendInput的例子,试验了以下,果然可以输入中文。大喜之下,决定花点时间研究一下人家的源代码,然后写一个VC的版本。

摸索了两天之后,发现实现中文自动输入还真不难,因为SendInput确实支持,所以终于可以不用输入法了,万幸。特意整理了几个函数,共享一下。

首先是,头文件必须包含以下两个:
#include <winable.h>
#include <atlconv.h>

前者是SendInput函数要用到,后者是字符串转换的时候要用到。

void SendAscii(wchar_t data, BOOL shift)
{
 INPUT input[2];
 memset(input, 0, 2 * sizeof(INPUT));
 
 if (shift)
 {
   input[0].type = INPUT_KEYBOARD;
   input[0].ki.wVk = VK_SHIFT;
   SendInput(1, input, sizeof(INPUT));
 }

input[0].type = INPUT_KEYBOARD;
 input[0].ki.wVk = data;

input[1].type = INPUT_KEYBOARD;
 input[1].ki.wVk = data;
 input[1].ki.dwFlags = KEYEVENTF_KEYUP;

SendInput(2, input, sizeof(INPUT));

if (shift)
 {
   input[0].type = INPUT_KEYBOARD;
   input[0].ki.wVk = VK_SHIFT;
   input[0].ki.dwFlags = KEYEVENTF_KEYUP;
   SendInput(1, input, sizeof(INPUT));  
 }
}

void SendUnicode(wchar_t data)
{
 INPUT input[2];
 memset(input, 0, 2 * sizeof(INPUT));
 
 input[0].type = INPUT_KEYBOARD;
 input[0].ki.wVk = 0;
 input[0].ki.wScan = data;
 input[0].ki.dwFlags = 0x4;//KEYEVENTF_UNICODE;
 
 input[1].type = INPUT_KEYBOARD;
 input[1].ki.wVk = 0;
 input[1].ki.wScan = data;
 input[1].ki.dwFlags = KEYEVENTF_KEYUP | 0x4;//KEYEVENTF_UNICODE;
 
 SendInput(2, input, sizeof(INPUT));
}

//为方便使用,下面这个函数包装了前两个函数。

void SendKeys(CString msg)
{
 short vk;
 BOOL shift;

USES_CONVERSION;
 wchar_t* data = T2W(msg.GetBuffer(0));
 int len = wcslen(data);

for(int i=0;i<len;i++)
 {
   if (data[i]>=0 && data[i]<256) //ascii字符
   {
     vk = VkKeyScanW(data[i]);

if (vk == -1)
     {
       SendUnicode(data[i]);
     }
     else
     {
       if (vk < 0)
       {
         vk = ~vk + 0x1;
       }
       
       shift = vk >> 8 & 0x1;
       
       if (GetKeyState(VK_CAPITAL) & 0x1)
       {
         if (data[i]>='a' && data[i]<='z' || data[i]>='A' && data[i]<='Z')
         {
           shift = !shift;
         }
       }

SendAscii(vk & 0xFF, shift);
     }
   }
   else //unicode字符
   {
     SendUnicode(data[i]);
   }
 }
}

直接调用SendKeys函数就可以在当前光标的位置自动输入指定的字符串,下面的例子演示了如何自动打开记事本程序并输入一段话:
void CSendInputDlg::OnTest()
{
 ShellExecute(NULL, NULL, "notepad.exe", NULL, NULL, SW_SHOWNORMAL);
 
 Sleep(500); //为了确保记事本程序打开完毕,稍等片刻

CWnd *pWnd = FindWindow(NULL, "无标题 - 记事本");
 if (pWnd)
 {
   pWnd->SetForegroundWindow();
   SendKeys("我是sway,我爱中国!\nI love China!\nEmail: \b\b");
 }
}

在VC中使用SendInput函数实现中文的自动输入的更多相关文章

  1. VC++中的延时函数

    原文链接:http://www.educity.cn/develop/478947.html VC中提供了很多关于时间操作的函数,编写程序时我们可以跟据定时的不同精度要求选择不同的时间函数来完成定时和 ...

  2. 解决 openSUSE 中 Sublime Text 3 的中文显示和输入问题

    测试环境 系统版本:openSUSE Leap 42.2 桌面环境:KDE Plasma 5输入法:fcitx-rime (中州韵) 见周围用 Windows 和 macOS 的小伙伴几乎都在用简单强 ...

  3. VC中常见API函数使用方法(经验版)

    ***********************************************声明*************************************************** ...

  4. VC中基于 Windows 的精确定时[转]

    在工业生产控制系统中,有许多需要定时完成的操作,如定时显示当前时间,定时刷新屏幕上的进度条,上位 机定时向下位机发送命令和传送数据等.特别是在对控制性能要求较高的实时控制系统和数据采集系统中,就更需要 ...

  5. VC中基于 Windows 的精确定时

    在工业生产控制系统中,有许多需要定时完成的操作,如定时显示当前时间,定时刷新屏幕上的进度条,上位 机定时向下位机发送命令和传送数据等.特别是在对控制性能要求较高的实时控制系统和数据采集系统中,就更需要 ...

  6. python中的zip()函数和map()函数

    一.zip()函数 1.语法: zip(iterable, ...) 参数说明: iterable,...-- 一个或多个迭代器; 在python2中: zip() 函数用于将可迭代的对象作为参数,将 ...

  7. 【thrift】vc中使用thrift中文字符串乱码问题解决

    问题描述: VC中使用Apache thrift时,如果字符串中包含中文,会出现乱码问题,这个问题的原因是由于thrift为了达到跨语言交互而使用了UTF-8格式发送字符串,这点对java或者C#不会 ...

  8. VC中实现GCC的2个比较常用的位运算函数

    在GCC中内嵌了两个位运算的函数,但在VC中并没有这两个函数(有相似函数). //返回前导的0的个数. int __builtin_clz (unsigned int x) //返回后面的0个个数,和 ...

  9. 如何在VC中查询中文,及QT5的中文处理

    1,VC中查询所有含中文字符串 使用正则表达式,查询内容为: (".*[\u4E00-\u9FA5]+)|([\u4E00-\u9FA5]+.*") 这样,就可以把代码中的中文都查 ...

随机推荐

  1. mount过程分析之一(基于3.16.3内核)【转】

    转自:https://blog.csdn.net/zr_lang/article/details/39963253 一直想写有些关于文件系统的博文,但是由于近一年来实在太忙,所以没有时间写.前几日赶上 ...

  2. MySQL 5.7在线设置复制过滤【转】

    转自 MySQL 5.7在线设置复制过滤 - yayun - 博客园 https://www.cnblogs.com/gomysql/p/4991197.html 5.7也GA了,有许多新的特性,其中 ...

  3. Ansible 插件 之 【CMDB】【转】

    Github地址: https://github.com/fboender/ansible-cmdb 从facts收集信息,生成主机概述 安装 wget https://github.com/fboe ...

  4. 【译】ASP.NET Identity Core 从零开始

    原文出自Rui Figueiredo的博客,原文链接<ASP.NET Identity Core From Scratch> 译者注:这篇博文发布时正值Asp.Net Core 1.1 时 ...

  5. C# 特性(Attribute)详细介绍

    1.什么是Atrribute 首先,我们肯定Attribute是一个类,下面是msdn文档对它的描述:公共语言运行时允许你添加类似关键字的描述声明,叫做attributes, 它对程序中的元素进行标注 ...

  6. JVM(3)对象A和B循环引用,最后会不会不被GC回收?-------关于Java的GC机制

    ①首先说一下,GC里边在JVM其中是使用的ROOT算法,ROOT算法,什么称作为ROOT呢,就是说类的静态成员,静态成员就是static修饰的那种,是"根"的一个,根还包含方法中的 ...

  7. Ubuntu+Nginx+uWSGI+Flask应用

    Ubuntu 18.04,Nginx 1.14.0,uWSGI 2.0.17.1,Flask 1.0.2,Python 3.6.5, 多日未更新博客,就是在忙着把自己的Flask应用在Ubuntu上运 ...

  8. Java 抽象类和抽象方法

    包含抽象方法的类叫抽象类,如果一个类中包含一个或多个抽象方法,该类必须被限定为抽象的,否则编译器会报错,抽象类不可创建对象,创建抽象类的对象编译器会报错 如果从一个抽象类继承,并想创建该新类的对象,那 ...

  9. spfa学习笔记

    序 spfa它死了 --by 大佬 但是本蒟蒻还是一如既往的使用spfa... 因为太弱了,其他什么都不会.于是就疯狂开O2跪倒在spfa上. 例题--汽车加油行驶问题 loj跳转链接 luogu跳转 ...

  10. hdu 1698 线段树(成段替换 区间求和)

    一条钩子由许多小钩子组成 更新一段小钩子 变成铜银金 价值分别变成1 2 3 输出最后的总价值 Sample Input11021 5 25 9 3 Sample OutputCase 1: The ...