0xAA55 发表于 2014-3-30 06:20:53

【输入法】C语言获取输入法候选词的方法

注意:我这里指的是Windows GUI编程。
当你设计一个3D游戏的时候,如果这个游戏不能拦截输入法,你就会觉得很难受,打字的时候看不到候选词,而游戏中按了Ctrl+空格之后各种难受、各种卡。
因此对于这样的程序,它就应该学会捕获输入法的操作,自己显示候选词列表。就像LOL(英雄联盟)那样,有自己的输入法框。
这个是怎么实现的呢?很简单,处理WM_IME_开头的窗口消息就行。
WM_IME_SETCONTEXT:
这个必须处理,告诉输入法,我自己绘制候选词列表的界面。
return DefWindowProc(hWnd,WM_IME_SETCONTEXT,wp,lp&(~ISC_SHOWUIALLCANDIDATEWINDOW));
只要这个消息被这样处理了以后,输入法的候选词框就不会出来了。
WM_IME_STARTCOMPOSITION:
处理这个消息请返回0。否则输入法的候选词框会出来。
return 0;
当你开始打字,候选词框出来的那一下,就会触发WM_IME_STARTCOMPOSITION这个消息。
WM_IME_NOTIFY:
这个消息非常重要。通过处理这个消息你可以获取候选词列表。
WPARAM的值是“子消息”,需要考虑进去。当它是以下数值的时候处理它可以获得候选词列表。
IMN_OPENCANDIDATE://开始选词
IMN_SETCANDIDATEPOS://选词窗口移动
IMN_CHANGECANDIDATE://改变选词
IMN_CLOSECANDIDATE://关闭选词窗口
这些消息触发的时候,你应该调用一些API来获取候选词列表。这个时候你需要声明一个HIMC(输入法句柄)
HIMC hIMC=ImmGetContext(hWnd);//取得输入法句柄
输入法句柄在用完后需要释放。代码如下:
ImmReleaseContext(hWnd,hIMC);//释放输入法句柄
候选词是以一个结构体的形式存储的。而且这个结构体的大小是不确定的。因此你需要取得候选词结构体的大小。
DWORD dwBufLen=ImmGetCandidateList(hIMC,0,NULL,0);//取得候选词列表结构体的大小
取得了大小,你就需要分配内存来读取候选词结构体。
LPCANDIDATELIST pList=(LPCANDIDATELIST)malloc(dwBufLen);//建立结构体
然后再次调用ImmGetCandidateList取得候选词列表
ImmGetCandidateList(hIMC,0,pList,dwBufLen);//取得候选词列表
通过pList->dwSelection可以得到当前选中的候选词的序号。pList->dwCount得到候选词个数。pList->dwOffset是一个数组,它的值是候选词的位置偏移。
取得候选词字符串指针的方法:(TCHAR*)((BYTE*)pList+pList->dwOffset[候选词序号]);//取得候选词
处理这个消息后返回0。
WM_IME_COMPOSITION:
这个消息也很重要,输入法在组字的时候发送这个消息。
这个时候需要处理LPARAM,它的值是多个常数通过按位或组合出来的值,因此需要拆开处理。if(lp&CS_INSERTCHAR)//当前光标插入一个字符
{
    wp是字符的值。;
    if(CS_NOMOVECARET)
         不移动插入符;
}
if(lp&GCS_CURSORPOS)//取得正在输入的字符串(拼音之类的)的插入符的位置
{
    HIMC hIMC=ImmGetContext(hWnd);
    插入符的位置=ImmGetCompositionString(hIMC,GCS_CURSORPOS,NULL,0);
    ImmReleaseContext(hWnd,hIMC);
}
if(lp&GCS_COMPSTR)//取得正在输入的字符串(拼音之类的)
{
    HIMC hIMC=ImmGetContext(hWnd);
    UINT uLen,uMem;
    TCHAR*szCompStr;

    uLen=ImmGetCompositionString(hIMC,GCS_COMPSTR,NULL,0);//取得正在输入的字符串大小
    szCompStr=(TCHAR*)malloc(uMem=(uLen+sizeof(TCHAR)));//分配内存
    if(szCompStr)
    {
      SIZE Size;
      szCompStr=0;//结尾的\0
      ImmGetCompositionString(hIMC,GCS_COMPSTR,szCompStr,uMem);//取得正在输入的字符串
      显示字符串szCompStr,长度为uLen;
      然后记得绘制插入符;
      free(szCompStr);
    }
    ImmReleaseContext(hWnd,hIMC);
}
if(lp&GCS_RESULTSTR)//取得结果字符串
{
    HIMC hIMC=ImmGetContext(hWnd);
    UINT uLen,uMem;
    TCHAR*szCompStr;

    uLen=ImmGetCompositionString(hIMC,GCS_RESULTSTR,NULL,0);//取得结果字符串大小
    szCompStr=(TCHAR*)malloc(uMem=(uLen+sizeof(TCHAR)));//分配内存
    if(szCompStr)
    {
      szCompStr=0;//结尾的\0
      ImmGetCompositionString(hIMC,GCS_RESULTSTR,szCompStr,uMem);//取得结果字符串
      把结果字符串添加到最终输出的文本里面。;
      free(szCompStr);
    }
    ImmReleaseContext(hWnd,hIMC);
}
return 0;WM_IME_ENDCOMPOSITION://打完字
这个消息需要处理,返回0即可。收到这个消息说明候选词窗口被关闭了。
最后,我把一个写好的程序发上来。
EXE下载:

