关闭

Win32多语言IME开发概述

792人阅读 评论(0) 收藏 举报
分类:

一、概  述

从Windows 95和Windows NT 4.0 开始,输入法编辑器(IMEs)是作为一个动态连接库(DLL)来提供的。与Windows 3.1远东版本相比,每个运行的IME相当于多语言键盘布局的一种。与Windows 3.1相比,Win32多语言输入法管理器(IMM)和输入法编辑器(IME)构架具有下列优势:

●运行时相当于多语言环境的一个组件;

●为每一个应用程序任务提供多样化的输入上下文;

●每个应用程序线程保持一个活动的IME;

●为应用程序消息循环提供信息(不能改变消息次序);

●为IME支持型应用程序和IME不支持型应用程序提供强有力的支持。

要全部利用这些特性,应用程序必须支持Win32 IMM/IME 应用程序接口(API)。

为了最大限度的保持Windows 95与 Windows NT 4.0 IMEs的兼容,Windows 98和 Windows 2000在设计中没有做显著的改变。不过,为了提高系统性能,新的特性已经增加。

IME开发者必须使用DDK中的immdev.h,其为SDK之imm.h或其他开发工具的集合。

1、Windows 98和Windows 2000 IMM/IME

Windows 98和Windows 2000 IMM/IME 构架保持了Windows 95和Windows NT 4.0的设计。不过,为了支持IME智能开发和IME与Windows的融合,有些构成已做了修改。这些修改包括:

(1)新的IME函数允许应用程序与IMM/IME相关联。其包括:

ImmAssociateContextEx

ImmDisableIME

ImmGetImeMenuItems

(2)新的函数允许IME与IMM及应用程序相关联。其包括:

ImmRequestMessage

ImeGetImeMenuItems

(3)支持复原。这是一个新特性,它允许你复原一个已经插入应用程序文档里的字符串。该功能将帮助智能IMEs获得有关转换结果的更多信息,并改善转换的准确性和性能。该特性需要应用程序和IME的配合。

(4)增加IME菜单项到系统笔图标的上下文菜单。该新特性为IME提供了一种将其菜单项插入和应用系统栏系统图标上下文菜单的方法。

(5)新的IME标志位。下列新的标志位支持新的转换模式:

IME_CMODE_FIXED

IME_SMODE_CONVERSION

IME_PROP_COMPLEDE_ON_UNSELECT

(6)IME编辑控制功能增强。通过两个新的编辑控制消息EM_SETIMESTATUS和EM_GETIMESTATUS,应用程序可以管理IME编辑控制状态。

(7)改变IME笔图标和工具提示。通过三个新消息INDICM_SETIMEICON、 INDICM_SETIMETOOLTIPS和 INDICM_REMOVEDEFAULTMENUITEMS,IME可以改变系统任务栏里的系统笔图标和工具提示。

(8)两个IMR消息。IMR_QUERYCHARPOSITION和 IMR_DOCUMENTFEED帮助IME和应用程序传递位置和文档信息。

●64位兼容:在IMM32中增加了两个新的结构((TRANSMSG和 TRANSMSGLIST),使用它们可以通过INPUTCONTEXT和ImeToAsciiEx接收IME转换消息。

●IME_PROP_ACCEPT_WIDE_VKEY:这是Windows 2000中增加的一个新属性。这样,IME就可以处理被SendInput API引入的Unicode字符。ImeProcessKey和ImeToAsciiEx也被更新以便能够处理引入的Unicode字符。引入Unicode字符能够被应用程序和用户输入设备放入输入队列的Unicode字符串中。

2、IME结构

Win32 IME必须提供两个组成部分。一个是IME转换接口,另一个是IME用户接口。IME转换接口由一组IME模块引出函数提供。这些函数被IMM所调用。IME用户接口由一组窗口提供。这些窗口接收消息并为IME提供用户界面。

3、应用程序类型

Win32 IME 构架一个主要的特性,就是在应用程序和IME之间提供更好的通讯逻辑。下例说明了应用程序与IME的复杂关系:

1、IME不支持型应用程序。这类应用程序对IME不实施控制。但是,只要应用程序接收BDCS字符,用户就可以利用IME向应用程序输入任何BDCS字符。

2、IME半支持型应用程序。这类应用程序只控制IME的一些上下文,如打开或关闭IME、组码窗口形状等。但是,它不显示IME的任何用户界面。

3、IME全支持型应用程序。这类应用程序负责通过IME显示给应用程序的任何信息。

在Windows 95和Windows NT 4.0及以后版本中,IME不支持型应用程序拥有一个默认的IME窗口和一个默认的输入上下文。

IME半支持型应用程序使用系统预定义的IME类创建自己的IME窗口并调用它。其可以处理也可以不处理它的输入上下文。

IME全支持型应用程序自己处理输入上下文,并显示输入上下文给出的任何信息,不使用IME窗口。

二、IME用户接口

IME用户界面包括IME窗口、UI窗口(用户界面窗口)及UI窗口组件。

1、特征

IME类是实现任何IME用户界面部分的预定义全局类。一个标准典型的IME类与其他公共控制类相同。其窗口实例可以通过CreateWindowEx函数创建。与静态控制一样,IME类窗口不能响应用户输入。但是,可以接收不同类型的控制消息,实现全部的IME用户接口功能。应用程序可以使用IME类创建自己的IME窗口,也可以使用ImmGetDefaultIMEWnd函数获得默认IME窗口。与Windows 3.1相比,一个能够控制IME及其窗口句柄的IME支持型应用程序,具有以下优势:

●IME包含候选列表窗口。每一个应用程序可以有自己的用户界面窗口实例,这样用户可以中止任何操作并切换到其他应用程序。在Windows 3.1日本版中,用户切换到其他应用程序之前,必须首先退出当前操作。

●由于IME用户界面窗口包含有关应用程序窗口句柄的信息,其可以为应用程序提供一些默认行为。例如IME窗口自动定位,窗口插字符位置自动跟随,应用程序模式指示等。

即使系统仅仅提供了一个IME类,IME窗口仍然有两种类型。一种是系统创建给DefWindowProc函数的,其特别适合IME不支持型应用程序。DefWindowProc函数的用户接口被线程的所有无IME支持窗口所共享。在本文档中,这种IME窗口称为默认IME窗口。另一种是由IME支持型应用程序创建的,在本文档中,这种IME窗口称为应用程序IME窗口。

2、默认IME窗口和应用程序IME窗口

当线程初始化时系统创建一个默认IME窗口,线程自动获取该默认IME窗口。该默认IME窗口处理IME不支持型应用程序的任何用户接口。

当IME或IMM生成WM_IME_XXX消息时,IME不支持型应用程序传递IME消息到DefWindowProc函数,DefWindowProc发送需要的消息到默认的IME窗口,使IME不支持型应用程序实现IME用户接口提供的默认行为。一个IME支持型应用程序,当它不从IME捕获消息时,也可以使用IME默认窗口,需要时可以使用自己的应用程序IME窗口。

3、IME类

Win32系统在系统里提供一个IME类。该类由用户定义,如同预定义的Edit类。系统IME类处理全部的IME用户接口和来自IME、应用程序及IMM函数的全部控制消息。应用程序可以使用该类创建自己的IME用户界面。系统IME类自身不能被任何IME所替代,但保留作为一个预定义类。

该类有一个用于实际处理WM_IME_SELECT消息的窗口过程。该消息有一个新选择IME的键盘布局句柄(hKL)。系统IME类在所有IME及键盘布局中查找定义的类名。使用该类名,系统IME类创建当前活动IME的用户界面窗口。

4、IME用户界面类

在此设计中,每个IME必须预先向系统注册自己的UI类。UI类为每个IME提供具体功能。当IME附加到进程上时,IME可以注册自己的UI类,即当DLLEntry以DLL_PROCESS_ATTACH参数调用时。IME注册UI类时,应给lpszClassName参数设置一个UI类名,其也为ImeInquire函数的第二个参数。

UI类应当以CS_IME注册其窗口样式,使每个应用程序在IME类中都能使用它。UI类名(包括空终结符)可以由多达16个字符组成,这一规定可能会延续到Windows的未来版本。

UI类的cbWndExtra字段必须为2*sizeof(LONG),这个窗口附加区的作用由系统指定(例如,IMMGWL_IMC和IMMGWL_PRIVATE)。

在应用程序工作期间,IME可以注册任何类并创建任何窗口。

下面的示例显示如何注册IME UI类:

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)szCompClassName;

