IMEを制御する方法

戻る

DOSでは、FEP(Front End Processer) と呼ばれていた「かな漢字変換機能」は、 Windowsでは IME(Input Method Editor)という名称となり、システムの一部として 提供され、制御するためのAPIも提供されるようになりました。
漢字(2バイト文字)を入力するときには、その度にIMEを起動するためのキーを入力 する必要があります。たとえば、IMEで入力する可能性が高いエディットボックスなどの 入力域では、キーを入力しなくても漢字が入力することができればキー操作がスムーズ にできるでしょう。
Windows95と共に、IMEも全面的に修正されました。とは言え、以前のメッセージ ベースのAPI も利用することができますし、キーボードからの操作は今までと同様に 可能です。新しくなった32ビットIMM API を利用することにより、処理が単純化 され、また新しく追加された高度な機能を利用することが可能になりました。

7-1 IMEとは

IMEは、IMM(Input Method Manager)によって管理され、入力域に表示されるキャレット と同様に、システム内で必ず1個所にしか表示されません。
アクティブなウィンドウ上で変換が行われているときには、他のウィンドウで動作して いるIMEは、ウィンドウがアクティブになるまで中断されます。
つまり、日本語版(中国語・ハングル語版も含めた、いわゆる極東版)のシステムでの IME, IMMはキー入力機能の一部でありキーボードから入力された文字はすべてIMMの管理 下にあります。Windows95 上で16ビットのIMEを利用することもできます。 しかし、このときには、IME, IMMが提供する APIの利用が制限されますので、 32ビット版のIMEでなければ利用できない機能を利用する必要があるときにはIMEの バージョンをチェックするなどしてトラブルが起こらないようにしておく必要が あります。32ビット版でも、バージョンやメーカーが異なると動作が異なることが あるため注意が必要になります。

7-2 32ビットIME制御API

●WindowsNT3.5以前のIME API
IME API は、IME.H に定義され、16ビットWindowsからサポートされているものと 同様です。
IME API を利用するための特別な初期化処理を必要とせず、IME API SendIMEMessageEx を利用して、IMESTRUCT構造体に必要なパラメータを設定して送信することで処理を 行うことができます。
WindowsではまたDDEを利用してAPI+αの機能を提供していましたが、WindowsNTでは サポートされません。また、IME API SendIMEMessage もありますが、32ビット環境 では事実上なくなっています。

<IME API でIMEをオープン(利用可能に)する>
hMemIme = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, sizeof(IMESTRUCT));
lpIme = (LPIMESTRUCT)GlobalLock(m_hgIme);
lpIme->fnc    = IME_SETOPEN;                    /* IME状態設定 */
lpIme->wParam = 1;                              /* オープンする */
GlobalUnlock(hMemIme);
SendIMEMessageEx(hWnd, (LPARAM)(hMemIme));      /* メッセージ送信 */
GlobalFree(hMemIme);

表7-1:IME API
WORD WINAPI SendIMEMessageEx(HWND hWnd, LPARAM lParam)
IMEにメッセージを送信する

引数
HWND hWnd ... 呼び出し元のウィンドウハンドル
LPARAM lParam ... IMESTRUCT構造体を含むグローバル
メモリのハンドルメッセージ *

戻り値
正常終了 TRUE
異常終了 FALSE
(IMESTRUCT構造体のwParamにエラー値を格納する)
IME_RS_DISKERROR ディスク エラー
IME_RS_ERROR 一般エラー
IME_RS_ILLEGAL 不正な文字
IME_RS_INVALID サブファンクションが無効
IME_RS_NEST 入れ子で使用することはできない
IME_RS_NOIME IMEがインストールされていない
IME_RS_NOROOM 領域が足りない
IME_RS_NOTFOUND 候補が見つからない
IME_RS_SYSTEMMODAL IMEにデータを渡すことができない
IME_RS_TOOLONG 文字が長すぎる
* IMESTRUCT構造体を格納する領域は、Win32 API GlobalAlloc で
GMEM_MOVEABLE, GMEM_SHAREフラグ を指定した領域である必要がある

