原文:Win7 64位系统,使用(IME)模式VS2010 编写 和 安装 输入法 教程(1)

首先感谢:
http://blog.csdn.net/shuilan0066/article/details/6884483输入法 编程分析
http://blog.csdn.net/mspinyin/article/details/6141599输入法的注册、安装和卸载
http://www.setoutsoft.cn/Html/?256.html 浅谈输入法编程
http://wenku.baidu.com/view/3d179422bcd126fff7050b9d.html输入法漫谈

这些文章作者的无私奉献。

TSF(Text Service Framework)WIN7

写这篇文章的动机是:由于Win7 64 位系统的普及,按照上面这些文章来编写自己的输入法会遇到很多意想不到的问题。至今网络上没有找到现成详细的解决方案。我通过一周的摸索和总结,深知靠自己摸索编译成功并安装一个可以在win7 64位系统下运行的输入法是多么的艰难。 特将自己的经验拿出来和大家分享。

编写输入法有几种方式,如外挂式,IME式,TSF式,今天我们主要介绍IME式( 输入法接口式(Input Method Editor-IME))

1,输入法是什么东西? 
编写输入法其实就是编写一个DLL ,一个导出一些操作系统约定函数的DLL,操作系统通过这些函数和我们的程序交互,将用户输入的编码转换成汉字通过消息传送给应用程序(如记事本,word,)。用现在的话来说就是实现一个“接口”。

(1)操作系统如何和我们的Dll交互呢?



(2)我们编写的这个Dll就是IME




输入法工作原理 如下图:



(上图来自于:http://blog.csdn.net/shuilan0066/article/details/6883629 输入法工作原理)

2,具体我们应该做哪些工作呢?
(1)首先编写一个DLL,导出IME规定的函数。
注意这个DLL除了必须导出IME规定的函数外,还要满足如下条件。

包含一个.rc 的资源文件。包含一个Version资源

如下图划红线的部分必须设置成:FILETYPE : VFT_DRV FILESUBTYPE : VFT2_DRV_INPUTMETHOD 

否则输入法无法加载。


(2)如何导出这些函数呢?
通过def文件导出函数。然后如下图设置。 使用def文件导出dll函数的好处是,导出的函数名不会变化。

 


(3)要导出哪些函数,这些函数有什么用呢?
IME要求导出的有十几个函数。可真正重要的只有几个。
输入法初始化:

ImeInquire: 刚选择某输入法时,IMM调用此函数,获得输入法相关信息

BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo,LPTSTR lpszUIClass,LPCTSTR lpszOption)

{

if (!lpIMEInfo) return (FALSE);

lpIMEInfo->dwPrivateDataSize = 0;

lpIMEInfo->fdwProperty = IME_PROP_KBD_CHAR_FIRST | 

#ifdef _UNICODE

IME_PROP_UNICODE |

#endif

IME_PROP_SPECIAL_UI |

IME_PROP_END_UNLOAD; //会让输入法随应用程序的退出而退出,这个在调试程序的时候特别重要,我们重新编译了程序就无需

//重启电脑,就可以更换输入法程序,进行调试。

lpIMEInfo->fdwConversionCaps = IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE;

lpIMEInfo->fdwSentenceCaps = IME_SMODE_NONE;

lpIMEInfo->fdwUICaps = UI_CAP_2700;

lpIMEInfo->fdwSCSCaps = 0;

lpIMEInfo->fdwSelectCaps = SELECT_CAP_CONVERSION;

_tcscpy(lpszUIClass, UICLASSNAME);

return TRUE;

}

ImeSelect: 打开或关闭输入法时被调用,在此函数中对输入法上下文进行初始化或恢复释放,

在打开输入法时 fSelect为TRUE, 在关闭输入法时fSelect为FALSE

将键盘消息转换为相应汉字:
ImeProcessKey :处理键盘消息:
IMM通过此函数,对键盘消息进行分类筛选,一类可以直接发给应用程序,一类需要发送给IME进行转换
 ,返回值为FALSE,说明键盘消息被直接发送给了应用程序; 返回值为TRUE 说明键盘消息被发送给了IME,被发送IME后,IMM会立即调用ImeToAsciiEx对键盘消息进行转换。