wc.hbrBackground  = NULL;

if(!RegisterClass((LPWNDCLASS)&wc ))

return FALSE;

break;

case DLL_PROCESS_DETACH:

UnregisterClass(szUIClassName,hInst);

UnregisterClass(szCompClassName,hInst);

break;

}

return TRUE;

}

5、UI窗口

IME类对应的IME窗口由应用程序或系统创建。IME窗口创建时,UI窗口由IME自身提供创建并被IME窗口所拥有。

每个UI窗口包含当前输入上下文。当UI窗口收到WM_IME_XXX消息时,可以通过调用GetWindowLong函数和IMMGWL_IMC参数获得该输入上下文。UI窗口能应用该输入上下文处理消息。UI窗口过程可以在除响应WM_CREATE消息以外的任何时间通过GetWindowLong函数和IMMGWL_IMC获取输入上下文。

IME不能改变UI窗口的cbWndExtra大小。当IME需要使用窗口实例的附加字节时,UI窗口可以使用IMMGWL_PRIVATE参数值调用SetWindowLong和GetWindowLong函数进行。该IMMGWL_PRIVATE提供一个访问窗口附加区的LONG类型值。如果UI窗口需要使用比LONG类型值更大的附加数据,UI窗口可以保存一个内存块句柄到IMMGWL_PRIVATE附加区。

UI窗口过程能够使用DefWindowProc,但不能将使用WM_IME_XXX消息传递给DefWindowProc。即使消息没有被UI窗口处理,UI窗口也不允许将其传递给DefWindowProc。

下例表明如何分配和使用一个私有内存块:

LRESULT UIWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)