リスト7-1:IMESTRUCT 構造体

    typedef struct tagIMESTRUCT {
        UINT    fnc;        /* サブファンクション             */
        WPARAM  wParam;     /* サブファンクションにより異なる */
        UINT    wCount;     /* サブファンクションにより異なる */
        UINT    dchSource;  /* サブファンクションにより異なる */
        UINT    dchDest;    /* サブファンクションにより異なる */
        LPARAM  lParam1;    /* サブファンクションにより異なる */
        LPARAM  lParam2;    /* サブファンクションにより異なる */
        LPARAM  lParam3;    /* サブファンクションにより異なる */
    } IMESTRUCT;
    typedef IMESTRUCT far *LPIMESTRUCT;

表7-2:IME API SendMessageEx のサブファンクション
IME_ENTERWORDREGISTERMODE単語登録
IME_GETCONVERSIONMODEIMEのモード取得
IME_GETOPENIME状態取得
IME_GETIMECAPS機能サポート調査
IME_GETVERSIONIMEのバージョン取得
IME_SENDVKEY仮想キー送信
IME_SETCONVERSIONFONTEX変換文字列のフェース名を指定
IME_SETCONVERSIONMODEIMEのモード設定
IME_SETCONVERSIONWINDOW変換ウィンドウの位置設定
IME_SETOPENIMEの状態設定

IME を制御するAPIは IME API 以外に IMEの有効,無効化や、ホットキーの制御 に関する IMM APIと、IMEを制御するためのIMP API があります。 一般的なアプリケーションではこれらのAPIを利用することはあまりないのでは ないかと思われますが、簡単に説明しておきます。

◆IMM API(WINNLS API)
IMM(Input Method Manager) API は WINNLS32.H に定義してあります。 このAPIは、IMMの動作を制御するときに利用します。たとえば、IMEで漢字の入力を させたくないときには、IMM API WINNLSEnableIME でIME自身の動作を一切できない ようにすることができます。

表7-3 IMM(Input Method Manager) API
BOOL WINAPI WINNLSEnableIME(HWND hWnd, BOOL bEnable)
IMEの動作を設定する

引数
HWND hWnd ... 呼び出し元のウィンドウハンドル
BOOL bEnale ... TRUE (IMEをイネーブル状態にする)
FLASE (IMEをディセーブル状態にする)
戻り値
 直前の状態
BOOL WINAPI WINNLSGetEnableStatus(HWND hWnd)
IMEの動作を取得する

引数
HWND hWnd ... 呼び出し元のウィンドウハンドル

戻り値
 現在の状態
UINT WINAPI WINNLSGetIMEHotkey(HWND hWnd)
IMEの動作を取得する

引数
HWND hWnd ... 呼び出し元のウィンドウハンドル

戻り値
 直前に設定されていた仮想キーの値
 設定されていない場合はNULLを返す

◆IMP API
IMP(Input Method Profiler) API も IMM APIと同様に WINNLS32.H に定義して あります。IMPは、システムにインストールしているIMEの情報を管理するための システムモジュールです。このAPIで、インストールされているIMEの管理を行うことが できます。


表7-4 IMP(Input Method Profiler) API
BOOL WINAPI IMPGetIME(HWND hWnd, LPIMEPRO lpIMEPro)
アクティブな状態のIMEの情報を取得

引数
HWND hWnd ... 呼び出し元のウィンドウハンドル
LPIMEPRO lpIMEPro ... IMEPRO構造体を指すポインタ

戻り値
正常終了 TRUE
異常終了 FALSE
BOOL WINAPI IMPQueryIME(LPIMEPRO lpIMEPro)
IMP内部リストに登録されているすべてのIMEの情報を取得

引数
LPIMEPRO lpIMEPro ... IMEPRO構造体を指すポインタ

戻り値
正常終了 TRUE
異常終了 FALSE
BOOL WINAPI IMPSetIME(HWND hWnd, LPIMEPRO lpIMEPro)
アクティブなIMEを切り替える

引数
HWND hWnd ... 呼び出し元のウィンドウハンドル
LPIMEPRO lpIMEPro ... IMEPRO構造体を指すポインタ