ImeToAsciiEx :输入法编程最重要部分----- 此函数将进过ImeProcessKey 筛选,通过IMM传递过来的键盘消息转换为composition写作窗口中的字符串,然后再查找码表,更新候选窗口,最后选择某候选字符作为最终结果,通过消息传递给应用程序。

(4)我们的输入法怎么显示和更新写作窗户,候选窗口,怎么把用户选择的汉字传递给应用程序,通过什么机制呢?
写作窗口:就是显示和编辑用户输入字符串的窗口,比如输入的是拼音


侯选窗口:就是显示符合用户输入编码的汉字,供用户选择。通常写作窗口和获选窗户可以合二为一。

首先我们要了解两个概念:

<1>UIWnd 和UIWndProc

<2>输入法上下文(HIMC)

我们都知道windos是通过消息来运作的,要显示,更新 输入法的写作和候选窗口,就需要有消息循环。

而输入法是一个插件,他需要依靠应用程序中用户的输入消息,来控制输入法写作和候选窗口的显示和更新。
可应用程序的消息怎样才能传递给输入法呢?
IME要求我们自建的输入法dll导出一个接口,原型如LRESULT WINAPI UIWndProc(HWND hUIWnd, UINT message,WPARAM wParam, LPARAM lParam),

而User.exe(一个系统进程) 会创建一个UIWnd ,这个窗口不会显示,就是它充当应用程序和输入法之间windos消息的传递。在这个窗口的消息循环中会调用我们输入法dll导出的接口:UIWndProc。 传递过来的HWND hUIWnd 就是这个窗口的句柄,它是输入法中创建的窗口如写作窗口,候选窗口的宿主(Owner)。

上面我们说了应用程序怎么把消息传递给输入法,下面我们说说输入法怎么把它的消息和数据传递给应用程序?
User.exe(一个系统进程) 会为应用程序分配一片内存,而HIMC就是这片内存的句柄,我们称之为输入法上下文。我们将输入法要传递给应用程序的消息和数据存入这片内存,再由User.exe 传递给应用程序。

下面我们我简单介绍一下消息和数据传递的具体方法。
首先要获得HIMC,通过UIWnd的句柄g_hUIWnd 使用ImmLockIMC

HIMC hIMC = (HIMC)GetWindowLong(g_hUIWnd, IMMGWL_IMC);

*lpIMC = (LPINPUTCONTEXT)ImmLockIMC(*hIMC)

然后向HIMC中写入消息

if (IsWindow(lpIMC->hWnd))

{
LPTRANSMSG lpTransMsg;

if (!(lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf,(lpIMC->dwNumMsgBuf+1) * sizeof(TRANSMSG))))

goto Error;

if (!(lpTransMsg = (LPTRANSMSG)ImmLockIMCC(lpIMC->hMsgBuf)))

goto Error;

//将消息写入HIMC中

lpTransMsg += (lpIMC->dwNumMsgBuf);

lpTransMsg->message=message;

lpTransMsg->wParam=wParam;

lpTransMsg->lParam=lParam;

lpIMC->dwNumMsgBuf++;
ImmUnlockIMCC(lpIMC->hMsgBuf);

//将消息发送到IME,IME再决定是自己处理还是继续发给应用程序

ImmGenerateMessage(hIMC);

}

向HIMC中写入数据,将用户选择的汉字传递给应用程序。

lpIMECompStr = (LPCOMPOSITIONSTRING)ImmLockIMCC(lpIMC->hCompStr);
if (fFlag) 

{

lpResultStr = GetResultStr();//用户选择的汉字字符串

if (!lpResultStr) return FALSE;

//将用户选择的字符串写入HIMC中

_tcscpy((LPTSTR)((LPBYTE)(lpIMECompStr) + (lpIMECompStr)->dwResultStrOffset), lpResultStr);

lpIMECompStr->dwResultStrLen = _tcslen(lpResultStr);
}

ImmUnlockIMCC(lpIMC->hCompStr); 