{

HIMC hIMC;

HGLOBAL hMyExtra;

 

switch(msg){

case WM_CREATE:

//Allocate the memory block 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窗口需要更新输入上下文时,它必须调用IMM函数。因为输入上下文是由IMM管理的,当输入上下文改变时,IMM和IME将会接收到通知消息。

例如,当用户单击鼠标时,UI窗口需要改变输入上下文转换模式。此时,UI窗口必须调用ImmSetConversionMode。ImmSetConversionMode函数为NotifyIME函数和UI窗口创建一个通知消息WM_IME_NOTIFY。如果UI窗口需要改变转换模式的显示,它必须等待WM_IME_NOTIFY消息。

6、UI窗口组件

UI窗口能够注册和显示当前输入上下文所涉及的组码窗口和状态窗口。UI窗口组件的窗口类样式必须包含CS_IME位。UI窗口的一个窗口实例,从当前输入上下文返回组码串、字体、位置等相关信息。

当应用程序的一个窗口获得焦点时,系统获取该窗口的输入上下文并将当前输入上下文设置到UI窗口。接着,系统发送WM_IME_SETCONTEXT消息和输入上下文句柄到应用程序,应用程序传递该消息给UI窗口。如果当前输入上下文被其他输入上下文替换更新,UI窗口必须重绘组码窗口。无论何时,当前输入上下文改变,UI窗口都会显示与当前输入上下文相适应的组码窗口,以保证IME的状态。

UI窗口可以创建子窗口或弹出式窗口显示状态、组码串或候选列表。然而,这些窗口都必须为UI窗口所拥有,并创建为Disable(无效窗口,不能接收用户输入)窗口。任何被IME创建的窗口都不能获得焦点。

三、IME输入上下文

每个窗口联系一个输入上下文。IMM使用输入上下文维护IME状态、数据等等,并使IME与应用程序相联系。

1、默认输入上下文

默认情况下,系统为每个线程创建一个默认的输入上下文。该输入上下文被线程的所有无IME支持窗口所共享。

2、应用程序创建输入上下文

一个应用程序窗口可以通过其窗口句柄和输入上下文去维护IME的所有状态,包括中间的组码串。一旦应用程序使一个输入上下文与一个窗口句柄发生联系,无论何时系统会自动选定该上下文并激活该窗口。这样,应用程序就避免了复杂的焦点切换处理。

3、使用输入上下文

当应用程序或系统创建一个新的输入上下文时,系统准备新的输入上下文与IMC组件(IMCC)。这些IMC组件包括hCompStr、 hCandInfo, hGuideLine、hPrivate和hMsgBuf。IME基本上不需要创建输入上下文和输入上下文组件。IME可以改变它们的大小,并锁定它们以获得它们的指针。

4、访问HIMC

当IME访问输入上下文时,IME必须调用ImmLockIMC函数获得输入上下文指针。ImmLockIMC使IMM为IMC增加锁定数,而ImmUnlcokIMC使IMM为IMC减少锁定数。

5、访问HIMCC

当IME访问输入上下文组件时,IME必须调用ImmLockIMCC函数获得IMCC指针。ImmLockIMCC使IMM为IMCC增加锁定数,而ImmUnlockIMCC使IMM为IMCC减少锁定数。ImmReSizeIMCC可以重新调整HIMC的大小。

有时,IME需要在输入上下文中创建一个新的组件,IME可以调用ImmCreateIMCC来实现。销毁一个新建的输入上下文组件,应该调用ImmDestroyIMCC来进行。

下例显示如何访问IMCC并改变组件大小:

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可以有两种方法生成消息:一种是使用ImeToAsciiEx函数提供的lpdwTransKey缓冲区,另一种是通过调用ImmGenerateMessage函数。

1、使用lpTransMsgList生成消息

事件开始,由IME实现生成消息给与输入上下文相联系的窗口。基本上,IME使用ImeToAsciiEx提供的lpTransMsgList类型参数生成消息。当ImeToAsciiEx调用时,IME保存消息到lpTransMsgList缓冲区。

缓冲区由系统提供,在ImeToAsciiEx中以lpTransMsgList表示。该函数可以同时保存多个消息在该缓冲区。缓冲区的第一个双字给定可以保存的消息个数。如果ImeToAsciiEx需要生成比这个给定消息数更多的消息,ImeToAsciiEx可以放置所有消息到输入上下文的hMsgBuf中,并返回消息个数。

当ImeToAsciiEx返回值大于lpTransMsgList中的指定值时,系统不从lpTransMsgList中取出消息,而是在输入上下文中查找hMsgBuf,作为ImeToAsciiEx参数传递。

以下代码示例是ImeToAsciiEx生成消息的实现:

UINT ImeToAsciiEx(uVirKey, uScanCode,

lpbKeyState, lpTransMsgList, fuState,  hIMC)

{

DWORD dwMyNumMsg = 0;

. . .

 

// Set the messages that the IME wants to generate.

pTransMsgList->TransMsg[0].message =msg;

pTransMsgList->TransMsg[0].wParam = wParam;

pTransMsgList->TransMsg[0].lParam = lParam;

 

// Count the number of the messages that the IME wants to generate.

dwMyNumMsg++;

 

. . .

 

return dwMyNumMsg;

}

2、使用消息缓冲区生成消息

即使不调用ImeToAsciiEx,也可以通过使用输入上下文的消息缓冲区为与输入上下文相联系的窗口生成消息。该消息缓冲区的操作与一个内存块句柄一样。IME保存消息到该内存块,然后调用ImmGenerateMessage函数,保存在消息缓冲区中的消息就会发送到适当的窗口。

下述代码示例是ImmGenerateMessage生成消息的实现:

MyGenerateMesage(HIMC hIMC, UINT msg, WPARAM wParam, LPARAMlParam)

{

LPINPUTCONTEXT lpIMC;

HGLOBAL hTemp;

LPTRANSMSG lpTransMsg;

DWORD dwMyNumMsg = 1;

 

// Lock the Input Context.

lpIMC = ImmLockIMC(hIMC);

if (!lpIMC) ….. // Error!

// re-allocate the memory block for the message buffer.

hTemp = ImmReSizeIMCC(lpIMC->hMsgBuf,

(lpIMC->dwNumMsgBuf + dwMyNumMsg) *

sizeof(TRANSMSG));

if (!hTemp) ….// Error!

lpIMC->hMsgBuf = hTemp;

// Lock the memory for the message buffer.

lpTransMsg = ImmLockIMCC(lpIMC->hMsgBuf);

if (!lpTransMsg) …. // Error!

 

// Set the messages that the IME wants to generate.

lpTransMsg[lpIMC->dwNumMsg].message = msg;

lpTransMsg[lpIMC->dwNumMsg].wParam = wParam;

lpTransMsg[lpIMC->dwNumMsg].lParam = lParam;

 

// Set the number of the messages.

lpIMC->dwNumMsgBuf += dwMyNumMsg;

 

 

// 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为GSC位。GSC位接着通知COMPOSITIONSTRING结构的有效成员。如果IME没有更新,只要该成员有效,IME就可以设置GCS位。

当IME生成WM_IME_COMPOSITION消息时,IME也可以同时改变串属性和子句信息。

五、软键盘

软键盘IME的一个特殊窗口显示。因为一些IME有特殊的读入字符,IME可以提供一个软键盘显示这些特殊的读入字符。这样,用户不必记忆每个读入字符键。例如,一个IME可以使用bo、po、mo、fo(拼音声母,这里指拼音符号)为它的读入字符,而另一个IME可能使用一些字根符号作为它的读入字符。(这里的读入字符,相当于输入字符,即输入到应用程序窗口的字符—译者注)。

根据转换状态,IME可以改变键所表示的读入字符,并将这些键的改变通知用户。例如,当选择候选字符时,IME可以只显示选择键给用户。

IME可以创建自己的软键盘用户界面,也可以使用系统预定义的软键盘。如果IME需要使用系统预定义的软键盘,它必须在调用ImeInquire函数时,将IMEINFO结构的fdwUICaps成员指定为UI_CAP_SOFTKBD。

IME必须调用ImmCreateSoftKeyboard函数创建软键盘窗口。它也可以调用ImmShowSoftKeyboard函数显示或隐藏软键盘。因为软键盘窗口是UI窗口的一个组件,其物主也应该是UI窗口。

软键盘有各种类型。每一种类型都可能是为特定的国家或特殊的用途而设计。IME可以通过两种方法改变软键盘上的读入字符:IMC_SETSOFTKBDSUBTYPE或IMC_SETSOFTKBDDATA

六、复原

复原是Windows 98和Windows 2000一个新的功能。它提供恢复一个已插入应用程序文档的字符串的能力。确切的说,无论是什么字符串,IME命令识别这个字符串,转换它的读入或键入信息,然后显示到候选列表。

新的智能IME能够识别和解释一个完整的句子,当IME较好的提供一个字符串的相关信息时,如全句和串分割,其就可以较好的、准确的完成转换功能。例如,应提供一个整句而不是只提供复原字符串,IME可以复原字符串而不需要首先转换到读入或键入信息。

编辑后的断句比编辑前更困难。因为断句将使未断句串的很多信息丢失。比如读入、短语、词性。复原获取这些信息后,制造编辑后的断句就如同断句之前一样容易。用户将可以在候选列表选择不同的同音字,改变短语中断让IME再次分析,等等。

RECONVERTSTRING结构可以通过其dwStartOffset和dwLen成员保存复原串的整句和位置。如果dwStartOffset是零且dwLen为串长度,则IME复原整个串。

1、简单复原

当目标串和组码串是相同的整串时,其复原为简单复原。在这种情况下,dwCompStrOffset和dwTargetStrOffset为零,dwStrLen、 dwCompStrLen和dwTargetStrLen是相同的值。IME将通过RECONVERTSTRING结构获取和提供整串的组码串,并将其设置目标子句为转换结果。

2、标准复原

一个高效的转换结果,应用程序必须提供RECONVERTSTRING结构和字符串信息。在这种情况下,组码串不是整串,但却是相同的目标串。IME可以通过整串转换组码串,并设置目标子句为它的转换结果。

3、高级复原

应用程序可以设置一个与组码串不同的目标串,目标串(或目标串一部分)即列入目标子句并被IME优先。目标串在RECONVERTSTRING结构里必须是组码串的一部分。当应用程序在复原期间不需要改变用户焦点时,目标串将会被指定。IME可以引用它。

4、IME取消复原

当用户取消组码串产生的复原时,IME应该确定原复原串。否则,应用程序将释放字符串。

5、SCS_SETRECONVERTSTRING和SCS_QUERYRECONVERTSTRING标志

应用程序可以通过调用ImmSetCompositionString请求IME复原字符串。它可以使用SCS_SETSTR或SCS_SETRECONVERTSTRING标志创建一个新的组码串。然而,为了提高转换效率,应用程序可以通过使用SCS_SETRECONVERTSTRING,将RECONVERTSTRING传递到IME。

开始,应用程序应该调用ImmSetCompositionString和SCS_QUERYRECONVERTSTRING。选定的IME将调整给定的RECONVERTSTRING结构以适于复原。应用程序接着调用ImmSetCompositionString和SCS_SETRECONVERTSTRING去请求IME生成一个新的组码串。如果应用程序通过调用SCS_QUERYRECONVERTSTRING请求IME调整RECONVERTSTRING结构,复原才能高效的完成。

SCS_SETRECONVERTSTRING 或SCS_QUERYRECONVERTSTRING只能使用在IME具有SCS_CAP_SETRECONVERTSTRING属性的情况下。该属性可以通过使用ImmGetProperty函数来查找。

6、IMR_RECONVERTSTRING和IMR_CONFIRMRECONVERTSTRING消息

当IME需要复原时,它可以请求应用程序提供将要复原的串。例如,当用户按复原键或选定状态窗口上的复原按钮时,IME发送WM_IME_REQUEST消息与IMR_RECONVERTSTRING返回目标串。开始,为了返回对RECONVERTSTRING结构大小的要求,IME必须发送WM_IME_REQUEST消息与NULL的lParam参数。然后,IME准备一个接收目标串的缓冲区,并再次发送WM_IME_REQUEST消息与以缓冲区指针对内容的lParam参数。

然后,应用程序处理IMR_RECONVERTSTRING。IME可以或不可以调整应用程序给定的RECONVERTSTRING结构。最后,IME发送WM_IME_REQUEST消息与IMR_CONFIRMRECONVERTSTRING,确认RECONVERTSTRING结构。

如果应用程序为IMR_CONFIRMRECONVERTSTRING返回真,IME在IMR_CONFIRMRECONVERTSTRING消息里以RECONVERTSTRING结构为基础生成新的组码串。如果应用程序返回假,IME在IMR_CONFIRMRECONVERTSTRING消息里以应用程序给定的原RECONVERTSTRING结构为基础生成新的组码串。在IMR_CONFIRMRECONVERTSTRING之前,IME将不为复原生成组码串。

给定串不应该被SCS_QUERYRECONVERTSTRING或 IMR_CONFIRMRECONVERTSTRING所改变。IME只能改变和重新确认CompStrOffset、 CompStrLen、 TargetStrOffset和TargetStrLen。

七、IME菜单功能

设置IME菜单功能的目的是为了减少系统任务栏IME相关图标的个数。这是Windows 98和Windows 2000的一个新特性。

当当前键盘布局是一个IME时,Windows系统程序将在任务栏安装两个图标。一个图标是系统ML图标,用于指示当前键盘布局。另一个是系统笔图标,用于聚焦窗口的IME状态。

通常,一个IME在任务栏放置一个另外的图标。上下文菜单使这个图标完全依赖于IME。所有在任务栏里的IME图标,都是为了给用户提供访问IME特定功能的快捷方式。然而,可能有三个或更多的与IME相关的图标需要用户去处理。

如果系统提供一种方式,将IME插入IME菜单项,并通过系统笔图标调用IME菜单。这样,IME就不需要在任务栏额外添加它的图标。

IMM调用IME函数ImeGetImeMenuItems获得IME菜单项。

应用程序可以使用ImmGetImeMenuItems获得IME的特定菜单项,并添加到上下文菜单。通过调用ImmNotify ,可以处理被选择的IME项。

IME菜单通知:当应用程序需要处理一个IME的菜单项时,它可以调用ImmNotifyIME。当菜单项对应的IME被选中时,NotifyIME将其调用到焦点线程之下。

八、IME帮助文件

IME帮助文件是Windows 98和Windows NT里增加的一个新功能。右击系统笔图标菜单有两个菜单项。一个是IME系统设置,用于改变焦点线程选定的IME设置,另一个菜单项是一个从未启用的在线帮助文件。因为该菜单项总是灰色的。该菜单项的目的是显示一个IME在线帮助。不过,因为系统没有提供IME指定IME帮助文件名的方法,系统任务栏程序不能显示它。

IME_ESC_GETHELPFILENAME:该换码允许IME指定它的帮助文件名。由于需要从函数返回,lpData(LPTSTR)必须是IME帮助文件的全路径文件名。

如果该帮助文件为HTML格式,请确认帮助文件的扩展名为.chm,这有助于Windows用户的起动。

九、IME指示器管理

通过使用一组在Windows 98和Windows 2000的预定义消息,IME可以改变系统任务栏上笔图标的图标和工具提示字符串。

1、指示器窗口

IME可以通过FindWindow和INDICATOR_CLASS获得指示器窗口句柄。

// 返回指标器窗口句柄

hwndIndicator = FindWindow(INDICATOR_CLASS, NULL);

if (!hwndIndicator)

{

// 没有指示器窗口,托盘中没有系统笔图标

return FALSE;

}

// 调用PostMessage函数改变笔图标

PostMessage(hwndIndicator, INDICM_SETIMEICON, nIconIndex, hMyKL);

注意:由于任务栏管理器内部设计的要求,IME必须使用PostMessage发送INDICM_XXX消息。

2、INDICM_XXX消息

IME可以发送下列消息到指示器窗口去完成相应的任务。

INDICM_SETIMEICON

INDICM_SETIMETOOLTIPS

INDICM_REMOVEDEFAULTMENUITEMS

 

十、Windows NT和 Windows 2000问题

下列主题首先叙述与Windows NT/2000相关的特殊问题。不过,有些也可能与Windows 98相同。

1、IME与本地化语言的兼容性

Windows 2000在任何的本地化语言版本中具有功能齐全的IME支持。也就是说,IME可以安装和使用任何Windows 2000语言。IME开发者应该测试其工作环境。该新特性同样需要IME开发者准备IME帮助目录,包括适合的字符集、字体信息,这样它才能在不同语言的操作系统中正确显示。

同样,IME开发者应该开发适用于Windows 2000的Unicode IME。Unicode IME将与Unicode应用程序一起工作在任何系统区域设置之下。对于非Unicode IME,用户必须改变系统区域设置,使其与IME支持的语言相同,以便使用它们。

2、Unicode接口

除ANSI版本的IMM/IME接口支持原来的Windows 95外,Windows NT、Windows 98均支持Unicode接口的IME。为了使Unicode接口与系统相联系,IME应该将IMEINFO结构的fdwProperty成员设置为IME_PROP_UNICODE。IMEINFO结构为ImeInquire函数的第一个参数。尽管ImeInquire的调用,是为应用程序进程的每个线程初始化IME的,但IME却为系统返回了一个IMEINFO结构。Windows 98支持除ImmIsUIMessage以外的所有Unicode函数。

3、安全考虑

在Windows NT中,主要有两个方面的安全考虑。一个涉及命名对象,另一个涉及Windows登陆。

(1)命名对象

IME可能需要创建各种各样的命名对象,供本地系统从多进程中访问。这样的对象可以包含文件、互斥对象或事件。由于进程可以属于不同的用户,谁是交互登录到系统,默认的安全属性(当IME创建一个对象的空指针参数时,系统创建一个安全属性)不可能对本地系统上的所有进程适合。

在Windows NT上,IME的第一个客户进程可以在WinLogon进程让用户登录到系统。由于WinLogon进程在登录会话活动到系统关闭期间,一直属于系统帐户。所以,IME创建的命名对象与默认安全属性在登录会话期间不能访问属于其他登录用户的进程。

微软DDK平台提供了一个为命名对象创建安全属性的原码样例。通过使用样例代码,IME作者可以创建能从本地系统的所有客户进程中访问的各种不同的命名对象。样例代码的每个进程分配安全属性。IME频繁地创建命名对象可能需要在进程附加时初始化安全属性,在进程分离时释放安全属性。在大多数情况下,IME不能创建命名对象。应该在初始化安全属性之前和释放安全属性之后创建命名对象。

(2)登录

由于用户在登录期间还尚未获得系统访问权,通过IME配置对话框获得信息有可能产生安全问题。即使系统管理员可以配置系统在登录会话时不激活IME。功能良好的IME应该不允许在客户进程为WinLogon进程时打开配置对话框。IME可以通过检查ImeInquier函数的dwSystemInfoFlags参数的IME_SYSTEMINFO_WINLOGON位来检查客户进程执行的登录会话是否为WinLogon进程。

十一、IME文件格式

下列主题论述IME文件格式及IME使用的数据结构。

1、IME文件格式

IME必须在版本信息资源中指定恰当的字段。其包括固定部分和长度可变部分。请参考微软SDK平台版本资源的详细信息。下列是IME文件应该包含的具体设置:

dwFileOS:指定版本信息的根块字段,用于指定文件的操作系统。在WINDOWS32 for Windows 95和Windows NT的IME中,该值必须为VOS__WINDOWS32。

dwFileType:指定版本信息的根块字段,用于指定文件类型。其值应为VFT_DRV.

dwFileSubtype:指定版本信息的根块字段,用于指定文件的子类型。其值应为 VFT2_DRV_INPUTMETHOD。

FileDescription:指定版本信息的特定语言块。包括IME名称和版本。该字符串仅用于显示,其长度为32个单字节字符。这一规定有可能延续到Windows的后续版本。

ProductName:指定特定语言的版本信息。

Charset ID和Language ID:在版本信息资源的可变信息块中指定IME的代码页(字符集标识)和语言标识。如果在块中指定了多个代码页和语言标识,IME使用第一个代码页显示文本,使用第一个语言标识作为IME语言。字符标识和语言标识必须符合IME语言,而不是资源语言。IME文件名为8.3格式(即文件名为8个字符,扩展名为3个字符)。

2、IME注册内容

在注册表的HKEY_CURRENT_USER\Control Panel中,包含了一个IME的Input Method键。其内容描述如下:

有四个值名:Perpendicular Distance、Parallel Distance、 Perpendicular Tolerance和Parallel Tolerance。近插字符操作IME会用到这些值。 如果这四个值名不存在,近插字符操作IME会根据IME设置一个默认值。

(1)Perpendicular Distance:与文本输出方向的垂直距离。它是插字符位置到组码窗口的垂直距离(像素),不含字体宽度和高度。近插字符操作IME将根据这个值和Parallel Distance调整组码窗口位置。其为REG_DWORD格式。

(2)Parallel Distance:与文本输出方向的水平距离。它是插字符位置到组码窗口的水平距离(像素点)。其为REG_DWORD格式。

(3)Perpendicular Tolerance:与文本输出方向的最大垂直距离。它是插字符位置到组码窗口的最大垂直距离(像素点)。如果插字符移动在这个范围内,近插字符操作IME将不会刷新组码窗口。其为REG_DWORD格式。

(4)Parallel Tolerance:与文本输出方向的最大水平距离。它是插字符位置到组码窗口的最大水平距离(像素点)。其为REG_DWORD格式。

IME可以将每个用户设置放入以下键位中:

HKEY_CURRENT_USER\Software\\Windows\CurrentVersion\。

IME可以将每个计算机设置放入以下键位中:

HKEY_LOCAL_MAACHINE\Software\\Windows\CurrentVersion\。

十二、IMM和IME数据结构

以下介绍的这些数据结构,是为IMM和IME提供通信的。 IMEs可以直接地访问这些结构,但应用程序不能直接访问。

1)INPUTCONTEXT

INPUTCONTEXT结构是一个用于存放输入上下文数据的内部数据结构。

1)定义

typedef struct tagINPUTCONTEXT {

HWND hWnd;

BOOL fOpen;

POINT ptStatusWndPos;

POINT ptSoftKbdPos;

DWORD fdwConversion;

DWORD fdwSentence;

union {

LOGFONTA    A;

LOGFONTW    W;

} lfFont;

COMPOSITIONFORM cfCompForm;

CANDIDATEFORM cfCandForm[4];

HIMCC hCompStr;

HIMCC hCandInfo;

HIMCC hGuideLine

HIMCC hPrivate;

DWORD dwNumMsgBuf;

HIMCC hMsgBuf;

DWORD fdwInit

DWORD dwReserve[3];

} INPUTCONTEXT;

2)成员