lpIMEPro->szNameに、長さが0の文字列を指定すると、
ロードされている全てのIMEが非アクティブ状態となります。

戻り値
正常終了 TRUE
異常終了 FALSE

●Windows95/NT3.51以降のIME API

WindowsNT3.5以前でサポートされているAPIはすべて利用可能で、これに加えて IMM.H に定義してあるIMM API を利用することができます。このAPIは、MS-IME95が 発表されるとともに利用可能になりました。
通常のアプリケーションではIMEのオープン・クローズが可能であればそれ以外の 機能を使うことはあまりないのではないかと思われます。
文字を入力する領域にエディットボックスやコンボボックスを利用するのであれば IMEが利用するフォントや変換を行うときに表示されるウィンドウの位置に関しても 制御を行っているため、あとはユーザはIMEのオープン・クロースのみを制御すれば よいことになります。これらのAPIを駆使する必要があるのは、たとえばテキスト エディタを自作する必要がある場合、たとえば、CADのような図形を作成するツール でウィンドウ内に直接文字列を書き込む必要があるときや、MS-Word95以降のように、 コンポジションウィンドウの処理をアプリケーション自身が行うときなどキャレットを アプリケーション自身が制御する必要があるときなどに限られます。
(* キャレットは、Win32 API CreateCaret, ShowCaret, HideCaretなどを利用して制御 します)
通常、ユーザが漢字(2バイト文字)を入力するとき、カナ入力が得意な方は 初期設定でカナ入力、カナ入力が苦手な方はローマ字入力にしているため、これらの 設定をアプリケーションで入力モードを変更する必要はありません。

◆外部からIMEの制御を可能とする新しいIMM API
Microsoft Word95 などでは、文字列の入力域にIMEの変換入力域が埋め込まれている ような動作をします。これはIME95でサポートされる、新しいIMMの機能で実現して います。WindowsNT3.5までのIME API では、IME を外部から制御することしか できませんでしたが、新しいIMM API を利用することにより、IME の機能が アプリケーションの機能の一部であるかのように動作させることが可能に なります。
IMM API では、変換結果を単語単位、文節単位、変換後など細かく取得することが できます。IMM API GetConpositionString を利用して、ローマ字入力を行ったとき でも変換で得られた漢字の仮名を半角カナ文字列で取得することができます。 この機能を利用すれば、氏名の入力域に漢字で氏名を入力すると自動的に「フリガナ」 を入力するといった機能を簡単に実現することができます。
逆に IMM API SetCompositionStringを利用して、「フリガナ」を入力すると漢字変換 を自動的に行うといったことも可能です。

◆新規アプリケーションは,新しいIMM APIを利用したほうがよい
IMEは、アプリケーションのスレッドごとにウィンドウを生成し、アプリケーションが 特に指定しない限りそれらのウィンドウを利用して漢字変換処理を行います。 アプリケーションは必要に応じて、IMM API ImmSetStatusWindow, IMM API ImmCompositionWindow, IMM API ImmSetCandilateWindow を利用してIMEが 持つウィンドウをカスタマイズすることができ、WM_IME_CONTROL メッセージで IMEのウィンドウを間接的に操作することもできます。
WindowsNT3.5以前のIME,IMP,IMM API の機能のほとんどは新しいIMM API で可能に なっていますので、新しく作成するアプリケーションは、特別な理由がなければ 新しいIMM API を利用した方がよいでしょう。

7-3 新しいIMM API

以前のIME API では、メッセージを送信することで動作を決定しますが、新しい IMM API は IMM API ImmGetContext でウィンドウハンドルから IMEコンテキスト ハンドルを取得し、このコンテキストハンドルでIMEの処理を決定します。
<IMM API でIMEをオープン(利用可能に)する> hImm = ImmGetContext(hWnd);
ImmSetOpenStatus(hImm, TRUE);
ImmReleaseContext(hWnd, hImm);
IME への要求や問い合わせなどはIMM API を利用して行い、実行結果が取得可能な 状態になるとウィンドウメッセージがIMEから送信されます。
アプリケーションは受信したメッセージの種類によって、利用するIMM API を選択して 結果を取得することができます。

