酒鬼z

我自将心向明月,独卧沙场醉圆缺

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

转自:http://tech.ddvip.com/2012-12/1355243739186932.html

 

IMM(Input Method Manager)只在安装了亚洲语言包之后才能使用。

通过调用GetSystemMetrics(SM_IMMENABLED)知道IMM是否使能。

一共由三部分组成:

status window  输入法状态栏   表示正在处于中文输入状态可以知道是什么输入法

composition window 当你开始输入字母的时候,显示字母

candidates window  紧靠在composition window下面,指示可能的字符组合(就是中文备选)

最终中文通过WM_IME_CHAR消息发送到对应的程序。

IME Window Class是系统预定义的窗口类。一般用于IME-aware程序定制输入法只用。

当一个窗口激活时,操作系统发送WM_IME_SETCONTEXT到程序。如果是IME-unaware程序,程序会把它传递给

DefWindowProc函数,然后由其发送给缺省的输入法。IME-aware程序可能会自行处理该消息。

发送WM_IME_CONTROL消息可以改变composition window

如果输入新字母时,IME会发送WM_IME_COMPOSITION通知程序。

如果设置有变化时,IME会发送WM_IME_NOTIFY。

输入上下文是IME维护的内部数据结构。缺省,操作系统为每个线程一个分配一个默认输入上下文,所以默认输入上下文是线程内窗口的共享资源。

通过ImmGetContext得到特定窗口的输入上下文。通过ImmReleaseContext来释放。

通过ImmCreateContext和ImmAssociateContext可以创建和应用新的输入上下文。

在程序退出之前,必须调用ImmDestroyContext销毁自建的输入上下文。

Composition String就是composition window中显示的字符串。Composition String由一个或者多个分类组成。

分类就是最后能翻译成目标字符的最小集合(比如chuntian对应春天)

通过ImmGetCompositionString and ImmSetCompositionString两个函数,程序可以得到或者设置当前的Composition String以及其相关的属性,比如分类信息,光标信息。

edit control支持两条消息EM_GETIMESTATUS and EM_SETIMESTATUS来改变IME的状态。

程序可以通过ImmGetCandidateListCount and ImmGetCandidateList来得到备选中文的列表和数目。

通过ImmSimulateHotKey 可以设置快捷键。

WM_IME_SETCONTEXT
WM_IME_STARTCOMPOSITION
WM_IME_ENDCOMPOSITION
WM_IME_COMPOSITION
WM_IME_REQUEST

下面我们来实现一个输入法框架

 

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
#include <windows.h>    
#include <stdio.h>    
#include <stdlib.h>    
#include <imm.h>    
#include <tchar.h>    
#pragma comment(lib,"imm32.lib")    
          
//窗口类名    
#define CLSNAME_UI          _T("DLLISUI")       //UI    
#define CS_INPUTSTAR            (CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS)    
          
          
#pragma data_seg("mysechx")    
DWORD CallBackData1=0;    
DWORD CallBackData2=0;    
DWORD CallBackData3=0;    
DWORD OnloadDllWhenExit=1;    // 当输入法退出时是否卸载客户DLL  0-是,1-否    
DWORD LoadNextWhenActive=1;    // 当本输入法激活时,是否自动打开下一个输入法 0-否,1-是    
char g_IMEDLLString[802]="";    
#pragma data_seg()    
          
typedef DWORD (CALLBACK * RUNDLLHOSTCALLBACK)(DWORD calldata1, DWORD calldata2,DWORD calldata3);    
          
HMODULE CilentDLL=NULL;    
RUNDLLHOSTCALLBACK RunDllCallBackX=NULL;    
          
// 先定义好各种函数    
BOOL ImeClass_Register(HINSTANCE hInstance);    
void ImeClass_Unregister(HINSTANCE hInstance);    
LRESULT WINAPI UIWndProc(HWND hUIWnd,UINT message,WPARAM wParam,LPARAM lParam);    
BOOL MyGenerateMessage(HIMC hIMC, UINT msg, WPARAM wParam, LPARAM lParam);    
          