hWnd:使用该输入上下文的窗口句柄。如果该输入上下文被多个窗口共享,该句柄必须是激活窗口的句柄。该句柄可以用函数ImmSetActiveContext重设。

fopen:IME的当前状态。打开或关闭。

ptStatusWndPos:状态窗口位置。

ptSoftKbdPos:软键盘位置。

fdwConversion:IME使用的编码转换模式。

fdwSentence:IME使用的编码句型模式。

lfFont:IME用户界面绘制字符串时所使用的逻辑字体结构。

cfCompForm:IME用户界面创建编码窗口时所使用的数据结构。

cfCandForm[4]:IME用户界面创建候选窗口时所使用的数据结构。其为具有4个单元的数组,可以支持4个候选窗口。

hCompStr:指向COMPOSITIONSTR结构的内存句柄。当有编码串时,该句柄是可用的。

hCandInfo:指向候选结构的内存句柄。该内存区有一个CANDIDATEINFO结构和某一个CANDIDATELIST结构。当有候选串时,该句柄是可用的。

hGuideLine:指向GUIDELINE结构的内存句柄。当有指南信息时,该句柄是可用的。

hPrivate:指向IME用户私有数据区域的内存句柄。

dwNumMsgBuf:存放在hMsgBuf中的消息数。

hMsgBuf:以TRANSMSG格式存放消息的内存缓冲区。缓冲区的大小应该能存放dwNumMsgBuf个TRANSMSG。该缓冲区格式在Windows 95/98和Windows NT 4.0的IME文件中被定义为[Message1] [wParam1] [lParam1] {[Message2] [wParam2] [lParam2] {… {… {…}}}}。在Win32平台,所有值均为双字节。