図7-3:文字列を変換して結果を取得するまでの流れ
       アプリケーション                                  IME
 +-------------------------+                      +----------------------+
 |□              [_][ ][X]|                      |                      |
 +-------------------------+                      |                      |
 | ImmSetConpositionString |                      |                      |
 |        "ヘンカン" ---------------(1)-----------------> "ヘンカン"→"変換"     |
 |                         |                      | (2) 変換の操作を行う |
 |                    (3)<----WM_IME_COMPOSITION-----           |        |
 |                         |                      |             |        |
 | ImmGetCompositionString ----------(4)------------>           |        |
 |        "変換" <-------------------(5)------------------------+        |
 |                         |                      |                      |
 +-------------------------+                      +----------------------+

                           (1) 変換する仮名文字列を設定
                           (2) ウィンドウ上で変換の操作
                               (またはImmNotifyIMEで変換を行う)
                           (3) 変換元のウィンドウに変換の操作が
                               行われたことを通知
                           (4) 必要な文字列を要求
                           (5) 目的の文字列を取得

新しいIMM API の関数は以前のものと比べて高機能になっています。このため、 APIの数もかなり多くなっていますが、使い方を理解すれは大変わかりやすい体系に なっています。実際に利用するときには、Win32 SDK にもサンプルが用意されています ので、そちらも参考にするとよいでしょう。
<Win32SDKのサンプルパス> (* サンプルの格納ディレクトリがIMEになっていますが、新しいIMM API を利用したサンプルです。)
\MSSDK\SAMPLE\WIN32\IME\FULLIME
\MSSDK\SAMPLE\WIN32\IME\HALFIME
\MSSDK\SAMPLE\WIN32\IME\IMEAPPS
\MSSDK\SAMPLE\WIN32\IME\MULTIUI
APIの仕様や動作は、IMEのメーカやバージョンによって多少の違いがあります。 気になった違いを次に示します。
1)MS-IME97ではカナ入力からローマ字入力に切り替える時にはカナキーのOFFは行われません。
2)MS-IME95は、クローズ状態ではImmSetConversionStatusの設定は無視されます。
3)MS-IME97では直接入力指定が無視されることがあります。(IME95とは異なる方法があるのかもしれませんが不明です。)
4)ImmSetCompositionString で変換文字列を設定して変換を行うとき、MS-IME では、文字列に空白が入っている場合、その空白を文字列の一部として変換を行いますが、NEC-AI は、空白以降の文字は変換対象になりません。
その他にも微妙な動作の違いがあります。IME自身の違い以外にOSの違いによっても 動作が異なることがありますので注意が必要です。

表7-5:新しいIME API
EnableEUDC ユーザ定義文字の利用を設定する
EnumRegisterWordProc ImmEnumRegisterWord のコールバック関数
ImmAssociateContext コンテキストハンドルの関連付けを行う
ImmConfigureIME IMEのプロパティ設定ダイアログボックスの表示を行う
ImmCreateContext IMEコンテキストを生成する
ImmDestroyContext IMEコンテキストを解放する
ImmEnumRegisterWord 登録されている単語を列挙する
ImmEscape 言語に依存した操作を行う
ImmGetCandidateList 単語の候補リストを取得する
ImmGetCandidateListCount 候補リストのサイズを取得
ImmGetCandidateWindow 候補リストウィンドウに関する情報を取得する
ImmGetCompositionFont コンポジションウィンドウで利用するフォントを取得する
ImmGetCompositionString 変換文字列を取得する
ImmGetCompositionWindow コンポジションウィンドウに関する情報を取得する
ImmGetContext 指定ウィンドウのコンテキストハンドルを取得する
ImmGetConversionList 文字または単語から単語リストを返す
ImmGetConversionStatus 現在の変換ステータスを取得する
ImmGetDefaultIMEWnd IMEクラスのデフォルトウィンドウを取得する
ImmGetDescription IMEの説明文字列を取得する
ImmGetGuideLine ガイドライン文字列を取得する
ImmGetIMEFileName IMEのファイル名を取得する
ImmGetOpenStatus IMEのオープン状態を取得する
ImmGetProperty プロパティを取得する
ImmGetRegisterWordStyle スタイルサポートのリストを取得する
ImmGetStatusWindowPos ステータスウィンドウの位置を取得する
ImmGetVirtualKey 処理後の入力メッセージのオリジナル仮想キーを取得する
ImmInstallIME IMEのインストールを行う
ImmIsIME IMEのハンドルであるかを返す
ImmIsUIMessage IMEウィンドウのウィンドウメッセージを処理する
ImmNotifyIME 入力コンテキストの状態変更を問い合わせる
ImmRegisterWord 単語登録を行う
ImmReleaseContext ImmGetContextで取得したハンドルを解放する
ImmSetCandidateWindow 候補リストウィンドウに関する情報を設定する
ImmSetCompositionFont コンポジションウィンドウで利用するフォントを設定する
ImmSetCompositionString 変換文字列を設定する
ImmSetCompositionWindow コンポジションウィンドウに関する情報を設定する
ImmSetConversionStatus 現在の変換ステータスを設定する
ImmSetOpenStatus IMEのオープン状態を設定する
ImmSetStatusWindowPos ステータスウィンドウの位置を設定する
ImmSimulateHotKey ホットキーをシミュレートする
ImmUnregisterWord 単語を削除する
(a)API

