【转载】VC IME 通信

文本输入框作为一个最基本的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: 邱金武<[email protected]>*/#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: 邱金武<[email protected]>*/#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 通信,码迷,mamicode.com

时间: 2024-08-04 00:57:41

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

转载:C#:Socket通信

原文地址:http://www.cnblogs.com/s380774061/archive/2012/10/15/2725297.html 之前一直想自己搞把C#的Socket代码,一直没有下手,今晚终于实践了一把.现把流程编写出来,以备后用. 很简单的源码. 工具:Vs2010 建立项目:C# 控制台应用程序 Server代码 using System; using System.Collections.Generic; using System.Linq; using System.Tex

VC++串口通信编程详解

总结来看串口通信原理,(也可以说大多数通信原理也是如此). 通信首先要有个通信,可以简单的把通信看成一个小桶,发送方住水桶里装水,接收方从水桶中取水.如果你要和对方通信首先需要将桶盖打开,再将水装入到桶中,这时接收方才能够从桶中取到水.这里就存在着一定的问题, 1,如果桶盖还没有打开,发送方已经发送了.这时接收方再从桶中取水,肯定取的水不对,会不一部分缺失了.解决方式就是让桶盖打开再往其中加水. 2,但是桶盖何时打开,发送方何时发送,这个不好把握.解决方法:接收方接到数据时,要返回一个应答标志,

VC 串口通信类

为了节省时间,我就贴出来吧 头文件 SerialPort.h 1 /*************************************************************************************************** 2 * SerialPort.h 3 * 4 * 功 能:串口通讯类 5 * 类 名:CSerialPort 6 * 7 * Ver 变更日期 负责人 变更内容 8 * ───────────────────────────────

VC com 通信实例

HANDLE hCom;//全局變量串口句柄 COMMTIMEOUTS TimeOuts; DCB dcb; 按鈕代碼() { hCom=CreateFile(L“COM1”,// 串口名稱 GENERIC_READ|GENERIC_WRITE,//允许读和写 0,//独占方式 NULL, OPEN_EXISTING,// 打开而不是创建 0,//同步方式 NULL); ///////////////////////////////////////////////////////////////

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

此文章以visual C++数据採集与串口通信測控应用实战为參考教程 此文章适合VC++串口通信入门 一.页面布局及加入控件 1, 安装好vs2010如图 2, 新建一个基于VC++的MFC项目comm 注意:点击ok,然后next,这时候要将application type改成dialog base.接着next到最后一个对话框是将generated dasses改成CcommDlg,然后finish 4, 将新生成的项目的对话框默认dialog edit删去,如图 5,在对话框中加入两个st

VC++USB及串口通信程序(附工程)

为公司开发产品测试程序,实际上是基于VC++的USB通信及串口通信.当初编写程序时,网上找了很多资料及程序,感觉大都只是说了一点点,没有一个完整的工程以供其他开发者借鉴,完全要靠开发者东拼西凑,最后凑成一个整体工程,还要在这个工程基础上进行相当艰苦的排查问题.解决问题的调试过程.本人对这一过程极其厌烦,现将走完的以上的"艰苦历程"之后的成果列出,以供后来者借鉴. 这一工程中包含了以下知识点: 1. VC++ USB通信: 2. VC++串口通信: 3. 文件(设备)同步异步操作: 4.

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

1.        两台计算机通信需要协议,通信的两台计算机IP必须唯一 2.        同一个计算机可以进行多个应用程序与其他计算机通信,IP地址唯一,而端口号是区别同一计算机(同一IP)的唯一标示. 3.        实际上就类似于一个办公室的总机号码(IP)和分机号码(端口号) 4.        协议:为了进行网络中的数据交换(通信)而建立的规则.标准或约定 5.        协议=语义+语法+规则 6.        不同层具有各自不同的协议 7.        上层使用下层提

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

软件介绍 一个由印度人编写的VC串口类(也是一种VC串口控件),他还配合这个类写了VC 串口通信方面的一些基础知识,如怎么用VC打开串口,如何对串口进行配置,读串口.写串口等. 这个类有点特别,它没有使用事件驱动原理,它是以查询方式工作的. 简介: 对没有接触过串口通信的VC程序员来说显得非常困难,很久以前我在 codeguru.com 上搜索过串口通信相关信息得到了非常大的帮助,从那时起能编写一个简单易用的VC 串口类是我的梦想. 经过七个月在串口通信编程方面实践经验后,我编写了一个基于API

Delphi 与 VC 共享接口和对象

我经常会用 Delphi 写一些工具和应用,为了扩展方便,大部分都会做成插件形式. 迫于某些原因,我的插件不得不用其他开发工具来完成,比如 VC. 于是有个大问题需要解决:如何让 D 和 VC 互相通信.互相操作. 最普遍的做法,无非是定义一些方法,VC 写 Dll 导出这些方法,D 载入 Dll 调用. 但问题是稍大点规模的应用,这种方式非常麻烦,也不够直观. 于是花了点时间研究 D 和 VC 之间共享接口和对象的一些方法,现将要点共享发布出来,希望对大家有用. 基础事项: 在 D 和 VC