【转载】VC IME 通信
文本输入框作为一个最基本的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消息。大概流程如下:
用户按下键盘,Windows发送WM_CHAR
如果当前使用输入法输入,则让输入法重组,获得第三方语言字符(串)
输入法发送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 通信的更多相关文章
- 转载 VC 2010下安装OpenCV2.4.4
说明: 1.安装平台:32位XP,VS2010: 2.OpenCV 2.4.4不支持VC 6.0: 3.网上有很多用CMake编译OpenCV的安装教程,这里建议先不要自己编译,如果使用预编译好的库有 ...
- 转载 VC轻松解析XML文件 - CMarkup类的使用方法
VC轻松解析XML文件 - CMarkup类的使用方法http://www.cctry.com/thread-3866-1-1.html VC解析XML文件的工具有很多,CMarkup, tinyXM ...
- VC 串口通信类
为了节省时间,我就贴出来吧 头文件 SerialPort.h /******************************************************************** ...
- VC com 通信实例
HANDLE hCom;//全局變量串口句柄 COMMTIMEOUTS TimeOuts; DCB dcb; 按鈕代碼() { hCom=CreateFile(L“COM1”,// 串口名稱 GENE ...
- 【转载】socket通信-C#实现tcp收发字符串文本数据
在日常碰到的项目中,有些场景需要发送文本数据,也就是字符串,比如简单的聊天文字,JSON字符串等场景.那么如何如何使用SharpSocket来收发此类数据呢?其中要掌握的关键点是什么呢? 点击查看原博 ...
- (转载)用vs2010开发基于VC++的MFC 串口通信一*****两台电脑同一个串口号之间的通信
此文章以visual C++数据採集与串口通信測控应用实战为參考教程 此文章适合VC++串口通信入门 一.页面布局及加入控件 1, 安装好vs2010如图 2, 新建一个基于VC++的MFC项目com ...
- VC++使用socket进行TCP、UDP通信实例总结
1. 两台计算机通信需要协议,通信的两台计算机IP必须唯一 2. 同一个计算机可以进行多个应用程序与其他计算机通信,IP地址唯一,而端口号是区别同一计算机(同一IP)的唯一 ...
- 一个由印度人编写的VC串口类
http://www.cnblogs.com/lwngreat/p/4098374.html 软件介绍 一个由印度人编写的VC串口类(也是一种VC串口控件),他还配合这个类写了VC 串口通信方面的一些 ...
- [转]Web 通信 之 长连接、长轮询(long polling)
本篇文章转载自Web 通信之长连接.长轮询(longpolling),版权归作者所有. 转者按:随着技术的发展,在HTML5中,可以通过WebSocket技术来完成长连接的开发,虽然如此,本文依然存在 ...
随机推荐
- Codeforces #55D-Beautiful numbers (数位dp)
D. Beautiful numbers time limit per test 4 seconds memory limit per test 256 megabytes input standar ...
- [转]CSS浏览器兼容问题总结
E6.0,ie7.0与Firefox的CSS兼容性问题1.DOCTYPE 影响 CSS 处理 2.FF: div 设置 margin-left, margin-right 为 auto 时已经居中, ...
- 【转】XMPP_3920_最靠谱的中文翻译文档
CHENYILONG Blog XMPP_3920_最靠谱的中文翻译文档 Fullscreen © chenyilong. Powered by Postach.io Blog
- NIO学习(1)-入门学习
一.NIO概念 IO:标准IO,也既阻塞式IO NIO:非阻塞式IO 二.NIO与标准IO的IO工作方式 标准IO基于字节流和字符流进行操作 NIO是基于通道(Channel)和缓冲区(Buffer) ...
- tf.range()函数
range()函数用于创建数字序列变量,有以下两种形式: range(limit, delta=1, dtype=None, name='range') range(start, limit, del ...
- 20165230 《Java程序设计》实验五《网络编程与安全》实验报告
20165230 <Java程序设计>实验五<网络编程与安全>实验报告 一.实验报告封面 课程:Java程序设计 班级:1652班 姓名:田坤烨 学号:20165230 成绩: ...
- PWN入门
pwn ”Pwn”是一个黑客语法的俚语词 ,是指攻破设备或者系统 .发音类似“砰”,对黑客而言,这就是成功实施黑客攻击的声音——砰的一声,被“黑”的电脑或手机就被你操纵.以上是从百度百科上面抄的简介, ...
- Twisted框架
Twisted是一个事件驱动型的网络模型.时间驱动模型编程是一种范式,这里程序的执行流由外部决定.特点是:包含一个事件循环,当外部事件发生时,使用回调机制来触发相应的处理. 线程模式: 1.单线程同步 ...
- 公共语言运行库(CLR)开发系列课程(3):COM Interop基础 学习笔记
上章地址 什么是COM Component Object Model 组建对象模型 基于接口(Interface) 接口=协议 IID 标识接口 V-table 虚表 方式调用 单继承 对象(Obje ...
- 二、vue中组件的使用
1.组件拆分 1.组件实质上也是一个vue实例,因此组件中也可以使用vue的对象属性,反过来每一个vue实例也是一个vue组件(注:1.唯一不同的是el是根实例的特有选项,2.组件中的data必须是一 ...