IME_CMODE_ALPHANUMERIC(0x0000) 英数モード
IME_CMODE_NATIVE(0x0001) 対応言語入力(ON)・英数入力(OFF) モード
IME_CMODE_CHINESE
IME_CMODE_HANGEUL
IME_CMODE_JAPANESE でも定義してある
IME_CMODE_KATAKANA(0x0002) カタカナ(ON)・ひらがな(OFF) モード
IME_CMODE_FULLSHAPE(0x0008) 全角モード
IME_CMODE_ROMAN(0x0010) ローマ字モード
IME_CMODE_CHARCODE(0x0020) キャラクタ入力モード
IME_CMODE_HANJACONVERT(0x0040) ハングル文字変換モード
IME_CMODE_SOFTKBD(0x0080) ソフトキーボードモード
IME_CMODE_NOCONVERSION(0x0100) 無変換モード
IME_CMODE_EUDC(0x0200) EUD変換モード
IME_CMODE_SYMBOL(0x0400) シンボルモード
(b)ImmSetConversionStatus, ImmGetConversionStatus の変換モードの ビットセット

IME_SMODE_NONE(0x0000) 無変換
IME_SMODE_PLURALCLAUSE(0x0001) 複合語優先
IME_SMODE_SINGLECONVERT(0x0002) 単変換
IME_SMODE_AUTOMATIC(0x0004) 自動変換
IME_SMODE_PHRASEPREDICT(0x0008) 連文節変換
(c)ImmSetConversionStatus, ImmGetConversionStatus の センテンスモードのビットセット


表7-6:IMEから受信するウィンドウメッセージ
WM_IME_CHAR IMEが取得した文字を受信
WM_IME_COMPOSITION 変換が実行されたことを受信する(フラグはGCS_xxxxx)
WM_IME_COMPOSITIONFULL コンポジションウィンドウの領域が以上広がらないときに受信する
WM_IME_CONTROL アプリケーションが生成したIMEウィンドウに処理要求を行う (コマンドはIMC_xxxxx)
WM_IME_ENDCOMPOSITION 変換が終了したことを受信する
WM_IME_KEYDOWN IMEが受信したWM_KEYDOWNを受信する
WM_IME_KEYUP IMEが受信したWM_KEYUPを受信する
WM_IME_NOTIFY アプリケーションが生成したIMEウィンドウに処理要求を行う (コマンドはIMN_xxxxx)
WM_IME_SELECT カレントのIMEが変更されたことを受信する
WM_IME_SETCONTEXT アプリケーションが生成したIMEウィンドウに処理要求を行う (コマンドはISC_xxxxx)
WM_IME_STARTCOMPOSITION 変換が開始されたことを受信する