同时将用户选择的汉字传递给应用程序需要消息的协助。 
分别是WM_IME_STARTCOMPOSITION、WM_IME_COMPOSITION和WM_IME_ENDCOMPOSITION,它们分别指示开始输入编码,输入编码或者结果(视参数而异)及编码输入完成 ,WM_IME_STARTCOMPOSITION和WM_IME_ENDCOMPOSITION需要成对使用。

当发送WM_IME_COMPOSITION (GCS_COMPREAD|GCS_COMP|GCS_CURSORPOS|GCS_DELTASTART|GCS_RESULTREAD|GCS_RESULT),消息时候,IME将HIMC中lpIMECompStr 中的汉字通过WM_IME_CHAR, 消息传递给应用程序。或者转换成WM_CHAR消息传递给应用程序。

上面总结了输入法编程的基本原理。

3,输入法的安装和调试
64位系统 的输入法安装和32位系统不同。64位系统兼容32位系统的应用程序,可输入法不行,64位的应用程序必须有64位的输入法,而32位程序必须有32位的输入法。
所以我们要在64位系统中安装输入法,首先必须将我们的输入法dll编译成64位和32位两种。
(1)如何编译64位的程序呢?使用64位的操作系统,在VS2010中打开 菜单:生成-》配置管理器


(2)如何安装输入法? 

将编译的dll扩展名改成.ime

<1>拷贝输入法dll到系统目录。将64位编译的dll放入 c:\windows\system32 目录,将32位编译的放入C:\Windows\SysWOW64目录
<2>将输入法注册,网上说可以使用ImmInstallIME 函数,可我在64位系统上始终没有成功。于是使用手动创建注册表项来实现输入法的注册

A.在注册表中HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Keyboard Layouts,创建一个新的Key,名字为xxxx0804 (低位表示语言,这里0804表示简体中文;高位表示设备句柄,0000表示默认的physical layout,如00000804表示简体中文英文键盘)。譬如:

[HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Keyboard Layouts/E0200804]

"IME File"="***.IME" //你的输入法dll的文件名

"Layout File"="kbdus.dll"

"Layout Text"="****输入法 2010"

B. Enable这个输入法,譬如:

[HKEY_CURRENT_USER/Keyboard Layout/Preload]

"1"="00000804"

"2"="e0200804" //按照已有最大的序号+1 = 上面你创建的key的名字:E0200804

C,重新启动系统

(3)如何调试输入法
按照上面的方法按照好输入法以后,我们就可以使用VS2010对输入法进行调试。

<1> 使用附加到进程的方式



然后再窗口选择 写字板,或者word,等进程,



然后,设置断点,在记事本中选择你自己编写的输入法,输入编码,进行调试。

<2>设置命令参数为记事本程序的路径。c:\\windows\\system32\\notepad.exe


 


(4)关于编译源程序可能会遇到的问题
1、确保应用 Imm32.lib


 


2、如果 IMM.H 的位置在项目中,应在 additional include directories 中指定为./

 

