mfc程序向焦点的输入

最近做一个手机控制电脑的项目需要实现向当前焦点输入字符的功能,查了好久终于完成了,记录下过程以备不时之需。

首先我得思路是模拟键盘输入的模式,这个方法实现起来很简单直接调用函数keybd_event即可。keybd_event函数有四个参数,第一个参数是windows的虚拟键盘值,在msdn里有详细说明,这里说些常用的以及注意事项,数字的虚拟键盘值即是对应的ascii码,小写字母的虚拟键值是大写字母的对应的ascii码,想要直接输入大写字母不可能,必须先使用CAPSLOCK键切换大写,再按照输入小写字母的方式输入,然后别忘了切回来。回车,空格等虚拟键盘值网上都有,键盘里逗号,分号,括号等键键值是VK_OEM_1-VK_OEM_7.第二个参数不常用,置0,地三个参数按键状态,0按下,KEYEVENTF_KEYUP按键弹起,跟咱们手动输入字母是一样的,最后一个置零,实现输入0:

keybd_event(‘0’, 0, 0 ,0);
keybd_event(‘0’, 0, KEYEVENTF_KEYUP ,0);

这么做看起来很简单但是有很大的隐患,我换了台电脑发现输入英文的时候它它由于当前的输入法是搜狗而不是默认的输入法,导致了英文没输进去而是输了一堆乱七八糟的汉字,所以使用这种方法输入英文必须要使当前输入法为英文输入状态,而且第二个问题也随之而来,输入中文怎么办,如果每次输入都要切换输入法状态就太麻烦,要命的是你不知道当输入中文的时候应该切换到哪个输入法(有搜狗我相信没有人愿意使用智能abc),后来想个办法把windows的软键盘调出来(osk.exe),但是客户不希望完全使用鼠标来代替键盘的操作,希望有键盘操作的过程,所以说这个思路不可行。

还有个思路使用GetForegroundWindow()函数可以得到系统的当前窗口的句柄,所以就这么干:

HWND hWnd;
hWnd = ::GetForegroundWindow();

::SetWindowTextA(hWnd, "sad"); //输入sad

结果我把那个程序的标题名字给改了,并没有实现在焦点处输入的功能,尴尬。

自然而然想到我获得的仅仅是整个程序的句柄,但是我们输入的方向却是当前焦点,所以使用::GetFocus()函数,获取输入的焦点的句柄,不过还是有问题,我只把我自己的应用程序里的一个控件名称改了,焦点处还没变。仔细看下msdn,上面清清楚楚写着使用GetForegroundWindow()函数获得当前窗口句柄,后面一句话很诡异,You can associate your thread’s message queue with the windows owned by another thread by using the AttachThreadInput function. 翻译过来大意就是你可以使用AttachThreadInput()函数将当前程序线程的消息队列和系统中其他的线程拥有的消息联系起来,真是服了都不说人话,百度了下查到原因,实际上GetFocus函数只能获得当前程序的输入焦点,想要获取其他程序的输入焦点必须将执行当前系统输入焦点的程序的线程和你自己的线程使用绑AttachThreadInput函数进行绑定。

HWND hWnd;
hWnd = ::GetForegroundWindow(); // 得到当前窗口 
DWORD FormThreadID = GetCurrentThreadId(); //本程序的线程id
DWORD CWndThreadID = GetWindowThreadProcessId(hWnd, NULL); //系统当前的程序线程
AttachThreadInput(CWndThreadID, FormThreadID, true);  //绑定
hWnd = ::GetFocus(); // 得到当前键盘光标所在的窗口 
AttachThreadInput(CWndThreadID, FormThreadID, false); // 取消 

这个时候可以使用PostMessage()发送消息,当然SendMessage()也一样,

for(int i = 0; i < strl; i ++)//strl是你要输入的字符长度

::PostMessage(hWnd, WM_CHAR, (WPARAM)buf[ i], NULL);

果然英文可以实现。接下来是输入中文。

由于是手机端向pc输入,所以手机端输入的汉字会经过utf-8编码,如果汉字也按照这么现实的话后果就是一个汉字都没有,全是乱七八糟的符号,因为程序不知道你是不是汉字,他会当作字母照常显示,网上说得将buf和0xff做一个与的运算,试了下倒是能显示汉字了,不过字不对。

然后我发现了个问题,传过来的一个汉字是3字节,我这边一个汉字仅需要两个字节就能显示,仔细想了下突然想到由于我要兼容大量的c代码,所以没有使用Unicod字符集而是使用多字节的字符集,所以得实现字符转化:

//utf-6转Unicode

DWORD dwUnicodeLen;        //转换后Unicode的长度
TCHAR *pwText;            //保存Unicode的指针
dwUnicodeLen = MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,kk,-1,NULL,0); //计算长度,注意第二个参数和倒数第二个参数
pwText = new TCHAR[dwUnicodeLen];

memset(pwText, 0, dwUnicodeLen * 2 + 2); //Unicode是两个字节表示一个字符

//Unicode转多字节

int slen = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)pwText, -1, NULL, 0, NULL, NULL);
char *szANSI=new char[slen + 1]; 
memset(szANSI, 0, slen + 1);
WideCharToMultiByte (CP_ACP, 0, (LPWSTR)pwText, -1, szANSI, slen, NULL,NULL);

然后就可以发消息了,我用的是vs2010,细心的童鞋会注意SendMessage后面有A或者W,A对应的是多字节,W对应的是Unicode,这里果断是SendMessageA,而且多字节只能一个一个字节发,并且每个字符要与0xff:

for(int i = 0; i < slen; i ++)
::SendMessageA(hWnd, WM_CHAR, (WPARAM)(szANSI[i] & 0xff), NULL);

至此整个功能得以实现。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值