文本输入框作为一个最基本的UI控件,被众多UI框架默认支持。Windows下最简单的就是CEdit(WTL封装),也有更为复杂的CRichEdit(WTL封装)。文本输入框是基本控件中最难实现的控件之一,估计这也是Chrome浏览器(For Windows)一直使用原生文本输入框封装,而不是自行实现的原因。很多情况下,默认的输入框足够使用,对于一些简单的限制(例如只能输入数字)也可以通过对原生控件进一步封装实现。不过如果要深度定制就估计只有自行实现了。

如果只要求支持ASCII吗,那就轻而易举了,直接监听WM_CHAR(For Windows)消息即可。不过这个世界语言太多了,作为一个红朝子民,至少得支持汉语吧!可是汉语并不能通过监听WM_CHAR获得。所以下面就来探讨一下Windows操作系统下中文的输入。

目前主流操作系统都是默认支持ASCII输入,而对于其他语言的输入则必须借助输入法来实现。为了支持多语言输入,主流的UI框架都会集成输入法嵌入的支持模块,而对输入法的友好程度也反映了该UI框架的水平。估计很多Linux用户(Gnome环境)以前会很烦在用QT实现的Opera浏览器中用输入法。

Windows的输入框架在这里(http://blog.csdn.net/dengting/archive/2002/08/17/14638.aspx )讲的比较详细,对于其他语言的输入,Windows并不是通过WM_CHAR消息传递,而是通过输入法发出的WM_IME_CHAR消息提供,所以我们可以监听这个消息来获得相应的汉字。不过在发送WM_IME_CHAR消息之前,Windows会先发送WM_IME_COMPOSITION消息。大概流程如下:

  1. 用户按下键盘,Windows发送WM_CHAR

  2. 如果当前使用输入法输入,则让输入法重组,获得第三方语言字符(串)

  3. 输入法发送WM_IME_COMPOSITION、WM_IME_CHAR等消息。UI控件截取这些消息,获得汉字。

Windows并不会同时发送WM_IME_COMPOSITION、WM_IME_CHAR和WM_CHAR消息,而是依次发送。首先会发送WM_IME_COMPOSITION消息,UI控件可以通过ImmGetCompositionString函数获得输入的字符串。如果希望继续发送后续消息,则调用Windows默认的处理函数。此时Windows会接着发送WM_IME_CHAR消息,UI控件可以通过它的参数获得单个中文字符,如果希望继续发送后续消息,则调用Windows默认的处理函数。此时Windows会接着发送WM_CHAR消息。很显然,只有经的上层同意,Windows才会发送后续的消息。

既然对于ASCII输入和中文输入需要监听不同的事件,那就必须有一个办法判断用户当前是使用英文键盘还是使用输入法输入。这可以通过Windows API函数ImmIsIME判断。此外关于中英文切换摘录了一段如下:

【http://topic.csdn.net/t/20020509/02/707135.html 】

中英文输入法切换?    
function   boolean   ImmSimulateHotKey   (UnsignedLong   hWnd,   
UnsingedLong   dwHotKeyID)   library   “IMM32.dll“   
function   unsignedlong   GetKeyboardLayout   (unsignedlongwLayout)library   “user32.dll“   
function   boolean   ImmIsIME(unsignedLong   hklKeyboardLayout)library   “IMM32.DLL“

英文输入法切换

constant int IME_THotKey_IME_NonIME_Toggle=112uint hklCurrentunsignedlong hnd hklCurrent = GetKeyboardLayout(0)if ImmIsIME(hklCurrent) then hnd = Handle(parent) ImmSimulateHotKey(hnd,IME_THotKey_IME_NonIME_Toggle)end if

中文输入法切换

constant int IME_THotKey_IME_NonIME_Toggle=112uint hklCurrentunsignedlong hnd hklCurrent = GetKeyboardLayout(0)if not ImmIsIME(hklCurrent) then hnd = Handle(parent) ImmSimulateHotKey(hnd,IME_THotKey_IME_NonIME_Toggle)end if

写了一个sample练练笔(WTL实现),有兴趣可以瞄瞄,有什么错误欢迎指正。支持ascii和unicode,不过只支持ascii可见字符、汉字和退格键,没有实现光标,方向键等。此外该sample同时处理了WM_IME_COMPOSITION消息和WM_IME_CHAR消息,所以用户输入一个汉字串后会显示两个相同的,实际应用应该选择其中之一。考虑到ascii方式汉字占用字节和英文字符不一样,所以退格键需要特殊处理,见源码。

使用方式示例:

InputStatic istatic_istatic_.Create(m_hWnd,CRect(0,250,500,400),NULL,WS_CHILD | WS_VISIBLE);istatic_.SetFocus();

之所以要SetFocus,是因为sample使用CStatic,该控件无法获得焦点。(注意:该sample仅仅只是一个测试代码,不要拿来和真正文本输入框对比)

(InputStatic.h)

/** Author: 邱金武<qiujinwu456@gmail.com>*/#ifndef INPUT_STATIC__H_#define INPUT_STATIC__H_#include <string>#include <atlbase.h>#include "atlapp.h"#include <atlwin.h>#include "atlctrls.h"#ifndef _UNICODEtypedef std::string ISString;#elsetypedef std::wstring ISString;#endifclass InputStatic: public CWindowImpl< InputStatic ,CStatic>{public: InputStatic(const ISString & initStr = _T("")); BEGIN_MSG_MAP( NormalButton ) MESSAGE_HANDLER(WM_CHAR, OnChar) MESSAGE_HANDLER(WM_IME_CHAR, OnImeChar) MESSAGE_HANDLER(WM_IME_COMPOSITION, OnImeCompositionChar) END_MSG_MAP()private: LRESULT OnChar(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled); LRESULT OnImeChar(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled); LRESULT OnImeCompositionChar(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/,BOOL& bHandled); ISString m_content_;};#endif

(InputStatic.cpp)

/** Author: 邱金武<qiujinwu456@gmail.com>*/#include "InputStatic.h"#ifndef _UNICODE//见: http://blog.chinaunix.net/u2/70445/showart_1133335.htmlstatic bool endWithGBCode(const std::string & strIn){ unsigned char ch1; unsigned char ch2; if (strIn.size() >= 2) { ch1 = (unsigned char)strIn.at(strIn.size() - 1); ch2 = (unsigned char)strIn.at(strIn.size() - 2);#ifdef USE_GB2312 //GB2312 if (ch1>=176 && ch1<=247 && ch2>=160 && ch2<=254)#else //GBK if (ch1>=129 && ch1<=254 && ch2>=64 && ch2<=254)#endif return true; else return false; } else return false;}#endifInputStatic::InputStatic(const ISString & initStr): m_content_(initStr){}LRESULT InputStatic::OnChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled){ //处理可显示ascii字符 if(wParam >= ' ' && wParam <= '~') { this->m_content_ += wParam; this->SetWindowText(this->m_content_.c_str()); } //处理退格键 else if(VK_BACK == wParam) { if(!m_content_.empty()) {#ifndef _UNICODE //考虑到ansi方式中文字符和ascii具有不同的长度,所以这里需要特殊处理 if(endWithGBCode(m_content_)) m_content_ = m_content_.substr(0,m_content_.size() - 2); else m_content_ = m_content_.substr(0,m_content_.size() - 1);#else m_content_ = m_content_.substr(0,m_content_.size() - 1);#endif this->SetWindowText(m_content_.c_str()); } } return 1;}LRESULT InputStatic::OnImeCompositionChar(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/,BOOL& bHandled){ //继续发送消息,否则收不到WM_IME_CHAR消息 bHandled = FALSE; HIMC hImc; DWORD dwSize; TCHAR *Buf; hImc = ImmGetContext(GetActiveWindow()); dwSize = ImmGetCompositionString(hImc, GCS_RESULTSTR, NULL, 0); if(dwSize) { Buf = reinterpret_cast<TCHAR*>(new char[dwSize + sizeof(TCHAR)]); memset(Buf,0,dwSize + sizeof(TCHAR)); ImmGetCompositionString(hImc, GCS_RESULTSTR, (LPVOID)Buf, dwSize); this->m_content_ += Buf; delete [] Buf; this->SetWindowText(m_content_.c_str()); } ImmReleaseContext(GetActiveWindow(), hImc); return 1;}LRESULT InputStatic::OnImeChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled){ //继续发送消息,否则收不到WM_CHAR消息 bHandled = FALSE;#ifndef _UNICODE char imeChar[3]; imeChar[0] = (char)(wParam>>8); imeChar[1] = (char)wParam; imeChar[2] = '\0';#else wchar_t imeChar = wParam;#endif this->m_content_ += imeChar; this->SetWindowText(m_content_.c_str()); return 1;}

如果需要做类似密码输入框的处理,不管使用什么输入法,总之只接收英文字符。此时可以将WM_IME_COMPOSITION、WM_IME_CHAR消息的处理函数留空,并使用Windows默认的处理函数。

原文地址:http://www.qiujinwu.com/ui/windows%E4%B8%AD%E6%96%87%E8%BE%93%E5%85%A5/

【转载】VC IME 通信的更多相关文章

  1. 转载 VC 2010下安装OpenCV2.4.4

    说明: 1.安装平台:32位XP,VS2010: 2.OpenCV 2.4.4不支持VC 6.0: 3.网上有很多用CMake编译OpenCV的安装教程,这里建议先不要自己编译,如果使用预编译好的库有 ...

  2. 转载 VC轻松解析XML文件 - CMarkup类的使用方法

    VC轻松解析XML文件 - CMarkup类的使用方法http://www.cctry.com/thread-3866-1-1.html VC解析XML文件的工具有很多,CMarkup, tinyXM ...

  3. VC 串口通信类

    为了节省时间,我就贴出来吧 头文件 SerialPort.h /******************************************************************** ...

  4. VC com 通信实例

    HANDLE hCom;//全局變量串口句柄 COMMTIMEOUTS TimeOuts; DCB dcb; 按鈕代碼() { hCom=CreateFile(L“COM1”,// 串口名稱 GENE ...

  5. 【转载】socket通信-C#实现tcp收发字符串文本数据

    在日常碰到的项目中,有些场景需要发送文本数据,也就是字符串,比如简单的聊天文字,JSON字符串等场景.那么如何如何使用SharpSocket来收发此类数据呢?其中要掌握的关键点是什么呢? 点击查看原博 ...

  6. (转载)用vs2010开发基于VC++的MFC 串口通信一*****两台电脑同一个串口号之间的通信

    此文章以visual C++数据採集与串口通信測控应用实战为參考教程 此文章适合VC++串口通信入门 一.页面布局及加入控件 1, 安装好vs2010如图 2, 新建一个基于VC++的MFC项目com ...

  7. VC++使用socket进行TCP、UDP通信实例总结

    1.        两台计算机通信需要协议,通信的两台计算机IP必须唯一 2.        同一个计算机可以进行多个应用程序与其他计算机通信,IP地址唯一,而端口号是区别同一计算机(同一IP)的唯一 ...

  8. 一个由印度人编写的VC串口类

    http://www.cnblogs.com/lwngreat/p/4098374.html 软件介绍 一个由印度人编写的VC串口类(也是一种VC串口控件),他还配合这个类写了VC 串口通信方面的一些 ...

  9. [转]Web 通信 之 长连接、长轮询(long polling)

    本篇文章转载自Web 通信之长连接.长轮询(longpolling),版权归作者所有. 转者按:随着技术的发展,在HTML5中,可以通过WebSocket技术来完成长连接的开发,虽然如此,本文依然存在 ...

随机推荐

  1. 使用JavaScript缓存图片

    在JS中,为了让图片缓存起来,客户端JS定义了一个API,首先利用Image()构造函数来创建一个屏幕外图片对象,之后将该对象的src属性设置 期望的URL,由于图片元素并没有添加到文档中,因此它是不 ...

  2. ASP.net学习总结

    学习ASP.net又一次接触了B/S开发.下面先通过一张图对ASP.net有一个宏观结构的总结.之后将详细介绍ASP.net中的六大对象. 1.Request从客户端得到数据,包括基于表单的数据和通过 ...

  3. J2EE的体系结构是指什么?

    J2EE 即Java2平台企业版,它提供了基于组件的方式来设计.开发.组装和部署企业应用.J2EE使用多层分布式的应用模型,这个多层通常通过三层或四层来实现: 客户层,运行在客户计算机上的组件. We ...

  4. Jenkins的安装及使用(一)

    操作环境:Windows7 一.环境准备 1 安装JDK 本文采用jdk-8u111-windows-x64.exe: 安装完成后配置环境变量. 2 配置tomcat 本文采用tomcat8,免安装版 ...

  5. Java并发——线程同步Volatile与Synchronized详解

    0. 前言 转载请注明出处:http://blog.csdn.net/seu_calvin/article/details/52370068 面试时很可能遇到这样一个问题:使用volatile修饰in ...

  6. 「Android 开发」入门笔记

    「Android 开发」入门笔记(界面编程篇) ------每日摘要------ DAY-1: 学习笔记: Android应用结构分析 界面编程与视图(View)组件 布局管理器 问题整理: Andr ...

  7. PyTorch学习系列(九)——参数_初始化

    from:http://blog.csdn.net/VictoriaW/article/details/72872036 之前我学习了神经网络中权值初始化的方法 那么如何在pytorch里实现呢. P ...

  8. Windows命令-系统木马取样

    1.前言 工作中偶尔会遇到去现场提取木马样本回公司分析的情况.如果是生产环境下,不方便安装各类抓包.安全软件时.能用系统自带的命令去定位出木马程序相关的信息是最理想不过的状态. 2.Windows常用 ...

  9. CMD常用命令(一)

    常用命令大全 net>user heibai lovechina /add 加一个heibai的用户密码为lovechina net>localgroup Administrators h ...

  10. mycat学习笔记

    MyCAT简易入门_数据库技术_Linux公社-Linux系统门户网站http://www.linuxidc.com/Linux/2016-01/127382.htm mycat读写分离配置 - PE ...