源代码下载:**** Hidden Message *****

0xAA55 发表于 2014-3-30 06:37:52

下图是运行效果

编程的过程中发现微软头文件一个拼写错误,dwIndex被写成了deIndex

FFFFFFFE 发表于 2014-3-30 19:37:52

请先验证邮箱

0xAA55 发表于 2014-3-30 19:43:38

FFFFFFFE 发表于 2014-3-30 11:37
请先验证邮箱

拿这种充满诱导性质的文字来做开门钥匙是对论坛不利的。。。

黑的哥 发表于 2014-4-8 12:52:54

正好需要这个,谢谢

dakuiz@163.com 发表于 2014-10-17 09:31:46

这是我需要的,我可以下载吗?

ZZZZ 发表于 2014-11-10 15:50:40

可以试试这个。

dakuiz@163.com 发表于 2014-11-11 16:36:11

szCompStr=0;//结尾的\0

这一句是有问题的,只是在本程序中碰巧可以运行。但很感谢楼主的分享。希望认识楼主。看到的话请加我扣:289七叁四32。再次感谢楼主。

0xAA55 发表于 2014-11-11 17:33:20

dakuiz@163.com 发表于 2014-11-11 16:36
szCompStr=0;//结尾的\0

这一句是有问题的,只是在本程序中碰巧可以运行。但很感谢楼主的分享。希望认识楼 ...

szCompStr=0;//结尾的\0

这一句是没有问题的。因为
szCompStr=(TCHAR*)malloc(uMem=(uLen+sizeof(TCHAR)));//分配内存
这句多分配了一个字符。所以我觉得没有问题。如果你觉得不是这个原因请告知我。

bozzer 发表于 2014-11-19 16:41:05

有点意思。响应也挺快的。

acBool 发表于 2014-12-23 21:43:58

赞啊,太强大了

acBool 发表于 2015-1-9 14:30:35

楼主应该在写一篇如何获取TSF 框架输入法候选的文章~

略游 发表于 2015-1-28 17:21:08

使用,全屏的时候需要

焰光的盛宴 发表于 2015-3-18 21:56:20

谢谢楼主!我一直都在疑惑这个问题,终于知道资料了

0x0208 发表于 2015-5-2 23:18:57

学长学长学长学长!!!我来啦

baidwwy 发表于 2015-5-12 13:18:19

看看看看看看看看

蓝莓味绿茶 发表于 2015-7-22 15:34:37

AIM 发表于 2015-8-10 11:40:10

不错不错,要的就是这个效果

卡卡 发表于 2015-8-10 16:49:04

light_月 发表于 2015-8-23 17:28:58

支持不错 看看
页: [1] 2 3 4 5
查看完整版本: 【输入法】C语言获取输入法候选词的方法