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

如果只要求支持ASCII吗,那就轻而易举了,直接监听WM_CHARFor 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. Git 操作指南

    http://blog.csdn.net/troy__/article/details/40082657

  2. [转载]ASP.NET Error – Adding the specified count to the semaphore would cause it to exceed its maximum count

    http://jwcooney.com/2012/08/13/asp-net-error-adding-the-specified-count-to-the-semaphore-would-cause ...

  3. ASP.NET中最简单的自定义控件

    ASP.NET用户控件一般适用于产生相对静态的内容,所以没有builtin的事件支持.本文讨论用户控件返回事件的方法.          假定用户控件(UserControl.ascx)中包含按钮控件 ...

  4. 用原生js对表格排序

    阿里的模拟笔试题,当时时间有限没写出来,其实是因为自己对原生dom操作不熟悉,这里补一下. 题目的大意是有一个表格,如代码所示 <table> <tr> <th>N ...

  5. 修改input placeholder样式

    <style> /* 通用 */ ::-webkit-input-placeholder { color: rgb(235, 126, 107); } ::-moz-placeholder ...

  6. 扩展欧几里得(E - The Balance POJ - 2142 )

    题目链接:https://cn.vjudge.net/contest/276376#problem/E 题目大意:给你n,m,k,n,m代表当前由于无限个质量为n,m的砝码.然后当前有一个秤,你可以通 ...

  7. Spring Boot 多模块项目创建与配置 (一)

    最近在负责的是一个比较复杂项目,模块很多,代码中的二级模块就有9个,部分二级模块下面还分了多个模块.代码中的多模块是用maven管理的,每个模块都使用spring boot框架.之前有零零散散学过一些 ...

  8. WEBAPI 帖子收藏

    [翻译]ASP.NET Web API入门 [翻译]ASP.NET WEB API异常处理 ASP.NET WebAPI 路由规则与POST数据 ASP.NET Web API路由规则(二) ASP. ...

  9. 源码安装svn 1.8.9

    2014年5月25日 12:26:14 需要文件: svn apr apr-util sqlite3 serf svn : http://subversion.apache.org/download/ ...

  10. 数组用console.log输出

    输出的时候,如果前面有字符串,那么输出的就是整个字符串