fdwInit:初始化标志。IME在初始化INPUTCONTEXT结构成员时,依据该标志进行。具体标志位如下:

INIT_STATUSWNDPOS:初始化ptStatusWndPos。

INIT_CONVERSION:初始化fdwConversion。

INIT_SENTENCE:初始化fdwSentence。

INIT_LOGFONT:初始化lfFont。

INIT_COMPFORM:初始化cfCompForm。

INIT_SOFTKBDPOS:初始化ptSoftKbdPos。

dwReserve[3]:为未来的用途预留。

3)注意

在对ImeToAsciiEx调用期间,IME可以将消息存入缓冲区lpdwTransKey。如果IME要发送消息到应用程序,它必须将消息先存放到hMsgBuf缓冲区,然后再调用ImmGenerateMessage。 ImmGenerateMessage函数将hMsgBuf缓冲区中的消息发送到应用程序。

(2)COMPOSITIONSTR

COMPOSITIONSTR结构包含编码信息。在转换期间,IME在该结构中设置转换信息。

1)定义

typedef struct tagCOMPOSITIONSTR {

DWORD dwSize;

DWORD dwCompReadAttrLen;

DWORD dwCompReadAttrOffset;

DWORD dwCompReadClsLen;

DWORD dwCompReadClsOffset;

DWORD dwCompReadStrLen;

DWORD dwCompReadStrOffset;

DWORD dwCompAttrLen;

DWORD dwCompAttrOffset;

DWORD dwCompClsLen;

DWORD dwCompClsOffset;

DWORD dwCompStrLen;

DWORD dwCompStrOffset;

DWORD dwCursorPos;

DWORD dwDeltaStart;

DWORD dwResultReadClsLen;

DWORD dwResultReadClsOffset;

DWORD dwResultReadStrLen;

DWORD dwResultReadStrOffset;

DWORD dwResultClsLen;

DWORD dwResultClsOffset;

DWORD dwResultStrLen;

DWORD dwResultStrOffset;

DWORD dwPrivateSize;

DWORD dwPrivateOffset;

} COMPOSITIONSTR;

2)成员

dwSize:该结构的内存块大小。

dwCompReadAttrLen:读入的编码串属性信息长度。

dwCompReadAttrOffset:从该结构开始位置的偏移。读入的编码串属性信息保存在这里。

dwCompReadClsLen:读入的编码子串信息长度。

dwCompReadClsOffset:从该结构开始位置的偏移。子串信息保存在这里。

dwCompReadStrLen:读入的编码串长度。

dwCompReadStrOffset:从该结构开始位置的偏移。读入的编码串存放在这里。

dwCompAttrLen:编码串属性信息长度。

dwCompAttrOffset:从该结构开始位置的偏移。编码串属性信息存放在这里。

dwCompClsLen:编码子串长度。

dwCompClsOffset:从该结构开始位置的偏移。编码子串存放在这里。

dwCompStrLen:编码串长度。

dwCompStrOffset:从该结构开始位置的偏移。编码串存放在这里。

dwCursorPos:当前光标位置。

dwDeltaStart:编码串被修改的位置。

dwResultReadClsLen:读入的结果子串长度。

dwResultReadClsOffset:从该结构开始位置的偏移。读入的结果子串存放在这里。

dwResultReadStrLen:读入的结果串长度。

dwResultReadStrOffset:从该结构开始位置的偏移。读入的结果串存放在这里。

dwResultClsLen:结果子串长度。

dwResultClsOffset:从该结构开始位置的偏移。结果子串存放在这里。

dwResultStrLen:结果串长度。

dwResultStrOffset:从该结构开始位置的偏移。结果串存放在这里。

dwPrivateSize:用户自定义的私有数据大小

dwPrivateOffset:从该结构开始位置的偏移。用户自定义的私有数据存放在这里。

3)注意

①在Unicode状态下,所有dw*StrLen成员均以Unicode字符大小计算。所有dw*Len和dw*Offset成员均以字节大小计算。

②属性信息是一个字节数组,用来表示组合字符串中的字符的状态。提供以下属性值:

ATTR_INPUT:当前被输入的字符。用户输入的字符,如果这是日语,这个字符是被IME转换的平假名、片假名或者字母、数字字符。