Win7 64位系统,使用(IME)模式VS2010 编写 和 安装 输入法 教程(1)的更多相关文章

  1. 新装的win7 64位系统上装了IE11,想调试网页的时候,按F12,工具会出来,但是没法正常使用,出现空白。

    Windows专区开了一帖,没人应.这边再开一帖,看看各位遇到过没.如题,新装的win7 64位系统上装了IE11,想调试网页的时候,按F12,工具会出来,但是没法正常使用.尤其是想切换文档模式,只能 ...

  2. WIN7 64位系统注册银行支付组件

    WIN7 64位系统注册银行支付组件目前只尝试注册了银联的chinapay.dll和工行的icbcebankutil.dll 1.将dll文件拷贝到windows\syswow64\文件夹下(Win7 ...

  3. WIN7 64位系统搭建WINCE6.0系统遇到的问题

    WIN7 64位系统搭建WINCE6.0系统遇到的问题 安装顺序如下: .先装Visual Studio2005: .安装Visual Studio2005 Service Pack 1: .安装Vi ...

  4. U盘安装Win7 64位系统(笔记本+台式机亲测)

    准备工具: 1. Win7 64位系统的镜像文件(网上随便一搜即可,最好是纯净版,没有一堆乱七八糟的内置软件) 2. 4G以上的U盘一个 所用软件: 老毛桃(官网下载) 具体步骤: 1.数据备份(将原 ...

  5. Win7 64位系统上配置使用32位的Eclipse(转)

    Win7 64位系统上配置使用32位的Eclipse 博客分类: Eclipse eclipse  最近工作电脑换成了64位的win7系统,之前个人电脑上安装的jdk和Eclipse都是32位的.而新 ...

  6. win7 64位系统装oracle11 提示环境变量path 值超过1023字符

    win7 64位系统装oracle10 提示环境变量path 值超过1023字符 1.提示环境变量path 值超过1023字符. 方案: 1.oracle安装文件,右键属性--设置兼容性--兼容XP ...

  7. win7 64位系统下安装autoitlibrary库遇到问题解决

    转载来自http://blog.sina.com.cn/s/blog_53f023270101skyq.html 今天需要在win7 64位系统下安装autoitlibrary库,起初安装好了robo ...

  8. Win7 64位系统,IE11,如何让IE的Tab强制运行64位内核?

    有些人在使用TerraExplorer Pro 7版本进行web二次开发的时候,常会遇到下面截图中这样的问题, 这个问题主要是因为安装的TerraExplorer Pro 7 版本是64位的,而模型运 ...

  9. (转)Win7 64位系统下 Retional rose 2003 安装及破解

    网上关于Retional rose 2003安装和破解的文章比较多,这里,我结合自己的亲身体验,和大家分享一下win7 旗舰版 64位系统下Retional rose 2003(下面简称rose200 ...

随机推荐

  1. 机器学习算法笔记1_2:分类和逻辑回归(Classification and Logistic regression)

    形式: 採用sigmoid函数: g(z)=11+e−z 其导数为g′(z)=(1−g(z))g(z) 如果: 即: 若有m个样本,则似然函数形式是: 对数形式: 採用梯度上升法求其最大值 求导: 更 ...

  2. 用Go写了一个相似Proxy的小程序,能够用来訪问goolge个人使用还是能够的.

    package main import ( "fmt" "io" "net/http" ) func main() { http.Handl ...

  3. 【48.51%】【poj 1611】The Suspects

    Time Limit: 1000MS Memory Limit: 20000K Total Submissions: 34447 Accepted: 16711 Description Severe ...

  4. iOS开发Quartz2D之 七:雪花效果

    #import "VCView.h" @implementation VCView -(void)awakeFromNib { //[NSTimer scheduledTimerW ...

  5. Spring ContextLoaderListener与DispatcherServlet所加载的applicationContext的区别

    http://www.lai18.com/content/9755931.html Spring 容器(Spring 的上下文) https://my.oschina.net/jast90/blog/ ...

  6. ios开发级联菜单(利用父子控制器--两个菜单封装为两个子控制器来实现)

    一:1:级联菜单可以使用两个tableView来实现,也可以利用父子控制器,两个控制器来实现,根视图控制器作为两个控制器的父控制器,来管理两个子控制器.2:将左右菜单分别交给两个控制器去管理,对于一些 ...

  7. java中的subString具体解释及应用

    substring(參数)是java中截取字符串的一个方法 有两种传參方式 一种是public String substring(int beginIndex) 返回一个新的字符串,它是此字符串的一个 ...

  8. Android JNI编程(三)——C语言指针的初步认识、指针变量、互换两个数、函数返回多个值

    版权声明:本文出自阿钟的博客,转载请注明出处:http://blog.csdn.net/a_zhon/. 目录(?)[+] 一.什么是指针? 简单来说: 指针就是内存地址      内存地址就是指针. ...

  9. CentOS 7安装fcitx中文输入法

    安装过程例如以下: 1.增加EPEL源 EPEL7差点儿是CentOS必备的源: sudo yum install epel-release 2.加入mosquito-myrepo源 mosquito ...

  10. 使用搜狐Sendcloud的Webapi发送邮件:Jodd和Apache Httpclient

    最近,在使用搜狐Sendcloud发邮件.    Sendcloud提供http格式的webapi,方便地发送邮件,当然是要付费的. 很早之前,http工具一直用Httpclient,后来觉得jodd ...