●IMEが持つ機能や能力の取得方法
新しいIMM API では、IMEが持つ機能や能力を知るための IMM API ImmGetProperty を用意してあります。このAPIにインデックスを指定して呼び出すことにより、 対応する情報を取得します。IME は、日本語だけでなく中国語やハングル語にも対応 したバージョンが存在するため、実行中のIMEがどのような機能をもっているかによって 処理を変える必要があるとき利用することができます。

表7-7:IMEのプロパティ
IGP_PROPERTY(0x00000004) プロパティ情報
IME_PROP_AT_CARET(0x00010000) コンポジションウィンドウはキャレットの位置に表示される
IME_PROP_SPECIAL_UI(0x00020000) IMEは非標準のインタフェースを持つ
IME_PROP_CANDLIST_START_FROM_1(0x00040000) 候補リスト文字列番号は1から開始
IME_PROP_UNICODE(0x00080000) 入力コンテキストはUNICODEを利用
IGP_CONVERSION(0x00000008)変換モードの能力
利用可能な IME_CMODE_xxxxx のビットがセットされる
IGP_SENTENCE(0x0000000c) センテンスモードの能力
利用可能な IME_SMODE_xxxxx のビットがセットされる
IGP_UI(0x00000010) ユーザインタフェースの能力
UI_CAP_2700(0x00000001) テキストの向きに 0 から 2700を指定できる
UI_CAP_ROT90(0x00000002) テキストの向きに 0, 900, 1800, 2700を指定できる
UI_CAP_ROTANY(0x00000004) テキストの向きに任意の値を設定できる
IGP_SETCOMPSTR(0x00000014) 文字列変換能力
SCS_CAP_COMPSTR(0x00000001) ImmSetCompositionString(SCS_SETSTR)実行時に 変換文字列を取得できる
SCS_CAP_MAKEREAD(0x00000002) ImmSetCompositionString(SCS_SETSTR)実行時に 変換仮名文字列を取得できる
IGP_SELECT(0x00000018) 選択の引継ぎ能力
SELECT_CAP_CONVMODE(0x00000001) 変換モードを新しいIMEが選ばれるとき引き継ぐ
SELECT_CAP_SENTENCE(0x00000002) センテンスモードを新しいIMEが選ばれるとき引き継ぐ
IGP_GETIMEVERSION((DWORD)(-4)) IMEのバージョンを取得する
IMEVER_0310(0x0003000A) Windows 3.1用
IMEVER_0400(0x00040000) Windows95用

7-4 アプリケーションについて

IMM API を利用したAPIの呼び出しを行うデモアプリケーションです。
ウィンドウ上に、IMEから取得できるIMEの能力や状態を表示します。 「IMM操作(M)」- 「開く」でIMEを起動させ、キー入力を行うと、「IME入力域」 にIMEの変換入力域を表示させます。ここでIMEから入力された文字列を 「変換された漢字」と「変換に利用された仮名」を表示します。
その他、「IMM操作(M)」-「動作許可」「動作抑制」で旧IMM API WINNLSEnableIME を 利用してIMEの動作を停止させることができます。
 IME97ではカナキーのロックは自動的に行われますが、IME95では、IMEにカナモードを 設定してもカナキーのロック状態は変化しません。このため、本サンプルで、IME95を 利用した場合、カナ入力を指定しても英数入力を設定したように振る舞います。 カナキーをロックするには、Win32 API keybd_event でカナキーが押下されたとき と同様の状態を作り出す必要があります。(本サンプルではサポートしていません。)  IME98では、IME95と同様に再びカナキーの制御を行わなくなりました。
カナキーを操作するための機能を他の方法でサポートしているかは不明ですが、 IME97の仕様に依存した処理を行うと、IME98では正しく動作しなくなる可能性 がありますので注意が必要です。

IMMTEST.EXE
 IMMTEST.H (本体ヘッダー)
 IMMTEST.C (本体)
 IMMCTL.H (IMM制御関数ヘッダー)
 IMMCTL.C (IMM制御関数)
 RESOURCE.H (リソースヘッダー)
 IMMTEST.RC (リソース)
 IMMTEST.ICO (アイコン)