ATTR_TERGET_CONVERTED:当前被已经转换的字符。由用户选定被IME转换了的字符。

ATTR_CONVERTED:已经由IME转换了的字符。

ATTR_TERGET_NOTCONVERTED:当前将被转换的字符。用户已经选定,但IME还未转换的字符。如果这日语,这个字符是用户输入的平假名、片假名或者字母、数字字符。

ATTR_FIXEDCONVERTED:不能转换的字符。

ATTR_INPUT_ERROR:错误字符,不可能被IME转换。

③属性信息的长度等于串的长度。每个字节对应于串的每个字节。即使串包括DBCS字符,属性信息有第一个字节和第二个字节的信息字节。在Windows NT的Unicode状态下,属性信息的长度是按Unicode字符计数的。每个属性字节对应于串的每个Unicode字符。

④子串信息是一个双字(32位)单元数组,用来表示每个子串所在的位置。数组开始部分的每个单元对应一个子串,最后一个单元的值用来表示整个编码字符串的长度。子串所在位置以其开始的字符在编码字符串中的位置来表示,字符在编码串中的位置值从0开始计算。假设一个编码字符串中有两个子串的话,那么子串信息数组中就应该有三个单元:第一个单元值为0;第二个单元的值表示第二个子串在编码串中的偏移;第三个单元值是编码串的长度。在Windows NT的Unicode状态下,子串位置和编码串长度都是按Unicode字符计数的。

⑤dwCursorPos成员指定光标位置。即用户在编码窗口中输入编码字符串时,那个用来编辑输入字符的光标所在的位置。它表示光标在当前编码字符串中的位置,从0开始计算。如果这个位置值为0,则表示光标位于当前编码字符串的第一个字符之前;如果这个位置值等于编码串的长度,就表示光标位于编码串最后一个字符之后;如果这个位置值为-1,则表示光标不出现。如果编码串不存在,则该成员无效。对于ANSI程序,以上提及的位置和长度值以字节为单位;而对于Unicode程序,则以Unicode字符为单位。

(3)CANDIDATEINFO

CANDIDATEINFO结构是整个候选信息的信息。其最多可以包含32个候选列表,并且这些候选列表必须在同一个存储区。

1)定义

typedef struct tagCANDIDATEINFO {

DWORD dwSize;

DWORD dwCount;

DWORD dwOffset[32];

DWORD dwPrivateSize;

DWORD dwPrivateOffset;

} CANDIDATEINFO;

2)成员

DWORD dwSize:该数据结构大小。

DWORD dwCount:候选列表个数。

DWORD dwOffset[32]:从该结构开始位置的偏移。每个偏移指定每个候选列表的开始位置。

DWORD dwPrivateSize:用户私有数据大小。

DWORD dwPrivateOffset:从该结构开始位置的偏移。用户私有数据存放在这里。

(4)GUIDELINE

GUIDELINE结构包含IME发送出的指南信息。

1)定义

typedef struct tagGUIDELINE {

DWORD dwSize;

DWORD dwLevel;

DWORD dwIndex;

DWORD dwStrLen;

DWORD dwStrOffset;

DWORD dwPrivateSize;

DWORD dwPrivateOffset;

} GUIDELINE;

2)成员

①DWORD dwSize:该结构的大小。

②DWORD dwLevel:指定错误级别。有下列定义:

GL_LEVEL_NOGUIDELINE:没有指南发送。 如果显示旧指南, UI将隐藏旧指南。

GL_LEVEL_FATAL:产生了致命错误。一些数据也许丢失。

GL_LEVEL_ERROR:产生了错误。处理不可以继续。

GL_LEVEL_WARNNING:IME对用户警告。意想不到的事发生了,但IME可能持续处理。

GL_LEVEL_INFORMATION:用户信息。

③DWORD dwIndex:提供下列值:

GL_ID_UNKNOWN:未知的错误。应用程序应该提取到错误串。

GL_ID_NOMODULE:IME不能找到其需要的模块。

GL_ID_NODICTIONARY:IME不能找到字典或字典格式错误。

GL_ID_CANNOTSAVE:字典或统计数据不能被保存。

GL_ID_NOCONVERT:IME不能再转换。

GL_ID_TYPINGERROR:键入错误。IME不能处理这个键入。

GL_ID_TOOMANYSTROKE:组合键输入字符或子串。

GL_ID_READINGCONFLICT:产生了读取冲突。例如,有些元音不能被组合。

GL_ID_INPUTREADING:IME提示用户,现在处于输入读字符状态。

GL_ID_INPUTRADICAL:IME提示用户,现在处于输入根字符状态。

GL_ID_INPUTCODE:IME提示用户,现在处于输入字符码状态。

GL_ID_CHOOSECANIDATE:IME提示用户,现在处于选择候选列表串状态。

GL_ID_REVERSECONVERSION:IME提示用户,现在提供反向转换的信息。反向转换的信息可以通过ImmGetGuideLine (hIMC, GGL_PRIVATE,lpBuf, dwBufLen)得到。在CANDIDATELIST中的lpBuf成员中包含反向转换信息格式。

GL_ID_PRIVATE_FIRST:ID位于在GL_ID_PRIVATE_FIRST和GL_ID_PRIVATE_LAST之间为IME是后备的。 IME可以自由的使用GUIDELINE结构提供的ID。

GL_ID_PRIVATE_LAST:ID位于在GL_ID_PRIVATE_FIRST和GL_ID_PRIVATE_LAST之间为IME是后备的。IME可以自由的使用GUIDELINE结构提供的ID。

④DWORD dwStrLen:错误串长度,如果为0,表示没有错误串。

⑤DWORD dwStrOffset:从该结构开始位置的偏移。错误串存放在这里。

⑥DWORD dwPrivateSize:用户私有数据大小。

⑦DWORD dwPrivateOffset:从该结构开始位置的偏移。用户私有数据存放在这里。

3)注意

在Unicode状态下,dwStrLen成员指定的错误串长度以Unicode字符为单位计算。dwSize、dwStrOffset、dwPrivateSize等大小以字节为单位计算。

(5)IMEINFO

IMEINFO结构由IMM和IME接口内部使用,提供输入法的接口信息。

1)定义

typedef struct tagIMEInfo {

DWORD dwPrivateDataSize;

DWORD fdwProperty;

DWORD fdwConversionCaps;

DWORD fdwSentenceCaps;

DWORD fdwUICaps;

DWORD fdwSCSCaps;

DWORD fdwSelectCaps;

} IIMEINFO;

2)成员

①dwPrivateDataSize:用户设计的私有数据结构的字节数。

②fdwProperty:IME属性。其高位为下列字节位组合:

IME_PROP_AT_CARET:设置该位表明IME转换窗口在插字符位置。否则表明在插字符位置附近操作IME。

IME_PROP_SPECIAL_UI:设置该位表明IME有特殊的用户接口。一般情况IME不会设置该标志位。

IME_PROP_CANDLIST_START_FROM_1:设置该位,表明候选窗口中候选串的起始序号为0或1。应用程序在画候选串时,可以在候选串前加上1、2、3等序号。

IME_PROP_UNICODE:设置该位,IME支持UNICODE字符。

IME_PROP_COMPLETE_ON_UNSELECT:为Windows98和Windows2000定义的新属性。如果设置该位,当撤销IME时,IME将完成编码串。 如果清除该位,当撤销IME时IME将取消编码串。

其低位为下列字节位的组合:

IME_PROP_END_UNLOAD:设置该位,表明IME将随使用它的应用的退出而卸载。否则,当使用它的应用程序退出时,IME有可能还驻留内存。

IME_PROP_KBD_CHAR_FIRST:设置该位,在IME转换DBCS字符之前,系统由键盘首先转换字符。这个字符是通过IME作为信息援助。否则不提供援助信息。

IME_PROP_NEED_ALTKEY:设置该位,IME需要通过ImeProcessKey函数处理Alt键。即允许Alt键事件进入IME。