void MyLoadCilentDLLFun()    
{    
    MessageBox(NULL,"HELLO","HELLO",MB_OK);    
}    
          
BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)    
{    
   switch(fdwReason)    
    {    
      case DLL_PROCESS_ATTACH:    
          if(!ImeClass_Register(hinstDLL)) return FALSE;   // DLL加载时注册必须的UI基本窗口类    
          //MyLoadCilentDLLFun();    
          break;    
      case DLL_THREAD_ATTACH:    
         break;    
      case DLL_THREAD_DETACH:    
         break;    
      case DLL_PROCESS_DETACH:    
          ImeClass_Unregister(hinstDLL);  // DLL退出时注销注册的窗口类    
          if (CilentDLL!=NULL && OnloadDllWhenExit==0)    
          {    
              FreeLibrary(CilentDLL);    // 输入法退出时卸载客户DLL    
          }    
        break;    
      default:    
        break;    
    }    
    return true;    
}    
          
          
          
          
//************************************************************    
//  基本输入法窗口UI类注册    
//************************************************************    
BOOL ImeClass_Register(HINSTANCE hInstance)    
{    
    WNDCLASSEX wc;    
              
    //    
    // register class of UI window.    
    //    
    wc.cbSize         = sizeof(WNDCLASSEX);    
    wc.style          = CS_INPUTSTAR | CS_IME;    
    wc.lpfnWndProc    = UIWndProc;    
    wc.cbClsExtra     = 0;    
    wc.cbWndExtra     = 2 * sizeof(LONG);    
    wc.hInstance      = hInstance;    
    wc.hCursor        = LoadCursor( NULL, IDC_ARROW );    
    wc.hIcon          = NULL;    
    wc.lpszMenuName   = (LPTSTR)NULL;    
    wc.lpszClassName  = CLSNAME_UI;    
    wc.hbrBackground  = NULL;    
    wc.hIconSm        = NULL;    
              
    if( !RegisterClassEx( (LPWNDCLASSEX)&wc ) )    
        return FALSE;    
              
    return TRUE;    
}    
          
//**************************************************************    
//  注销注册的窗口类    
//**************************************************************    
void ImeClass_Unregister(HINSTANCE hInstance)    
{    
    UnregisterClass(CLSNAME_UI,hInstance);    
}    
          
          
// ------------------------------------    
//需导出函数    
DWORD WINAPI ImeConversionList(HIMC hIMC,LPCTSTR lpSource,LPCANDIDATELIST lpCandList,DWORD dwBufLen,UINT uFlag)    
{    
    return 0;    
}    
//需导出函数    
BOOL WINAPI ImeConfigure(HKL hKL,HWND hWnd, DWORD dwMode, LPVOID lpData)    
{    
    switch (dwMode) {    
    case IME_CONFIG_GENERAL:    
        MessageBox(NULL,"Windows标准输入法扩展服务 V1.0  ","关于输入法扩展",48);    
        break;    
    default:    
        return (FALSE);    
        break;    
    }    
    return (TRUE);    
}    
//需导出函数    
BOOL WINAPI ImeDestroy(UINT uForce)    
{    
    if (uForce) {    
        return (FALSE);    
    }    
          
    return (TRUE);    
}    
//需导出函数    
LRESULT WINAPI ImeEscape(HIMC hIMC,UINT uSubFunc,LPVOID lpData)    
{    
    return FALSE;    
}    
          
//需导出函数    
BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo,LPTSTR lpszUIClass,LPCTSTR lpszOption)    
{    
    // 输入法初始化过程    
    lpIMEInfo->dwPrivateDataSize = 0; //系统根据它为INPUTCONTEXT.hPrivate分配空间    
          
    lpIMEInfo->fdwProperty = IME_PROP_KBD_CHAR_FIRST |     
                             IME_PROP_IGNORE_UPKEYS |    
                             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,CLSNAME_UI);  // 注意该输入法基本窗口类必须注册,否则输入法不能正常运行    
          
    return TRUE;    
}    
          
