原文: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. Perl遍历查找文件

    Perl遍历查找文件 使用Perl查找当前目录下的所有PDF文件 ******************************************************************* ...

  2. POJ 1775 Sum of Factorials (ZOJ 2358)

    http://poj.org/problem?id=1775 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1334 题目大意: ...

  3. 【36.86%】【codeforces 558B】Amr and The Large Array

    time limit per test1 second memory limit per test256 megabytes inputstandard input outputstandard ou ...

  4. Oracle 字符集的查看和修改 分类: H2_ORACLE 2013-06-19 16:52 316人阅读 评论(0) 收藏

    一.什么是Oracle字符集 Oracle字符集是一个字节数据的解释的符号集合,有大小之分,有相互的包容关系.ORACLE 支持国家语言的体系结构允许你使用本地化语言来存储,处理,检索数据.它使数据库 ...

  5. 【t070】二进制

    Time Limit: 1 second Memory Limit: 128 MB [问题描述] 求所有可以只用1和00拼成的长度为N的二进制数的个数除以15746的余数. 比如当N=4的时候,有5个 ...

  6. mysql mha高可用架构的安装

    MMM无法全然地保证数据的一致性,所以MMM适用于对数据的一致性要求不是非常高.可是又想最大程度的保证业务可用性的场景对于那些对数据一致性要求非常高的业务,非常不建议採用MMM的这样的高可用性架构.那 ...

  7. 设置好ftp后用xftp连接提示无法打开,无法显示远程文件夹

    原文:设置好ftp后用xftp连接提示无法打开,无法显示远程文件夹 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/the_victory/artic ...

  8. zzuli OJ 1128: 课程平均分

    Description 期末考试结束,班主任拿到了本班学生的成绩汇总表.由m行n列组成(本班共同拥有m名学生,本学期有n门课程),每行是一个同学的n门课程成绩,请编敲代码,计算并输出每门课的平均分.结 ...

  9. 数组filter方法对数组元素进行过滤

    Array.prototype.filter对数组中元素进行过滤 /** * @method reduce * @param {number} item 当前迭代的数组元素 * @param {num ...

  10. [Postgres] Create a Postgres Table

    Learn how to create a table using the most widely-used data types (serial, varchar, integer, float, ...