IME_PROP_IGNORE_UPKEYS:设置该位,IME不需要通过ImeProcessKey函数处理上位键。即禁止上位键事件进入IME。

IME_PROP_ACCEPT_WIDE_VKEY:Windows2000下:如果设置该位, IME处理来自SendInput函数使用VK_PACKET被注入的Unicode字符。 如果清除, IME也许不处理被注入的Unicode字符,被注入的Unicode字符也许直接发送到应用。

③fdwConversionCaps:IME功能转换模式。定义的功能和转换模式相同。如果一些相关位关闭,IME则没有处理转换模式所定义的功能,不论转换模式的对应位是打开或关闭。其有下列定义:

IME_CMODE_KATAKANA:设置该位表明IME支持KATAKANA(片假名)模式。

IME_CMODE_NATIVE:设置该位表明IME支持NATIVE(本国)模式。

IME_CMODE_FULLSHAPE:设置该位表明IME支持全角模式。

IME_CMODE_ROMAN:设置该位表明IME支持ROMAN(罗马)输入模式。

IME_CMODE_CHARCODE:设置该位表明IME支持CHARCODE(字符码)输入模式。

IME_CMODE_HANJACONVERT:设置该位表明IME支持HANJA转换模式。

IME_CMODE_SOFTKBD:设置该位表明IME支持软键盘输入模式。

IME_CMODE_NOCONVERSION:设置该位表明IME不支持模式转换。

IME_CMODE_EUDC:设置该位表明IME支持EUDC模式。

IME_CMODE_SYMBOL:设置该位表明IME支持标点转换模式。

IME_CMODE_FIXED:设置该位表明IME支持固定转换方式。

④fdwSentenceCaps:IME句子功能模式。固定定义和句子模式相同。如果一些相关位关闭,IME则没有处理句子模式的功能,不论转换模式的对应位是打开或关闭。具体定义如下:

IME_SMODE_PLAURALCLAUSE:设置该位表明IME支持多个子句模式。

IME_SMODE_SINGLECONVERT:设置该位表明IME支持单一字符句子模式。

IME_SMODE_AUTOMETIC:设置该位表明IME支持自动句子模式。

IME_SMODE_PHRASEPREDICT:设置该位表明IME支持词组联想句子模式。

IME_SMODE_CONVERSATION:设置该位表明IME使用交谈方式。这对聊天应用程序是有用的。聊天应用程序可以改变IME的句子模式到交谈样式。这是为Windows98和Windows2000提供的新模式。

⑤fdwUICaps:IME用户界面功能。具体定义如下:

UI_CAP_2700:IME用户界面支持逻辑字体旋转角度为0或270度。

UI_CAP_ROT90:IME用户界面支持逻辑字体旋转角度为0、90、180或270度。

UI_CAP_ROTANY:IME用户界面支持逻辑字体以任何角度旋转。

UI_CAP_SOFKBD:IME使用系统提供的软键盘显示方式。

⑥fdwSCSCaps:ImeSetCompositionString函数功能,即编码串功能设置。具体定义为:

SCS_CAP_COMPSTR:IME可以由SCS_SETSTR产生编码串。

SCS_CAP_MAKEREAD:当使用SCS_SETSTR调用函数ImmSetCompositionString时, IME可以不使用lpRead创造读入编码串。 IME在此功能下,应用程序不需要设置lpRead为SCS_SETSTR。

⑦fdwSelectCaps:IME之继承IMC功能,即输入法切换时是否使用以前输入法的模式。提供以下定义:

SELECT_CAP_CONVMODE:在ImeSelect函数中,IME有转换模式继承能力。即可以继续使用以前输入法的模式。

SELECT_CAP_SENTENCE:在ImeSelect函数中,IME有句子模式继承能力。

(6)CANDIDATELIST

CANDIDATELIST结构包含有关候选列表信息。用于管理候选窗口的列表信息。

1)定义

typedef struct tagCANDIDATELIST {

DWORD dwSize;

DWORD dwStyle;

DWORD dwCount;

DWORD dwSelection;

DWORD dwPageStart;

DWORD dwPageSize;

DWORD dwOffset[];

} CANDIDATELIST;

2)成员

①dwSize:以字节为单位的该结构的大小。

②dwStyle:列表串样式,可以是以下一个或多个标志组合:

IME_CAND_UNKNOWN:未定义列表样式。

IME_CAND_READ:读入数据和列表数据相同。我们一般使用该标志。

IME_CAND_CODE:候选列表数据在一个代码范围。

IME_CAND_MEANING:候选列表有同一个意思。

IME_CAND_RADICAL:候选列表由相同的根字符组成。

IME_CAND_STROKES:候选列表由输入的相同数字组成。

③dwCount:当前候选列表串个数。

④dwSelection:当前选择的候选列表串序号。

⑤dwPageStart:候选窗口中第一候选串列表的索引。当用户按上下翻页键时使用。

⑥dwPageSize:候选窗口一页显示的候选列表串个数。如果这个数字是零,应用程序可以定义其他适当的值。

⑦dwOffset[]:从该结构开始位置的偏移,用于存放列表串。

3)注意

在IME_CAND_CODE模式下,候选列表根据dwCount的值确定其结构。如果dwCount是1, dwOffset不是偏移地址,而是一个DBCS字符,并且不提供候选列表串。 如果dwCount大于1, dwOffset是偏移地址数组,并且提供候选列表串。

CANDIDATELIST结构使用ImmGetCandidateList函数返回。候选列表串在dwOffset数组跟随最后偏移。

(7)COMPOSITIONFORM

COMPOSITIONFORM结构提供编码窗口信息,由消息IMC_SETCOMPOSITIONWINDOW和IMC_SETCANDIDATEPOS使用。

1)定义

typedef tagCOMPOSITIONFORM {

DWORD dwStyle;

POINT ptCurrentPos;

RECT rcArea;

}COMPOSITIONFORM;

2)成员

dwStyle:窗口位置管理方式。具体定义如下:

CFS_DEFAULT:移动编码窗口到缺省位置。 IME窗口可以显示编码窗口在客户区域之外,例如当应用程序这一个浮动窗口时。

CFS_FORCE_POSITION:将编码窗口显示到ptCurrentPos指定的位置。该坐标是相对于编码窗口的包含窗口的左上角,并且不受IME控制。

CFS_POINT:将编码窗口显示到ptCurrentPos指定的位置。该坐标是相对于编码窗口的包含窗口的左上角,但受IME控制。

CFS_RECT:将编码窗口显示到rcArea指定的位置。坐标是相对于编码窗口的包含窗口的左上角。

ptCurrentPos:编码窗口的左上角坐标。

rcArea:编码窗口的左上角和右下角坐标。

3)注意

当dwStyle 是CFS_POINT或CFS_FORCE_POINT时, IME将绘制编码串到ptCurrentPos指定的位置。如果dwStyle是CFS_RECT,编码串将是在rcArea指定的矩形里。否则,rcArea将是应用程序窗口的客户区。

当应用程序指定编码字体时,编码窗口被旋转到与编码字体相同的角度。IME跟随编码窗口和编码字体的角度方向绘制编码串。

编码字体的旋转角度是0。在这种情形下,编码字体的ptCurrentPos构造点在串的左上角。所有IME支持这种编码窗口类型。

编码字体的旋转角度是2700。当应用程序提供垂直文字时,应用程序可以用ImmCompositoinFont设置编码字体的旋转角度为2700,然后将向下绘制编码串。IME如果具有UI_CAP_2700、 UI_CAP_ROT90或UI_CAP_ROTANY属性时,将支持这种编码窗口类型。

编码字体的旋转角度是900或1800。IME具有UI_CAP_ROT90或UI_CAP_ROTANY属性时,将支持这种编码窗口类型。