/*    
系统调用这个接口来判断IME是否处理当前键盘输入    
HIMC hIMC:输入上下文    
UINT uKey:键值    
LPARAM lKeyData: unknown    
CONST LPBYTE lpbKeyState:键盘状态,包含256键的状态    
return : TRUE-IME处理,FALSE-系统处理    
系统则调用ImeToAsciiEx,否则直接将键盘消息发到应用程序    
*/    
//需导出函数    
BOOL WINAPI ImeProcessKey(HIMC hIMC,UINT uKey,LPARAM lKeyData,CONST LPBYTE lpbKeyState)    
{    
    return FALSE;    
}    
          
/**********************************************************************/
/* ImeSelect()                                                        */
/* Return Value:                                                      */
/*      TRUE - successful, FALSE - failure                            */
/**********************************************************************/
//需导出函数    
BOOL WINAPI ImeSelect(HIMC hIMC,BOOL fSelect)    
{    
    MyLoadCilentDLLFun();   // 在切换输入法时判断是否需要加载客户DLL    
          
    if (!hIMC) {    
        return (FALSE);    
    }    
    if (fSelect==TRUE && LoadNextWhenActive!=0)    
    {    
        //ActivateKeyboardLayout((HKL)HKL_NEXT,0);  // 不要在该接口中使用此函数切换到下一个输入法,否则函数返回时输入法又会切换回去    
                  
    }    
    return TRUE;    
}    
          
          
/*   
使一个输入上下文激活或者失活,并通知输入法最新的输入上下文,可以在此做一些初始化工作   
HIMC hIMC :输入上下文   
BOOL fFlag : TRUE if activated, FALSE if deactivated.    
Returns TRUE if successful, FALSE otherwise.    
*/
//需导出函数    
BOOL WINAPI ImeSetActiveContext(HIMC hIMC,BOOL fFlag)    
{    
    //通过IME消息来实现窗口状态变化    
    return TRUE;    
}    
          
/*   
Causes the IME to arrange the composition string structure with the given data.   
This function causes the IME to send the WM_IME_COMPOSITION message.    
Returns TRUE if successful, FALSE otherwise.   
*/
//需导出函数    
BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp, DWORD dwComp, LPCVOID lpRead, DWORD dwRead)    
{    
    return FALSE;    
}    
          
          
/*   
应用程序调用这个接口来进行输入上下文的转换,输入法程序在这个接口中转换用户的输入   
UINT uVKey:键值,如果在ImeInquire接口中为fdwProperty设置了属性IME_PROP_KBD_CHAR_FIRST,则高字节是输入键值   
UINT uScanCode:按键的扫描码,有时两个键有同样的键值,这时需要使用uScanCode来区分   
CONST LPBYTE lpbKeyState:键盘状态,包含256键的状态   
LPDWORD lpdwTransKey:消息缓冲区,用来保存IME要发给应用程序的消息,第一个双字是缓冲区可以容纳的最大消息条数   
UINT fuState:Active menu flag(come from msdn)   
HIMC hIMC:输入上下文   
return : 返回保存在消息缓冲区lpdwTransKey中的消息个数   
*/
//需导出函数    
UINT WINAPI ImeToAsciiEx (UINT uVKey,UINT uScanCode,CONST LPBYTE lpbKeyState,LPDWORD lpdwTransKey,UINT fuState,HIMC hIMC)    
{    
    return 0;    
}    
          
          
//由应用程序发给输入法的消息,输入法可以在此响应用程序的请求    
//return : TRUE-正确响应了请求,FALSE-无响应    
//需导出函数    
BOOL WINAPI NotifyIME(HIMC hIMC,DWORD dwAction,DWORD dwIndex,DWORD dwValue)    
{    
    BOOL bRet = FALSE;    
    switch(dwAction)    
    {    
    case NI_OPENCANDIDATE:    
        break;    
    case NI_CLOSECANDIDATE:    
        break;    
    case NI_SELECTCANDIDATESTR:    
        break;    
    case NI_CHANGECANDIDATELIST:    
        break;    
    case NI_SETCANDIDATE_PAGESTART:    
        break;    
    case NI_SETCANDIDATE_PAGESIZE:    
        break;    
    case NI_CONTEXTUPDATED:    
        switch (dwValue)    
        {    
        case IMC_SETCONVERSIONMODE:    
            break;    
        case IMC_SETSENTENCEMODE:    
            break;    
        case IMC_SETCANDIDATEPOS:    
            break;    
        case IMC_SETCOMPOSITIONFONT:    
            break;    
        case IMC_SETCOMPOSITIONWINDOW:    
            break;    
        case IMC_SETOPENSTATUS:    
            break;    
        default:    
            break;    
        }    
        break;    
                  
    case NI_COMPOSITIONSTR:    
        switch (dwIndex)    
        {    
        case CPS_COMPLETE:    
            break;    
        case CPS_CONVERT:    
            break;    
        case CPS_REVERT:    
            break;    
        case CPS_CANCEL:    
            break;    
        default:    
            break;    
        }    
        break;    
                      
    default:    
        break;    
    }    
    return bRet;    
}    
          
          
/**********************************************************************/
/* ImeRegsisterWord                                                   */
/* Return Value:                                                      */
/*      TRUE - successful, FALSE - failure                            */
/**********************************************************************/
//需导出函数    
BOOL WINAPI ImeRegisterWord(    
    LPCTSTR lpszReading,    
    DWORD   dwStyle,    
    LPCTSTR lpszString)    
{    
    return (FALSE);    
}    
          
