输入法编程指南(根据msdn翻译)
Windows 95输入法编辑器(IME)
原著:Microsoft
翻译:TBsoft Software Studio
一、关于Windows 95混合语言IME
在Windows 95中,IME是一个动态链接库(DLL),与Windows 3.1远东版本IME不同的是,每一个运行的IME相当于混合语言键盘布局中的一种。与Windows 3.1 IME相比较,Windows 95混合语言IME提供下列增强功能:
●运行时相当于混合语言环境的一个部件
●为每一个应用程序任务提供多重输入上下文
●为每一个应用程序线程提供一个活动的IME
●通过应用程序消息循环给应用程序提供信息(消息顺序不能改变)
●为无IME支持应用程序和部分IME支持应用程序提供有力的支持
要得到全部的增强功能,应用程序需要支持Windows 95 IME应用程序I/F。
本文档描述了Windows 95 IME体系结构的应用程序I/F。
1、IME的结构
Windows 95 IME必须提供两个部件:IME转换接口和IME用户接口。IME转换接口由一组IME模块引出函数提供,这些函数被IMM(输入法管理器——译者注)调用。
IME用户接口由一组窗口提供,这些窗口接收消息并提供IME的用户界面。
2、IME支持应用程序(IME感知应用程序——译者注)
应用程序有下列类型:
●无IME支持应用程序:这种应用程序不控制IME,然而,如果应用程序接受DBCS字符,用户可以通过IME在应用程序中输入DBCS字符。
●部分IME支持应用程序:这种应用程序只控制不同的IME上下文,例如打开和关闭IME、写作窗口等等,但是不重新显示任何IME用户界面。
●完全IME支持应用程序:这种应用程序负责管理通过IME显示给应用程序的任何信息。
在Windows 95中,一个无IME支持应用程序有一个缺省的IME窗口和一个缺省的输入上下文。
部分IME支持应用程序使用预定义的“IME”类创建自己的IME窗口,可以管理或者不管理自己的输入上下文。
完全IME支持应用程序自己管理输入上下文,显示输入上下文给出的任何需要的信息,不使用IME窗口。
二、IME用户界面
IME用户界面包括IME窗口、用户界面(UI)窗口以及UI窗口的部件。
1、特征
IME类是实现IME用户界面部分的预定义全局窗口类。“IME”类与预定义的公共控制窗口类有许多相同的特点,IME窗口实例与静态控制一样通过CreateWindowEx函数创建,IME类窗口自己不响应用户输入,取而代之的是接收不同类型的控制消息实现全部IME用户接口。应用程序可以使用IME类创建自己的IME窗口,还可以使用ImmGetDefaultIMEWnd函数获取缺省IME窗口。创建自己的IME窗口或者使用缺省IME窗口的应用程序被称为IME支持应用程序,具有以下优点(与对应的Windows3.1应用程序比较):
●包括候选字列表窗口(候选窗口),每一个应用程序可以有自己的用户界面窗口实例,使得用户可以在任何输入过程的中途停止并切换到另一个应用程序。在Windows 3.1日文版本中,用户切换到另一个应用程序是必须放弃当前输入过程。
●因为IME用户界面窗口包括应用程序窗口句柄,IME用户界面窗口可以为应用程序提供缺省行为。例如当应用程序移动时IME用户界面窗口自动移动,自动跟随窗口中的插入符号位置,为每一个应用程序标示模式等等。
即使系统仅仅只提供一个IME类,IME窗口仍然有两种类型。一种类型是系统为无IME支持应用程序创建的IME窗口,DefWindowProc函数为该窗口处理消息,DefWindowProc函数的IME用户接口被线程的所有无IME支持窗口共享,在文档中,这种窗口称为缺省IME窗口。另一种类型是IME支持应用程序创建的IME窗口,在文档中,IME支持应用程序创建的IME窗口称作应用程序IME窗口。
2、缺省和应用程序IME窗口
当线程初始化时系统创建缺省IME窗口,这就是说,线程自动获取缺省IME窗口。缺省IME窗口为无IME支持应用程序提供IME用户界面,当IME或者IMM生成一个IME消息(WM_IME_*)时,无IME支持应用程序传递该消息到DefWindowProc函数,DefWindowProc函数发送需要的消息到为应用程序提供缺省IME用户界面的缺省IME窗口。IME支持应用程序当不从IME获取消息时也可以使用缺省IME窗口,需要时可以使用自身的IME窗口。
3、IME类
IME类是Windows 95远东版本预定义的窗口类,就像Edit是预定义的窗口类一样。预定义的IME类实现全部的IME用户接口,处理所有来自IME和包含IMM函数的应用程序的消息,应用程序使用IME类创建自己的IME窗口。系统IME类不能被被任何IME替换。
窗口过程与IME类通过WM_IME_SELECT消息交互,该消息包括新选中的IME的键盘布局,IME类使用键盘布局查找到每一个IME定义的类名。使用类名,IME类为当前活动的IME创建IME用户界面窗口。
4、IME UI类
每一个IME必须向系统注册自己的用户界面(UI)类,UI类提供IME相关功能。当IME附加在进程上时IME注册自己的UI类,这就是说,当DLLEntry函数被调用DLL_PROCESS_ATTACH功能时,IME必须在对ImeInquire函数的调用过程中指定UI类名。UI类应该使用CS_IME窗口风格注册以使得每一个应用程序都可以使用UI类。
UI类名(包括空终结符)可以使用16位的TCHAR字符,这个限制可能延续到Windows的未来版本。
当注册一个UI类时,应该指定8个字节的窗口附加数据(这就是说,设置WNDCLASSEX类的cbWndExtra成员的值为2*sizeof(LONG)),系统使用该窗口附加数据。
IME可以在为应用程序执行任务时注册任何类和创建任何窗口。
下面的实例显示了怎样注册IME窗口类:
BOOL WINAPI DLLEntry ( HINSTANCE hInstDLL, DWORD dwFunction, LPVOID lpNot)
{
switch (dwFunction)
{
case DLL_PROCESS_ATTACH:
hInst= hInstDLL;
wc.style = CS_MYCLASSFLAG | CS_IME;
wc.lpfnWndProc = MyUIServerWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 2 * sizeof(LONG);
wc.hInstance = hInst;
wc.hCursor = LoadCursor( NULL, IDC_ARROW);
wc.hIcon = NULL;
wc.lpszMenuName = (LPSTR) NULL;
wc.lpszClassName = (LPSTR) szUIClassName;
wc.hbrBackground = NULL;
if(!RegisterClass((LPWNDCLASS)&wc))
return FALSE;
wc.style = CS_MYCLASSFLAG | CS_IME;
wc.lpfnWndProc = MyCompStringWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = cbMyWndExtra;
wc.hInstance = hInst;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = NULL;
wc.lpszMenuName = (LPSTR) NULL;
wc.lpszClassName = (LPSTR) szUICompStringClassName;
wc.hbrBackground = NULL;
if(!RegisterClass((LPWNDCLASS)&wc))
return FALSE;
break;
case DLL_PROCESS_DETACH:
UnregisterClass(szUIClassName,hInst);
UnregisterClass(szUICompStringClassName,hInst);
break;
}
return TRUE;
}
5、UI窗口
IME类对应的IME窗口被应用程序或者系统创建,当IME窗口被创建时,IME自身提供的UI窗口被创建并被IME窗口所拥有。每一个UI窗口有一个当前的输入上下文,当UI窗口接收到IME消息(WM_IME_*)时,可以通过调用GetWindowLong函数和指定IMMGWL_IMC索引值查找到输入上下文,UI窗口可以根据输入上下文处理消息,UI窗口可以在除响应WM_CREATE消息以外的任何时间查找到输入上下文。
IME不允许改变UI窗口的窗口附加数据,如果UI窗口的某个实例需要窗口附加数据,可以使用IMMGWL_PRIVATE参数值调用SetWindowLong和GetWindowLong函数,IMMGWL_PRIVATE参数值提供为UI窗口的某个实例存取附加数据中LONG类型值的能力,如果需要大于LONG类型值的附加数据,可以保存一个内存块的句柄到IMMGWL_PRIVATE域。
UI窗口过程可以使用DefWindowProc函数,但是UI窗口不允许传递IME消息给DefWindowProc函数,即使某个IME消息没有被处理,UI窗口也不允许传递该消息给DefWindowProc函数。
LRESULT UIWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HIMC hIMC;
HGLOBAL hMyExtra;
switch(msg){
case WM_CREATE:
// Allocate the memory bloack for the window instance.
hMyExtra = GlobalAlloc(GHND,size_of_MyExtra);
if (!hMyExtra)
MyError();
// Set the memory handle into IMMGWL_PRIVATE
SetWindowLong(hWnd, IMMGWL_PRIVATE, (LONG)hMyExtra);
.
.
.
break;
case WM_IME_xxxx:
// Get IMC;
hIMC = GetWindowLong(hWnd,IMMGWL_IMC);
// Get the memory handle for the window instance.
hMyExtra = GetWindowLong(hWnd, IMMGWL_PRIVATE);
lpMyExtra = GlobalLock(hMyExtra);
.
.
.
GlobalUnlock(hMyExtra);
break;
.
.
.
case WM_DESTROY:
// Get the memory handle for the window instance.
hMyExtra = GetWindowLong(hWnd, IMMGWL_PRIVATE);
// Free the memory block for the window instance.
GlobalFree(hMyExtra);
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
}
UI窗口必须在当前选定的输入上下文中执行动作,当一个窗口被激活时,UI窗口接收到提供当前输入上下文的消息,此后,UI窗口运行在当前选中的输入上下文上。输入上下文必须包括UI窗口显示写作窗口、状态窗口等需要的所有信息。
UI窗口要求输入上下文,但是窗口不必自己更新输入上下文。当UI窗口需要更新输入上下文时,应该调用IMM函数,因为输入上下文由IMM函数管理,当输入上下文更新时,IMM和IME接收到通知消息。
例如,有时UI窗口当鼠标单击时需要改变输入上下文的转换模式,为了设置转换模式,UI窗口调用ImmSetConversionMode函数,该函数为NotifyIME生成一个通知消息并发送WM_IME_NOTIFY消息到UI窗口,如果UI窗口改变转换模式的显示,UI窗口会等待处理WM_IME_NOTIFY消息。
6、UI窗口的部件
UI窗口可以根据输入上下文注册和显示写作窗口和状态窗口,UI窗口的部件类的窗口风格必须包括CS_IME。UI窗口的一个窗口实例从当前输入上下文接收例如写作字符串、字体、位置等信息,当应用程序的一个窗口获得焦点时,系统获取该窗口自己的输入上下文并将当前输入上下文传递给UI窗口,系统发送WM_IME_SETCONTEXT消息和输入上下文的句柄给应用程序,应用程序传递该消息给UI窗口。如果当前输入上下文被更新,UI窗口应该重新绘制写作窗口,无论何时输入上下文改变,UI窗口都应该显示正确的写作窗口,可以保证IME的状态。
UI窗口可以创建子窗口或者弹出式窗口显示状态、写作字符串或者候选字列表,这些窗口必须是UI窗口的附属窗口,而且必须创建为不可接收输入(Disable)窗口,任何IME创建的窗口都不应该获取焦点。
三、输入上下文
1、缺省输入上下文
缺省情况下系统给每个线程一个输入上下文,该输入上下文被线程的所有无IME支持窗口共享。
2、输入上下文与窗口的交互
应用程序的一个窗口可以使用窗口句柄与输入上下文交互以维护任何IME状态,包括中间写作字符串。一旦应用程序使得输入上下文与窗口句柄交互,无论何时窗口被激活,系统自动选中输入上下文。使用这个特点,应用程序可以轻松地完成Windows 3.1下必须的复杂切换处理。
3、使用输入上下文
当应用程序或者系统创建新的输入上下文时,系统准备新的输入上下文,新的输入上下文已经包括IMCC,这个IMC的部件由hCompStr、hCandInfo、hGuideLine、hPrivate和hMsgBuf组成。IME基本上不需要创建输入上下文和输入上下文的部件,不过IME可以改变它们的大小,可以通过锁定它们查找到部件的指针。
⑴存取HIMC
为了存取输入上下文,IME必须调用ImmLockIMC函数以查找到输入上下文的指针,ImmLockIMC函数给IMC增加imm锁定计数,ImmUnlockIMC函数减少之。
⑵存取HIMCC
为了存取输入上下文中的一个部件,IME必须调用ImmLockIMCC函数获取IMCC的指针,ImmLockIMCC函数给IMCC增加imm锁定计数,ImmUnlockIMCC函数减少之,ImmReSizeIMCC函数可以修改IMCC的大小以指定新的大小。
某些情况下,IME可能需要自己创建输入上下文的一个部件,这种情况下,IME可以调用ImmCreateIMCC函数获取IMCC的句柄,这个IMCC可以是INPUTCONTEXT结构的成员(hCompStr、hCandInfo、hGuideLine、hPrivate或者hMsgBuf)。
ImmDestroyIMCC清除输入上下文的一个部件。
⑶怎样使用输入上下文
下面的实例显示了怎样使用输入上下文
LPINPUTCONTEXT lpIMC;
LPCOMOSITIONSTRING lpCompStr;
HIMCC hMyCompStr;
if (hIMC) { // It is not NULL context.
lpIMC = ImmLockIMC(hIMC);
if (!lpIMC) {
MyError( "Can not lock hIMC");
return FALSE;
}
// Use lpIMC->hCompStr.
lpCompStr = (LPCOMPOSITIONSTRING) ImmLockIMCC(lpIMC->hCompStr);
// Access lpCompStr.
ImmUnlockIMCC(lpIMC->hCompStr);
// ReSize lpIMC->hCompStr.
if (!(hMyCompStr = ImmReSizeIMCC(lpIMC->hCompStr,dwNewSize)) {
MyError("Can not resize hCompStr");
ImmUnlockIMC(hIMC);
return FALSE;
}
lpIMC->hCompStr = hMyCompStr;
ImmUnlockIMC(hIMC);
}
四、生成消息
IME需要生成IME消息。当IME开始转换时,IME必须生成WM_IME_STARTCOMPOSITION消息,如果IME改变了写作字符串,IME必须生成WM_IME_COMPOSITION消息,IME引发的事件导致生成消息给与输入上下文进行交互的窗口。IME基本上使用ImeToAsciiEx函数参数提供的lpdwTransKey缓冲区生成消息,当ImeToAsciiEx函数被调用时IME存储消息到lpdwTransKey缓冲区中,不过即使ImeToAsciiEx函数没有
被调用,IME也可以生成消息给使用输入上下文的消息缓冲区与输入上下文交互的窗口。输入上下文有一个内存块的句柄作为消息缓冲区,IME存储消息到被消息缓冲区句柄提供的内存块中,以后IME调用ImmGenerateMessage函数,ImmGenerateMessage函数发送保存在消息缓冲区中的消息到适当的窗口。
1、在ImeToAsciiEx函数中使用消息缓冲区
下面的实例显示了怎样通过传递缓冲区到ImeToAsciiEx函数生成消息:
UINT ImeToAsciiEx(uVirKey, uScanCode, lpbKeyState, lpdwTransBuf,
fuState , hIMC )
{
DWORD dwMyNumMsg = 0;
.
.
.
// Set the messages that the IME needs to generate.
*lpdwTransBuf++ = (DWORD) msg;
*lpdwTransBuf++ = (DWORD) wParam;
*lpdwTransBuf++ = (DWORD) lParam;
// Count the number of the messages that the IME needs to generate.
dwMyNumMsg++;
.
.
.
return dwMyNumMsg;
}
系统提供lpdwTransBuf参数指定的缓冲区,IMEToAsciiEx函数可以一次存储所有的消息到该缓冲区中,缓冲区的第一个双字给出存储在缓冲区中的消息个数。如果ImeToAsciiEx函数需要生成比这个给定的个数更多的消息,函数可以存储所有的消息到输入上下文的hMsgBuf域中,然后函数ImeToAsciiEx返回消息个数。当ImeToAsciiEx函数的返回值大于lpdwTransBuf中指定的值时,系统不从lpdwTransBuf中取出消息,系统查找作为ImeToAsciiEx函数参数传递的输入上下文中的hMsgBuf域。
2、使用消息缓冲区
下面的实例显示了怎样使用消息缓冲区:
MyGenerateMesage(HIMC hIMC, UINT msg, WPARAM wParam, LPARAMlParam)
{
LPINPUTCONTEXT lpIMC;
HGLOBAL hTemp;
LPDWORD lpdwMsgBuf;
DWORD dwMyNumMsg = 1;
// Lock the input context.
lpIMC = ImmLockIMC(hIMC);
if (!lpIMC)
// Error!
// re-allocate the memory bloack for the message buffer.
hTemp = ImmReSizeIMCC(lpIMC->hMsgBuf,
(lpIMC->dwNumMsgBuf + dwMyNumMsg) * sizeof(DWORD) * 3);
if (!hTemp)
// Error!
lpIMC->hMsgBuf = hTemp;
// Lock the memory for the message buffer.
lpdwMsgBuf = ImmLockIMCC(lpIMC->hMsgBuf);
if (!lpdwMsgBuf)
// Error!
lpdwNumMsgBuf += 3 * lpIMC->dwNumMsgBuf.
// Set the number of the messages.
lpIMC->dwNumMsgBuf += dwMyNumMsg;
// Set the messages that the IME needs to generate.
*lpdwMsgBuf++ = (DWORD) msg;
*lpdwMsgBuf++ = (DWORD) wParam;
*lpdwMsgBuf++ = (DWORD) lParam;
// Unlock the memory for the message buffer and the input context.
ImmUnlockIMCC(lpIMC->hMsgBuf);
ImmLockIMC(hIMC);
// Call ImmGenerateMessage function.
ImmGenerateMessage(hIMC);
}
3、WM_IME_COMPOSITION消息
当IME生成WM_IME_COMPOSITION消息时,IME指定lParam参数为GCS位。GCS位的意义是COMPOSITIONSTRING结构中的有效成员,即使IME没有更新,成员目前仍然有效,IME也会设置GCS位。
为IME定义服务
当IME生成WM_IME_COMPOSITION消息时,IME可能会立刻改变字符串、属性以及子句信息。IME使用下列定义:
GCS_COMP
GCS_COMPREAD
GCS_RESULT
GCS_RESULTREAD
五、关于ImeSetCompositionString函数
1、ImeSetCompositionString函数能力
如果IME没有ImeSetCompositionString函数能力,IME将不能在IMEINFO结构中指定任何SCS能力。如果IME可以处理ImeSetCompositionString函数,IME设置SCS_COMPSTR位。如果IME可以通过写作字符串生成解释(本文中的“解释”是单词“reading”的直译,真正意义可能是“原始输入的”,例如输入的汉语拼音字母字符串,下同)字符串,IME可以设置SCS_CAP_MAKEREAD位。
如果IME有SCS_CAP_COMPSTR能力,ImeSetCompositionString函数将被调用,IME从应用程序获取新的写作字符串并生成WM_IME_COMPOSITION消息。
如果IME有SCS_CAP_MAKEREAD能力,IME可以通过写作字符串建立解释字符串。
2、关于SCS_SETSTR
如果ImeSetCompositionString函数的dwIndex参数值为SCS_SETSTR,IME可以清除hIMC中的COMPOSITIONSTR结构中所有的域。
如果IME需要,IME可以更新候选信息并生成候选消息IMN_OPENCANDIDATE、IMN_CHANGECANDIDATE或者IMN_CLOSECANDIDATE。
如果ImeSetCompositionString函数的lpRead参数有效,IME应该通过lpRead参数中的解释字符串建立写作字符串,另外IME为新的写作字符串和lpRead参数中的解释字符串建立属性和子句信息,IME生成lParam参数为(GCS_COMP|GCS_COMPREAD)的WM_IME_COMPOSITION消息。有时IME需要自动确定建立上述信息,这种情况下,IME可以生成lParam参数以(GCS_RESULT|GCS_RESULTREAD)代替GCS_COMPxxx的消息。
如果ImeSetCompositionString函数的lpComp参数有效,IME应该通过lpComp参数中的写作字符串建立写作属性和子句信息,IME生成lParam参数为GCS_COMP的WM_IME_COMPOSITON消息。如果IME有SCS_CAP_MAKEREAD能力,IME应该同时建立解释字符串,IME生成lParam参数为(GCS_COMP|GCS_COMPREAD)的WM_IME_COMPOSITION消息。有时IME需要自动确定建立上述信息,这种情况下,IME可以生成lParam参数以(GCS_RESULT|GCS_RESULTREAD)代替GCS_COMPxxx的消息。
如果lpRead参数和lpComp参数同时有效,IME应该建立写作字符串和解释字符串,这时IME不需要完全按照lpRead参数和lpComp参数。如果IME不能建立应用程序指定的lpRead参数和lpComp参数之间的关系,IME应该修正写作字符串,IME为新的写作字符串和lpRead参数指定的解释字符串建立属性和子句信息,IME生成lParam参数为(GCS_COMP|GCS_COMPREAD)的WM_IME_COMPOSITION消息。有时IME需要自动完成建立上述信息,这种情况下,IME可以生成lParam参数以(GCS_RESULT|GCS_RESULTREAD)代替GCS_COMPxxx的消息。
3、关于SCS_CHANGEATTR
SCS_CHANGEATTR只影响属性信息,IME不应该更新写作字符串、写作字符串的子句信息、写作字符串的解释以及写作字符串的解释子句信息。
首先IME检查新的属性并判断新的属性是否可用,然后IME设置属性到hIMC中的COMPOSITIONSTRING结构中,最后IME生成WM_IME_COMPOSITION消息。
如果需要,IME可以更新候选信息并生成候选消息IMN_OPENCANDIDATE、IMN_CHANGECANDIDATA、IMN_CLOSECANDIDATE。IME不能确定写作字符串。
如果ImeSetCompositionString函数的lpRead参数有效,IME使用lpRead参数中的新属性。IME也应该为当前写作字符串建立写作字符串的新属性,这时子句信息不被修改。
写作字符串、属性、子句信息、解释字符串、解释属性和解释子句信息必须有效。IME生成lParam参数为(GCS_COMP|GCS_COMPREAD)的WM_IME_COMPOSITION消息,如果IME不能接受lpComp参数中的新属性,IME不需要生成任何消息并返回FALSE。
如果ImeSetCompositionString函数的lpComp参数有效,IME使用lpComp参数中的新属性,这时子句信息不被修改。
如果IME有SCS_CAP_MAKEREAD能力,并且解释字符串有效,IME应该为当前写作字符串的解释建立写作字符串的解释的新属性。
如果lpRead参数和lpComp参数同时有效,并且如果IME能够接受新的信息,IME设置新的信息到hIMC中的COMPOSITION结构中并生成lParam参数为(GCS_COMP|GCS_COMPREAD)的WM_IME_COMPOSITION消息。
4、关于SCS_CHANGECLAUSE
SCS_CHANGECLAUSE影响写作字符串和写作字符串的解释的字符串和属性。
如果需要,IME可以更新候选信息并生成候选消息IMN_OPENCANDIDATE、IMN_CHANGECANDIDATA、IMN_CLOSECANDIDATE。IME不能确定写作字符串。
如果ImeSetCompositionString函数的lpRead参数有效,IME使用lpRead参数中的解释子句信息。IME必须修正写作字符串的解释的属性,IME可以更新写作字符串、属性和写作字符串的子句信息,IME生成lParam参数为(GCS_COMP|GCS_COMPREAD)的WM_IME_COMPOSITION消息。
如果ImeSetCompositionString函数的lpComp参数有效,IME使用新的子句信息。IME必须修正写作字符串和写作字符串的属性,IME可以更新解释属性和解释的子句信息,IME生成lParam参数为(GCS_COMP|GCS_COMPREAD)的WM_IME_COMPOSITION消息。
如果lpRead参数和lpComp参数同时有效,并且如果IME能够接受新的信息,IME设置新的信息到hIMC中的COMPOSITION结构中并生成lParam参数为(GCS_COMP|GCS_COMPREAD)的WM_IME_COMPOSITION消息。
六、软键盘
1、关于软键盘
一些IME有特殊的解释字符,例如一个IME可能使用注音符号作为解释字符(这里指台湾中文版Windows 95,即CWin95中的注音符号,PWin95中可能指汉语拼音字母或者音调符号——译者注),另一个IME使用了一些字根符号(原文单词是“radials”,但实际可能是“radicals”——译者注)作为解释字符,IME可以提供一个软键盘显示这些特殊解释字符使得用户不必逐键记忆解释字符。
IME需要根据不同的变换状态改变键表示的解释字符,使用软键盘可以通知用户键的改变。在选择候选字时,IME可以只显示那些选择键给用户。
2、使用软键盘
IME可能需要为软键盘创建一个更好的用户界面,或者可能需要系统预定义的软键盘,如果IME需要使用系统预定义的软键盘,IME需要在调用ImeInquire函数时将IMEINFO结构的fdwUICaps成员指定为UI_CAP_SOFTKBD。
IME可以调用ImmCreateSoftKeyboard函数为软键盘创建窗口,还可以调用ImmShowSoftKeyboard函数显示或者隐藏软键盘。软键盘窗口是UI窗口的一个组件,所以软键盘窗口应该附属于UI窗口。
IME可能需要决定是否在无论何时焦点移走的情况下删除窗口,软键盘可能占有一些系统资源(可能需要释放——译者注)
软键盘有不同的类型,一种类型可能是为特定的国家或者特定的目的设计的。为每一种类型的软键盘改变解释字符的方式可能不同,有两种改变解释字符的方式:使用IMC_SETSOFKBDSUBTYPE或者IMC_SETSOFKBDDATA。不同类型的软键盘有不同的窗口过程并存在不同的用户界面给用户。
七、IME接口
在Windows 95中,IME与设备驱动程序一样是动态链接库(DLL),输入法管理器(IMM)应该处理所有安装的IME。因为IME在运行时是可以改变的,不需要重新启动系统,IMM有一个结构用于维护每一个IME的所有入口点。IME函数列表是所有远东版本Windows 95公共IME功能函数的描述,这些函数不应该在应用程序中直接调用。
UI窗口中的IMM函数
下面是可以在UI窗口中调用的IMM函数:
ImmGetCompositionWindow
ImmSetCompositionWindow
ImmGetCandidateWindow
ImmSetCandidateWindow
ImmGetCompositionString
ImmSetCompositionString
ImmGetCompositionFont
ImmSetCompositionFont
ImmGetNumCandidateList
ImmGetCandidateList
ImmGetGuideLine
ImmGetConversionStatus
ImmGetConversionList
ImmGetOpenStatus
ImmSetConversionStatus
ImmSetOpenStatus
ImmNotifyIME
ImmCreateSoftKeyboard
ImmDestroySoftKeyboard
ImmShowSoftKeyboard