编码字体的旋转角度是任意值。IME具有UI_CAP_ROTANY属性时,将支持这种编码窗口类型。

UI_CAP_ROT90和UI_CAPS_ANY是IME的改进属性。一般推荐使用UI_CAP_2700。

(8)CANDIDATEFORM

CANDIDATEFORM结构提供列表窗口信息,由消息IMC_GETCANDIDATEPOS和 IMC_SETCANDIDATEPOS使用。

1)定义

typedef tagCANDIDATEFORM {

DWORD dwIndex;

DWORD dwStyle;

POINT ptCurrentPos;

REC rcArea;

} CANDIDATEFORM;

2)成员

dwIndex:指定候选列表序号。 0是第一个候选列表, 1是第二个等等。

dwStyle:窗口显示方式。如果其为CFS_CANDIDATEPOS或CFS_EXCLUDE,为本地插入IME。如果其为CFS_DEFAULT,本地插入IME将根据其他UI组件调整候选窗口位置。

ptCurrentPos:位置坐标,其取决于dwStyle。当dwStyle是CFS_CANDIDATEPOS时,在ptCurrentPos指定位置显示候选列表窗口。 当dwStyle是CFS_EXCLUDE时, ptCurrentPos指定插入符位置。

rcArea:候选列表窗口在CFS_EXCLUDE情况下,为其指定一个无显示的矩形区域。

(9)STYLEBUF

STYLEBUF为注册字样式结构,其包含注册字样式的标识符和名字。

1)定义

typedef struct tagSTYLEBUF {

DWORD dwStyle;

TCHAR szDescription[32]

} STYLEBUF;

2)成员

dwStyle:注册字样式。

szDescription[32]:样式描述串。

3)注意

注册串样式包括IME_REGWORD_STYLE_EUDC,在EUDC范围内。如果常数范围在IME_REGWORD_STYLE_USER_FIRST和IME_REGWORD_STYLE_USER_LAST内,则注册字为用户的私有IME ISV样式。IME ISV能自由地定义用户自己的注册字样式。

(10)SOFTKBDDATA

SOFTKBDDATA结构为每个DBCS码定义虚拟键。

1)定义

typedef struct tagSOFTKBDDATA {

UINT uCount;

WORD wCode[][256]

} SOFTKBDDATA;

2)成员

uCount:虚拟键码数组个数(可以为1和2,当区分SHIFT键时应为2,即一组带SHIFT,一组不带SHIFT)。

wCode[][256]:256个虚拟键数组。

(11)RECONVERTSTRING

RECONVERTSTRING为IME复原结构。

1)定义

typedef struct _tagRECONVERTSTRING {

DWOPD dwSize;

DWORD dwVersion;

DWORD dwStrLen;

DWORD dwStrOffset;

DWORD dwCompStrLen;

DWORD dwCompStrOffset;

DWORD dwTargetStrLen;

DWORD dwTargetStrOffset;

} RECONVERTSTRING;

2)成员

dwSize:本结构的大小。

dwVersion:系统预留,必须是零。

dwStrLen:包含编码串的串长度。

dwStrOffset:从该结构开始位置的偏移。包含转变词的串存放在这里。

dwCompStrLen:编码串长度。

dwCompStrOffset:编码串偏移地址。

dwTargetStrLen:编码串中的目标子串长度。

dwTargetStrOffset:编码串中的目标子串的偏移地址。

3)注意

RECONVERTSTRING是为Windows98和Windows2000设置的一个新结构。 dwCompStrOffset和dwTargetOffset成员是dwStrOffset的相对位置。在WindowsNT Unicode下, dwStrLen、dwCompStrLen、和dwTargetStrLen是以TCHAR计数,而dwStrOffset、dwCompStrOffset和dwTargetStrOffset是以字节为单位的偏移。

如果应用程序通过使用SCS_SETRECONVERTSTRING和SCS_QUERYRECONVERTSTRING调用ImmSetCompositionString开始复原,应用程序应该负责为该结构及编码缓冲区分配必要的内存空间。如果IME开始处理,它应该为该结构和编码串缓冲区分配必要的内存。

IME的复原功能,可用于词语联想功能的实现。

(12)IMEMENUITEMINFO

IMEMENUITEMINFO为输入法菜单信息结构,其包含有关IME菜单项的信息。

1)定义

typedef _tagIMEMENUITEMINFO {

UINT cbSize;

UINT fType;

UINT fState;

UINT wID;

HBITMAP hbmpChecked;

HBITMAP hbmpUnchecked;

DWORD dwItemData;

TCHAR szString[48];

HBITMAP hbmpItem;

} IMEMENUITEMINFO;

2)成员

cbSize:该结构大小。

fType:菜单项类型,由下列一项或多项组合而成:

IMFT_RADIOCHECK:显示使用无线按钮标志的检查菜单项。如果hbmpChecked成员为NULL,则不校验标志。

IMFT_SEPARATOR:指定菜单项是分界线。hbmpItem和szString的成员被忽略。

IMFT_SUBMENU:指定菜单项是子菜单。

fState:菜单项状态。可以是以下一个或多个值的组合:

IMFS_CHECKED:检查菜单项。

IMFS_DEFAULT:指定缺省菜单项。缺省菜单项在菜单中只能有一个,并被突显。

IMFS_DISABLED:使菜单项无效,不可能被选择。

IMFS_ENABLED:使菜单项有效,可以被选择。这是菜单项的缺省状态。

IMFS_GRAYED:显示菜单项为灰色,不可以被选择。

IMFS_HILITE:焦点菜单项。

IMFS_UNCHECKED:非检查菜单项。

IMFS_UNHILITE:从菜单项去除焦点。这是菜单项的缺省状态。

wID:应用程序定义的16位菜单项标识。

hbmpChecked:显示在菜单项旁边的检查图标句柄。如果该成员为空,则使用缺省位图。

hbmpUnchecked:显示在菜单项旁边的非检查图标句柄。如果该成员为空,不使用位图。

dwItemData:与菜单项相关的应用程序定义值。

szString[48]:菜单项内容,即菜单项名称。该成员是以#0终止的字符串。

hbmpItem:显示的位图句柄。

3)注意

IMEMENUITEMINFO是为Windows98和Windows2000设置的一个新结构。该结构的Unicode版本,有一个WCHAR类型的szString的成员。

(13)TRANSMSG

TRANSMSG结构包含转转换消息,用于ImeToAsciiEx接收IME引发的消息。

1)定义

typedef _tagTRANSMSG {

UINT message;

WPARAM wParam;

LPARAM lParam;

} TRANSMSG;

2)成员

message:指定消息标识。

wParam:指定有关消息的其它信息。确切含义取决于message成员的值。

lParam:指定有关消息的其它信息。确切含义取决于message成员的值。

3)注意

该结构是为64位WindowsNT平台新增的。其与TRANSMSGLIST一起将用于ImeToAsciiEx,替换以前使用的LPDWORD lpdwTransBuf。使用该结构将依然保持数据在内存有相同的偏移地址,并保持向后兼容。

(14)TRANSMSGLIST

TRANSMSGLIST结构包含从ImeToAsciiEx返回的转换消息列表。

1)定义

typedef _tagTRANSMSGLIST {

UINT uMsgCount;

TRANSMSG TransMsg[1];

} TRANSMSGLIST;

2)成员

uMsgCount:指定TransMsg数组中的消息数。

TransMsg[1]:包含TRANSMSG数据的数组。

3)注意

该结构是为64位WindowsNT平台新增的。其将用于ImeToAsciiEx,替换以前使用的LPDWORD lpdwTransBuf。 使用该结构将依然保持数据在内存有相同的偏移地址,并保持向后兼容。


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:226385次
    • 积分:2438
    • 等级:
    • 排名:第15246名
    • 原创:68篇
    • 转载:72篇
    • 译文:0篇
    • 评论:16条
    文章分类