/**********************************************************************/
/* ImeUnregsisterWord                                                 */
/* Return Value:                                                      */
/*      TRUE - successful, FALSE - failure                            */
/**********************************************************************/
//需导出函数    
BOOL WINAPI ImeUnregisterWord(    
    LPCTSTR lpszReading,    
    DWORD   dwStyle,    
    LPCTSTR lpszString)    
{    
    return (FALSE);    
}    
          
/**********************************************************************/
/* ImeGetRegsisterWordStyle                                           */
/* Return Value:                                                      */
/*      number of styles copied/required                              */
/**********************************************************************/
//需导出函数    
UINT WINAPI ImeGetRegisterWordStyle(    
    UINT       nItem,    
    LPSTYLEBUF lpStyleBuf)    
{    
    return (FALSE);    
}    
          
/**********************************************************************/
/* ImeEnumRegisterWord                                                */
/* Return Value:                                                      */
/*      the last value return by the callback function                */
/**********************************************************************/
//需导出函数    
UINT WINAPI ImeEnumRegisterWord(    
    REGISTERWORDENUMPROC lpfnRegisterWordEnumProc,    
    LPCTSTR              lpszReading,    
    DWORD                dwStyle,    
    LPCTSTR              lpszString,    
    LPVOID               lpData)    
{    
    return (FALSE);    
}    
          
          
/**********************************************************************/
/*                                                                    */
/* UIWndProc()                                                        */
/*                                                                    */
/* 输入法界面窗口的窗口处理过程                                       */
/*                                                                    */
/**********************************************************************/
          
//需导出函数    
LRESULT WINAPI UIWndProc(HWND hUIWnd,UINT message,WPARAM wParam,LPARAM lParam)    
{    
    return 0;    
}    
//需导出函数    
LRESULT WINAPI StatusWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)    
{    
    // 输入法状态条的窗口处理过程    
    return 0;    
}    
//需导出函数    
LRESULT WINAPI CompWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)    
{    
    // 输入法显示候选字的窗口的的窗口处理过程    
    return 0;    
}    
//需导出函数    
LRESULT WINAPI CandWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)    
{    
    // 输入法编码窗口的窗口处理过程    
    return 0;    
}
posted on 2013-12-13 19:45  酒鬼z  阅读(692)  评论(0)    收藏  举报