入り口に戻る

原文はこちら

翻訳にあたって ai56go [Qiita]の「XIM(X Input Method)日本語入力の流れ」を参考にした。

IM Server Developers Kit - C Language Interface(日本語訳)

Hidetoshi Tajima

X11R6 Xi18n Implementation Group

May 15, 1994

1. 関数

1.1. IM サービスを開設する

XIMS IMOpenIM(Display display,...)

display X サーバとの接続を指定する。
... IMValues (IM 属性)を設定するための可変長引数リストを指定する。詳しくは第2章「IMValues」を参照。

 IMOpenIM は、入力メソッド・サービスへの接続を初期化するとともに、1つ以上の IMValues (IM の属性群)を設定するものである。この IMValues は、「可変長引数リスト」というプログラミング・インタフェイスを用いて指定する。IMOpenIM は、接続開設に成功した場合には、新たな XIMS 構造体を1つ割り当て、これを戻り値として返す。成功しなかった場合には、IMOpenIM は NULL を返す。XIMS は、不透明なデータ構造体であり、入力メソッド・サービスの抽象表現である。

 まず、IMOpenIM は予備接続メソッド(a preconnection method)を初期化する。クライアントは、この予備接続メソッドを使って IM サーバを探すことができる。予備接続の手続きの規約は、下に示す通り、IMProtocol(IM プロトコル)のモデルによって異なる。けれども、読者はこうした違いにそれほど注意を払う必要は無い。なぜかというと、IMOpenIM がそのような違いを包み隠してしまうからである。

R5 Ximp の予備接続の場合
IM サーバは、「_XIMP_%locale」のような文字列を表す ATOM (セレクション・アトム)の所有者となるウィンドウを作成しなければならない。クライントはこれを使用して IM サーバを探すことになる。

R6 IMProtocol (IM プロトコル)の予備接続の場合
IM サーバは、「@server=%im_name」のような文字列を表す ATOM (セレクション・アトム)の所有者となるウィンドウを作成しなければならず、このアトムをデフォルトのルート・ウィンドウのプロパティ「XIM_SERVERS」に格納されているリストに登録しなければならない(訳註:上と同じ。要確認)。このリストにはアトムの目録が入っており、各アトムが対象ディスプレイ上で利用可能な IM サーバの1つ1つを表している。

次いで、IMOpenIM はトランスポート接続(伝送接続)を初期化する。クライアントと IM サーバは、このトランスポート接続を通じて互いに IMProtocol (IM プロトコル)のデータを送受信することができる。トランスポート接続を初期化する手続きは、下に示す通り、トランスポート機構によって異なる。けれども、読者はこうした違いにそれほど注意を払う必要は無い。なぜかというと、ここでも IMOpenIM がそうした違いを覆い隠してしまうからである。

X のトランスポート接続の場合
IM サーバは、次のアトム群を割り当てなければならない(must intern)。即ち、IM サーバ固有の機能と特性の設定に使用するプロパティ群を表すアトム群(プロパティ名となるアトム)を割り当てなければならない。

TCP/IP の伝送接続の場合
IM サーバは、クライアントからの接続リクエストを待ち受けるための待受けソケットを開設しなければならない。

1.2. IM の属性群を設定する

char *IMSetIMValues(XIMS ims,...)

ims入力メソッド・サービスを指定する。
...IMValues(IM の属性群)を設定するための可変長引数リストを指定する。

 IMSetIMValues は、プログラミング・インタフェイスである「可変長引数リスト」を通じて指定された1つ以上の IMValues (IM の属性群)を、XIMS 構造体に登録するものである。IMOpenIM を使っても IMValues の全ての値を設定することができる上、IMValues の各属性の中には IMOpenIM を呼び出した時に設定しなければならない属性も存在することに注意。
 IMSetIMValues は、IMValues の全ての値の設定に成功した場合、NULL を返す。失敗した場合には、値の登録に失敗した最初の引数の名前を返す。

1.3. IM の属性群を取得する

char *IMGetIMValues(XIMS ims,...)

ims入力メソッド・サービスを指定する。
...IMValues (IM の属性群)を取得するための可変長引数リストを指定する。

 IMGetIMValues は、プログラミング・インタフェイスである「可変長引数リスト」を通じて指定された1つ以上の IMValues (IM 属性)を、XIMS 構造体から取得するものである。
 IMGetIMValues は、IMValues の全ての値の取得に成功した場合、NULL を返す。失敗した場合は、値の取得に失敗した最初の引数の名前を返す。

1.4. IM サービスの閉鎖

void IMCloseIM(XIMS ims)

ims閉鎖したい入力メソッド・サービスを指定する。

 IMCloseIM は、IMOpenIM によって開設された接続を閉鎖するものである。IMCloseIM は、XIMS 構造体の中の割り当てられていたデータを全て解放し、次いで XIMS 自体を解放する。

1.5. 前編集を開始する

int IMPreeditStart(XIMS ims, XPointer im_protocol)

ims入力メソッド・サービスを指定する。
im_protocol入力プロトコルのデータを指定する。

 Dynamic Event Flow 方式においては、IMPreeditStart を使って前編集を開始する。

 im_protocol に指定する構造体は、下に示す通り、IMProtocol (IM プロトコル)のモデルによって異なる。

/* R5 Ximp */
typedef struct {
    INT32	type;
    CARD32	icid;
    Window	focus_win;
    long	fwin_sel_mask;
    CARD32	ximp_type_mask;
    Window	client_win;
} XIMPPreeditStateStruct;
/* R6 IMProtocol */
typedef struct {
    int		major_code;
    int		minor_code;
    CARD16	connect_id;
    CARD16	icid;
} IMPreeditStateStruct;

1.6. 前編集を中断する

int IMPreeditEnd(XIMS ims, XPointer im_protocol)

ims入力メソッド・サービスを指定する。
im_protocol入力プロトコルのデータを指定する。

 Dynamic Event Flow 方式においては、IMPreeditEnd を使って前編集を中断する。但し、 IMValue (IM の属性)の1つである IMOffKeysList を使用してオフ・キー(off-keys)のリストを登録していた場合、IMPreeditEnd を使う必要は無いかもしれない。なぜかというと、 IMdkit は、登録済みのオフ・キーのいづれかと一致するキー・イベントを受信したとき、内部で IMPreeditEnd を呼び出すからである。そのため、オフ・キーのリストを登録していない場合に限って IMPreeditEnd を使用するようにすべきである(greatly encouraged)。

1.7. キー・イベントを送り返す

void IMForwardEvent(XIMS ims, XPointer im_protocol)

ims入力メソッド・サービスを指定する。
im_protocol入力プロトコルのデータを指定する。

 IMForwardEvent は、濾過で取り除かれない(non-filtered) KeyPress/KeyRelease イベントを送り返すために使用するものである。(訳註:fcitx-3.6.1/src/vk.c では「Backspace」「Tab」「Ins」「Del」を送り返している。)
 im_protocol に指定する構造体は、下に示す通り、IMProtocol (IM プロトコル)のモデルによって異なる。

/* R5 Ximp */
typedef struct {
    INT32	type;
    CARD32	icid;
    Window	focus_win;
    long	fwin_sel_mask;
    CARD32	ximp_type_mask;
    Window	client_win;
    CARD32	keycode;
    CARD32	state;
    CARD32	time;
} XIMPKeyEventStruct;
/* R6 IMProtocol */
typedef struct {
    int		major_code;
    int		minor_code;
    CARD16	connect_id;
    CARD16	icid;		/* input context ID */
    BITMASK16	sync_bit;	/* 同期をとって処理するか否か */
    CARD16	serial_number;
    XEvent	event;		/* 濾過処理される X イベント */
} IMForwardEventStruct;

1.8. 変換済み文字列を送致する(訳註:訳語要確認)

void IMCommitString(XIMS ims, XPointer im_protocol)

ims入力メソッド・サービスを指定する。
im_protocol入力プロトコルのデータを指定する。

 IMCommitString は、確定文字列(committed string)を送るために使うものである。この文字列の中には、IM サーバによって変換されたローカライズ済みのテキストが入っている(可能性がある)。
 im_protocol に指定する構造体は、下に示す通り、IMProtocol(IM プロトコル)のモデルによって異なる。

/* R5 Ximp */
typedef struct {
    INT32	type;
    CARD32	icid;
    Window	focus_win;
    long	fwin_sel_mask;
    CARD32	ximp_type_mask;
    Window	client_win;
    char	*ctext;
} XIMPCommitStringStruct;
/* R6 IMProtocol */
typedef struct {
    int		major_code;
    int		minor_code;
    CARD16	connect_id;
    CARD16	icid;		/* input context ID */
    CARD16	flag;
	/* bit combination to tell the receiver what to do */
		#0001	: process it synchroously, return XIM_SYNC_REPLY
		#0002	: Lookup Chars
		#0004	: Lookup KeySym
		#0006	: Lookup Both = Lookup Chars and KeySym
	 */
    KeySym	keysym;		/* returned keysym */
    char	*commit_string;	/* string to commit to XIM client */
} IMCommitStruct;

1.9. コールバック関数を呼び出す

int IMCallCallback(XIMS ims, XPointer im_protocol)

ims入力メソッド・サービスを指定する。
im_protocol入力プロトコルのデータを指定する。

 IMCallCallback を使えば、読者の IM サーバから、直前の IM プロトコル・リクエストを用いて(訳註:with 要確認)非同期にコールバック・リクエストを送信することができる。コールバック・リクエストの型は、読者の IM サーバによって、im_protocol のデータ構造体の適切なメンバに設定されていなければならない。加えて、コールバック・リクエストを発する前に新たな IMProtocol 構造体(IMProtocol という名前の構造体)を宣言するのは読者(実装者)の仕事である。
 im_protocol に指定する構造体は、下に示す通り、IMProtocol(IM プロトコル)のモデルによって異なる。

/* R6 IMProtocol の場合*/
 コールバック・リクエストの型を IMProtocol 構造体(IMProtocol という名前の構造体)の major_code メンバと minor_code メンバに設定しておかなければならない。例えば、ジオメトリ管理のコールバックを開始するには、次のようなコードを書く。

IMGeometryCBStruct geometry;
...
geometry.major_code = XIM_GEOMETRY;
geometry.connect_id = previous_request->any.connect_id;
...
IMCallCallback(ims, (IMProtocol)&geometry);

 R6 IMProtocol(IM プロトコル)のコールバックのための構造体には、次の3つのものがある。

/* for Geometry Callback */
typedef struct {
    int		major_code;
    int		minor_code;
    CARD16	connect_id;
    CARD16	icid;
} IMGeometryCBStruct;
/* for Preedit Callback */
typedef struct {
    int		major_code;
    int		minor_code;
    CARD16	connect_id;
    CARD16	icid;
    union {
	int	return_value;			/* PreeditStart */
	XIMPreeditDrawCallbackStruct draw;	/* PreeditDraw */
	XIMPreeditCaretCallbackStruct caret; 	/* PreeditCaret */
    } todo;
} IMPreeditCBStruct;
/* for Status Callback */
typedef struct {
    int		major_code;
    int		minor_code;
    CARD16	connect_id;
    CARD16	icid;
    union {
	XIMStatusDrawCallbackStruct draw;
    } todo;
} IMStatusCBStruct;

 R5 Ximp のコールバックのための構造体には次の3つのものがある。

/* for Geometry Callback */
typedef struct {
    INT32	type;
    CARD32	icid;
    Window	focus_win;
    long	fwin_sel_mask;
    CARD32	ximp_type_mask;
    Window	client_win;
} XIMPAnyStruct;
/* for Preedit Callback */
typedef struct {
    INT32	type;
    CARD32	icid;
    Window	focus_win;
    long	fwin_sel_mask;
    CARD32	ximp_type_mask;
    Window	client_win;
    union {
	int	return_value;			/* PreeditStart */
	XIMPreeditDrawCallbackStruct draw;	/* PreeditDraw */
	XIMPreeditCaretCallbackStruct caret; 	/* PreeditCaret */
    } todo;
} XIMPPreeditCBStruct;
/* for Status Callback */
typedef struct {
    INT32	type;
    CARD32	icid;
    Window	focus_win;
    long	fwin_sel_mask;
    CARD32	ximp_type_mask;
    Window	client_win;
    union {
	XIMStatusDrawCallbackStruct draw;	/* StatusDraw */
    } todo;
} XIMPStatusCBStruct;

2. IMValues(IM の属性群)

(訳註:以下の「引数」は、関数 IMOpenIM、IMSetIMValues、IMGetIMValues の引数となるものである。)

2.1. IMModifiers

 引数 IMModifiers は、文字列型であり、IMProtocol (IM プロトコル)のモデルの名前を指定するものである。 現在の版では、IMdkit は3種類の名前しか受け付けていない。(訳註:下の2つともう1つは?)

"Xi18n"R6 規格の IMProtocol(IM プロトコル) モデルを指定。
"XIMP"R5 の Ximp モデルを指定。

 引数 IMModifiers の設定は IMOpenIM を呼び出した際の1回だけに留めなければならず、同引数は IM サーバ実行中に変更してはならない。

2.2. IMServerWindow

 引数 IMServerWindow は、Window 型であり、XIM クライアントとの予備接続で用いるメソッドを特定するためのウィンドウを指定するものである。この第1の用途に加えて、IMServerWindow は 、他の用途(使用される IMProtocol (IM プロトコル)のモデル次第で必要となるもの)にも使用することができる。
 この引数が指定されていない場合、デフォルトのウィンドウ(使用される IMProtocol (IM プロトコル)のモデル次第で定まるもの)を IMdkit が用意する。この引数を指定する場合、指定は IMOpenIM もしくは IMSetIMValues のどちらかによって1回だけ行われるようにしなければならず、同引数は IM サーバ実行中に変更してはならない。

2.3. IMServerName

 引数 IMServerName は、文字列型であり、IM サーバの名前を指定するものである。この引数は、IM サーバの識別子(XIM クライアントが IM サーバを探すために用いるもの)の一部として使用することもできる。
 引数 IMServerName の設定は IMOpenIM を呼び出した際の1回だけに留めなければならず、同引数は IM サーバ実行中に変更してはならない。

2.4. IMLocale

 引数 IMLocale は、文字列型であり、IM サーバが対応しているロケールのリスト(目録)を指定するものである。この引数は、IM サーバの識別子(XIM クライアントが IM サーバを探すために用いるもの)の一部として使用することもできる。
 引数 IMLocale の設定は IMOpenIM を呼び出した際の1回だけに留めなければならず、同引数は IM サーバ実行中に変更してはならない。

2.5. IMServerTransport

 引数 IMServerTransport は、文字列型であり、IM サーバが用いるトランスポート接続機構の名前を指定するものである。この引数は、IM サーバの識別子(XIM クライアントが IM サーバを探すために用いるもの)の一部として使用することもできる。
 この引数のために予め登録されている書式を以下に示す。(*1)

(*1) 「The Input Method Protocol」の附録 B にある「各トランスポート方式固有の IM サーバ・アドレスの書式の登録リスト」を参照。

TCP/IP の名前の場合
------------
インターネット・ドメイン名の構文:

<TCP name> ::= "tcp/"<hostname>":"<ipportnumber>

 <hostname> には、ホスト・マシンの名前のシンボルの書式(数字+ピリオドでないもの)、あるいはホスト・マシンの名前の数字とピリオドによる書式のどちらかが入る。<ipportnumber> は、IM サーバが接続を待ち受けているポートの番号である。

システム内部のドメイン名の構文:

<local name> ::= "locale/"<hostname>":"<pathname>

 <pathname> には、ソケット・アドレスの経路名が入る。

DECnet の名前の場合
------------
DECnet 名の構文:

<DECnet name> ::= "decnet/"<nodename>"::IMSERVER$"<objname>

 <nodename> には、DECnet アドレスのシンボルの書式、あるいは DECnet アドレスの数字とピリオドによる書式のどちらかが入る。<objname> には大文字と小文字を区別する、DECnet の通常のオブジェクト名が入る。

X の名前の場合
-------
X の名前の構文:

<X name> ::= "X/"

 引数 IMServerTransport の設定は IMOpenIM を呼び出した際の1回だけに留めなければならず、同引数は IM サーバ実行中に変更してはならない。

2.6. IMInputStyles

 引数 IMInputStyles は、型は XIMStyles 型であり、IM サーバが対応している入力方式のリスト(目録)を指定するものである。
 この引数が指定されなかった場合、デフォルトのリスト(使用される IMProtocol (IM プロトコル)のモデル次第で定まるもの)を IMdkit が用意する。同引数は、IMOpenIM でも IMSetIMValues でも設定可能だが、IM サーバの実行中に変更するべきでない。

2.7. IMProtocolHandler

 引数 IMProtocolHandler は、型は IMProtoHandler 型であり、コールバック関数を指定するものである。このコールバック関数は、IM の main ループで XIM クライアントから IMProtocol (IM プロトコル)の入力を受け取る度に呼び出される。関数 IMProtocolHandler の型(prototype)は次の通り。(訳註:x.org/releases/unsupported/lib/IMdkit/IMdkit/Xi18n/Xi18n.h においては、型名は IMProtoHandler であり、引数は XIMS と IMProtocol* である。「typedef int (*IMProtoHandler)(XIMS, IMProtocol*);」)

typedef int (*IMProtoHandler)();

int ProtocolHandlerProc(ims, call_data)
XIMS ims;
XPointer call_data;

call_data は IMProtocol 構造体を参照する。

2.8. IMOnKeysList

 引数 IMOnKeysList は、型は XIMTriggerKeys 型であり、Dynamic Event Flow モデルで前編集を開始するためのキーのリストを指定するものである。IMOnKeysList 属性(IMOnKeysList IMValue)は、Dynamic Event Flow モデルを採用する IM サーバが必ず持っていなければならない属性である。これによって IM ライブラリは、ここに登録したオン・キー(on-keys)のいづれかが現れた事実を添えて、IM サーバに対して前編集を開始するためのリクエストを送信することができるようになる。
 IMOnKeysList が指定されていない場合、デフォルトのものは提供されず、Static Event Flow モデルが採用されることになる。
 XIMTriggerKeys 構造体は IMdkit にて次のように定義されている。

typedef struct {
    CARD32	keysym;
    CARD32	modifier;
    CARD32	modifier_mask;
} XIMTriggerKey;
typedef struct {
    unsigned short count_keys;
    XIMTriggerKey *keylist;
} XIMTriggerKeys;

2.9. IMOffKeysList

 引数 IMOnKeysList は、型は XIMTriggerKeys 型であり、Dynamic Event Flow モデルで前編集を終了するためのキーのリストを指定するものである。IMOffKeysList 属性(IMOffKeysList IMValue)は、Dynamic Event Flow モデルを採用する IM サーバにとって必須のものではない。
 IMOffKeysList が指定されている場合、IM ライブラリは、ここに登録したオフ・キー(off-keys)のいづれかが現れた事実を添えて、IM サーバに対して前編集を中断するためのリクエストを送信することができる。IMOffKeysList が指定されていない場合、IM サーバは、自分(IM サーバ)が前編集を中断したいと思った時、IMPreeditEnd を呼び出し、前編集を中断することを IM ライブラリに知らせる。
 IMOffKeysList が指定されていない場合、デフォルトのものは提供されない。

2.10. IMEncodingList

 引数 IMEncodingList は、型は XIMEncodings 型であり、IM サーバが対応している符号化方式のリストを指定するものである。XIM クライアントは、IM サーバへの接続を確立した後、直ちにこの引数の通知を受ける。
 引数 IMEncdoingList の用途は、IM サーバと XIM クライアントとの間でローカライズ(特定地域化)されたテキストをやり取りするにあたって、どの符号化方式が利用可能なのかを指定することである。
 この引数が指定されていない場合、予備のデフォルト設定として使用できるのは「COMPOUND_TEXT」符号化方式のみである。
 XIMEncodings 構造体は、IMdkit にて次のように定義されている。

typedef char *XIMEncoding;

typedef struct {
    unsigned short count_encodings;
    XIMEncoding *supported_encodings;
} XIMEncodings;

2.11. IMFilterEventMask

 引数 IMFilterEventMask は、long 型であり、前編集の実施中に IM サーバが濾過して取り除くべきイベント群を指定するものである。
 この引数が指定されていない場合、KeyPressMask (1L<<0) が予備のデフォルト設定となる。

2.12. IMProtocolDepend

 引数 IMProtocolDepend を使って、各 IMProtocol (IM プロトコル)モデル専用の IM 属性(IM values)を指定することができる(そのような属性が存在する場合)。この属性は、XVaCreateNestedList() で生成される入れ籠状の可変長リストを通じて、IMOpenIM、IMSetIMValues、IMGetIMValues に渡される。今版では、IMProtocolDepend のリストに入る名前としては、R5 Ximp モデルのものしか定義されていない。同モデルのものを以下に示す。

2.12.1. R5 Ximp 専用の IM 属性(IM Values)

XIMPVersion

 引数 XIMPVersion は、文字列型であり、R5 Ximp モデルの版を指定するものである。

意味
-----------------------------------
"3.5" Ximp バージョン 3.5 のモデルに対応
"4.0" Ximp バージョン 4.0 のモデルに対応
XIMPType

 引数 XIMPType (訳註:原文は「XIMPVersion」)は、unsigned long 型のリストへのポインタであり、ビットマスク(の組み合わせ)のリストの指定するものである。このビットマスクの各ビットは、読者(実装者)の IM サーバが対応しているイベント・フローのモデルを表す。同リストの中で使用可能な値すべての定義を以下に挙げる。(*)

(*) X11R5 contribution の中にある「Protocol Specification for the Distributes Input System on the X Window System, Version 11」を参照。(訳註:X11R5/mit/doc/I18N/Ximp/Ximp3_3.doc にある。)

XIMP_BE_TYPE1
バックエンド型である。IM ライブラリは、登録されているキーを認識し、サーバに対してキー・イベントの処理を開始するよう通告する。
XIMP_FE_TYPE1
フロントエンド型である。IM ライブラリは、登録されているキーを認識し、サーバに対してキー・イベントの処理を開始するよう通告する。
XIMP_BE_TYPE2
バックエンド型である。IM ライブラリは登録されているキーを一切認識せず、常に IM サーバが先にキー・イベントを処理する。
XIMP_FE_TYPE2
フロントエンド型である。IM ライブラリは登録されたキーを一切認識せず、常に IM サーバが先にキー・イベントを処理する。
XIMP_FE_TYPE3
フロントエンド型である。キー・イベントは常に IM サーバと IM ライブラリの両方に渡される。両者とも登録されているキーを認識する。
XIMP_SYNC_BE_TYPE1
XIMP_BE_TYPE1 と同じであるが、KeyPress は同期を取って転送される。
XIMP_SYNC_BE_TYPE2
XIMP_BE_TYPE2 と同じであるが、KeyPress は同期を取って転送される。
XIMPExtension

 引数 XIMPExtension を使うと、予め登録してある拡張群を有効にしたり無効にしたりすることができる。同引数のリストは、XVaCreateNestedList() を通じて生成された入れ籠状の可変長リストである。今版においては、XIMPExtension のリストで使用可能であって且つ予め登録されている拡張は、以下のものが定義されている。

XIMPExtStatusWin
これがリストに含まれている場合、入力コンテクスト属性 XNExtXimp_StatusWindow は有効で、状態ウィンドウ(status window)を設定することができる。属性値は評価されない(訳註:属性名と属性の値の組を指定するわけだが、属性の値の方は何でもよいということ。www.x.org/releases/unsupported/lib/IMdkit/Ximp_sample/sampleIM.c において、値には「True」を指定している)。
XIMPExtBackFront
これがリストに含まれている場合、入力コンテクスト XNExtXimp_Backfront は有効であり、フロント・エンド方式かバック・エンド方式かを選択できる。属性値は評価されない(訳註:www.x.org/releases/unsupported/lib/IMdkit/Ximp_sample/sampleIM.c において、値には「1」を指定している)。
XIMPExtConversion
これがリストに含まれている場合、入力コンテクスト XNExtXimp_Conversion は有効であり、入力モードを設定することができる。属性値は評価されない(訳註:www.x.org/releases/unsupported/lib/IMdkit/Ximp_sample/sampleIM.c において、値には「True」を指定している)。

3. X・IMProtocol (IM プロトコル)で使用する構造体

 X・IMProtocol (IM プロトコル)の各種入力には、その入力のための構造体が定義されている(IMdkit の公開ヘッダ・ファイルの中で定義)。<X11/Ximd/Xi18n.h> では、R6 規格の IMProtocol モデルで使用する IMProtocol (IM プロトコル)構造体が全て定義されている。<X11/Ximd/Ximp.h> では、R5 Ximp モデルのものが全て定義されている。

3.1. R6 IMProtocol (IM プロトコル)

3.1.1. IMProtocol 共用型データ構造体

 R6 規格の IMProtocol モデルにおいては、全てのイベント構造体は次の共通メンバを持つ。

typedef struct {
    int major_code;	/* major code of last IMProtocol */
    int minor_code;	/* minor code of last IMProtocol */
    CARD16 connect_id;	/* client connection ID */
} IMAnyStruct;

 major_code と minor_code は、IMProtocol (IM プロトコル)の型の名前を表す。この名前は、定数であり、IM プロトコルの型を一意に指定するものである。
 IMProtocol (IM プロトコル)の各型に対して個別の構造体が宣言されている。また、IMProcotol 構造体(「IMProtocol」という名前の構造体)の実体は、そうした個別の構造体の共用体である。(操作対象の) IM プロトコルの型に従いつつ、IMProtocol 共用体を使って、それぞれの IM プロトコルの構造体のメンバにアクセスするものとする。

typedef union _IMProtocol {
    int	major_code;
    IMAnyStruct any;
    IMConnectStruct imconnect;
    IMDisConnectStruct imdisconnect;
    IMOpenStruct imopen;
    IMCloseStruct imclose;
    IMQueryExtensionStruct queryext;
    IMGetIMValuesStruct getim;
    IMEncodingNegotiationStruct encodingnego;
    IMExtSetEventMaskStruct extsetevent;
    IMExtForwardKeyEventStruct extforward;
    IMExtMoveStruct extmove;
    IMSetEventMaskStruct setevent;
    IMChangeICStruct changeic;
    IMDestroyICStruct destroyic;
    IMResetICStruct resetic;
    IMChangeFocusStruct changefocus;
    IMCommitStruct commitstring;
    IMForwardEventStruct forwardevent;
    IMTriggerNotifyStruct triggernotify;
    IMErrorStruct imerror;
    IMGeometryCBStruct geometry_callback;
    IMPreeditCBStruct preedit_callback;
    IMStatusCBStruct status_callback;
    long pad[32];
} IMProtocol;

 いづれの IMProtocol 構造体においても、最初の2つのエントリは必ず major_code と minor_code であり、これが IMProtocol (IM プロトコル)の型を表す。3番目のメンバは connect_id member であり、これは専ら IMdkit が内部でクライアントを識別するために使用するものである。

3.1.2. プロトコルの処理

 IM ライブラリから送られた IM プロトコル・リクエストの一部は、IMdkit によって内々に処理され、読者の IM サーバへは渡されない。なぜかというと、IMdkit は、XIMS 構造体に設定されている IMValues (IM 属性)を利用するだけで、そのような IM プロトコル・リクエストへの回答を決めることができるからである。
 今版では、次の4つの IM プロトコル・リクエストは、 IMdkit 自身によって処理され、読者の IM サーバへは送られない。

 そのため、読者は、これらの IM プロトコル・リクエストで使用する IMProtocol 構造体の中身を知る必要は無い。

 一方、次に挙げるリクエストについては、読者は自分でこれらを処理する必要がある。

 読者は生のパケットを受け取る必要は無いが、自分のコールバック関数 IMProtocolHandler で同パケットに対応する IMProtocol 構造体を受け取ることができる。また、読者は自分でリプライ(返答)を送信する必要は無いが、読者の IMProtocolHandler が返った後、直ちに IMdkit がリプライを送信する。読者の IMProtocolHandler が True を返した場合、IMdkit は直前のリクエストに対して適切なリプライを送信する。IMProtocolHandler が False を返した場合、IMdkit は XIM クライアントへ XIM_ERROR リプライを送信する。
 以下に挙げる IMProtocol 構造体は、IM プロトコル・リクエストの代わりとして、読者が自分の IMProtocolHandler 関数で実際に受け取るものである。

IMOpenStruct
------------
 IMOpenStruct 構造体は、XIM_OPEN リクエストと XIM_OPEN_REPLY リクエストで使用される。構造体の中身は次の通り。

typedef struct {
    int length;
    char *name;
} XIMStr;
typedef struct {
    int major_code;
    int minor_code;
    CARD16 connect_id;
    XIMStr lang;
} IMOpenStruct;

 読者作成の IM サーバは、新たなクライアントがどの言語サービスを必要としているのかを知るために、lang フィールドを調べるものとする。同クライアントは connect_id メンバで識別する。

IMCloseStruct
-------------
 IMCloseStruct 構造体は、XIM_CLOSE リクエストと XIM_CLOSE_REPLY リクエストで使用される。構造体の中身は次の通り。

typedef struct {
    int		major_code;
    int		minor_code;
    CARD16	connect_id;
} IMCloseStruct;

 読者作成の IM サーバは、どの入力メソッド接続を閉鎖すべきなのかを知るために、connect_id メンバを調べるものとする。

IMChangeFocusStruct
-------------------
 IMChangeFocusStruct 構造体は、XIM_SET_IC_FOCUS リクエストと XIM_UNSET_IC_FOCUS リクエストで使用される。構造体の中身は次の通り。

typedef struct {
    int major_code;
    int minor_code;
    CARD16 connect_id;
    CARD16 icid;	/* フォーカスを変更すべき入力コンテクストの ID */
} IMChangeFocusStruct;

 読者作成の IM サーバは、どの入力コンテクストにフォーカスを設定すべきなのか、あるいはどの入力コンテクストのフォーカスを解除すべきなのかを知るために、icid メンバを調べるものとする。

IMDestroyICStruct
-----------------
 IMDestroyICStruct 構造体は、XIM_DESTROY_IC リクエストで使用される。構造体の中身は次の通り。

typedef struct {
    int major_code;
    int minor_code;
    CARD16 connect_id;
    CARD16 icid;	/* 破棄すべき入力コンテクストの ID */
} IMDestroyICStruct;

 読者作成の IM サーバは、どの入力コンテクストを破棄すべきなのかを知るために、icid メンバを調べるものとする。

IMResetICStruct
---------------
 IMResetICStruct 構造体は、XIM_RESET_IC リクエストで使用される。構造体の中身は次の通り。

typedef struct {
    int major_code;
    int minor_code;
    CARD16 connect_id;
    CARD16 icid;	/* リセットすべき入力コンテクストの ID */
    CARD16 length;	/* 次の確定文字列の長さ */
    char *commit_string; /* XIM クライアントに送致するべき文字列 */
} IMResetICStruct;

 読者作成の IM サーバは、どの入力コンテクストをリセットすべきなのかを知るために、icid メンバを調べるものとする。

IMChangeICStruct
----------------
 IMChangeICStruct 構造体は、リクエスト XIM_CREATE_IC、XIM_SET_IC_VALUES 及び XIM_GET_IC_VALUES で使用される。構造体の中身は次の通り。

/*
 *  value type for IC defined in XimProto.h
 */
#define	XimType_SeparatorOfNestedList	 0
#define	XimType_CARD8			 1
#define	XimType_CARD16			 2
#define	XimType_CARD32			 3
#define	XimType_STRING8			 4
#define	XimType_Window			 5
#define	XimType_XIMStyles		10
#define	XimType_XRectangle		11
#define	XimType_XPoint			12
#define XimType_XFontSet		13
#define XimType_XIMOptions		14
#define XimType_XIMHotKeyTriggers	15
#define XimType_XIMHotKeyState		16
#define XimType_XIMStringConversion	17
#define	XimType_NEST			0x7fff
typedef struct {
    int attribute_id;	/* ID for this IC */
    CARD16 name_length;	/* length of IC name below */
    char *name;		/* IC name */
    int value_length;	/* length of IC value below */
    void *value;	/* IC value */
    int type;		/* value type for IC, see above */
} XICAttribute;
typedef struct {
    int major_code;
    int minor_code;
    CARD16 connect_id;
    CARD16 icid;
	/* input context ID:
	   for each CREATE, different ID is expected to be returned.
	   for each SET, it shows the ID to set.
	   for each GET, it shows the ID to get.
	 */
    CARD16 preedit_attr_num;	/* number of preedit_attr list below */
    CARD16 status_attr_num;	/* number of preedit_attr list below */
    CARD16 ic_attr_num;		/* number of ic_attr list below */
    XICAttribute *preedit_attr;	/* IC values for preedit attribute */
    XICAttribute *status_attr;	/* IC values for status attribute */
    XICAttribute *ic_attr;	/* IC values for other attributes */
} IMChangeICStruct;

 XIM_SET_IC_VALUES もしくは XIM_GET_IC_VALUES の場合、読者作成の IM サーバは、どの入力コンテクストを対象とするべきなのかを知るために、icid メンバを調べるものとする。XIM_CREATE_IC の場合、読者作成の IM サーバは、新たに作成された入力コンテクストを識別するために、icid メンバを(新たに)設定するものとする。

IMTriggerNotifyStruct
---------------------
 IMTriggerNotifyStruct 構造体は、XIM_TRIGGER_NOTIFY リクエストで使用される。構造体の中身は次の通り。

typedef struct {
    int major_code;
    int minor_code;
    CARD16 connect_id;
    CARD16 icid;
    CARD32 flag;
    CARD32 key_index;
    CARD32 event_mask;
} IMTriggerNotifyStruct;

IMForwardEventStruct
--------------------
 IMForwardEventStruct 構造体は、XIM_FORWARD_EVENT リクエストで使用される。構造体の中身は次の通り。

typedef struct {
    int major_code;
    int minor_code;
    CARD16 connect_id;
    CARD16 icid;	/* input context ID */
    BITMASK16 sync_bit;	/* precessed synchronously or not */
    CARD16 serial_number;
    XEvent event;	/* X event to be filtered */
} IMForwardEventStruct;

3.2. R5 Ximp の IMProtocol (IM プロトコル)

3.2.1. 「XIMProtocol」 共用型データ構造体

R5 Ximp IMProtocol モデルにおいては、全てのイベント構造体は次の共通メンバを持つ。

typedef struct {
    INT32 type;		/* message type */
    CARD32 icid;	/* input context ID */
    Window focus_win;	/* focus window */
    long fwin_sel_mask; /* focus window select-mask */
    CARD32 ximp_type_mask; /* Ximp event flow type */
    Window client_win;	/* client window */
} XIMPAnyStruct;

 type メンバは、Ximp IMProtocol (Ximp IM プロトコル)の型の名前を表す。この名前は、定数であり、Ximp IMProtocol (Ximp IM プロトコル)の型を一意に指定するものである。
 Ximp の「XIMProtocol」の各型に対して個別の構造体が宣言されている。また、Ximp IMProtocol 構造体の実体は、そうした個別の構造体の共用体である(IMPProtocol)。(操作対象の) Ximp IM プロトコルの型に従いつつ、 XIMProtocol(IMPProtocol) 共用体を使って、それぞれの Ximp IMProtocol (Ximp IM プロトコル)の構造体のメンバにアクセスするものとする。

typedef union _IMPProtocol {
    int				type;
    XIMPAnyStruct		any;
    XIMPKeyEventStruct		keyevent;
    XIMPICValuesStruct		create;
    XIMPICValuesStruct		setvalue;
    XIMPICValuesStruct		getvalue;
    XIMPAnyStruct		destroy;
    XIMPAnyStruct		regkey;
    XIMPAnyStruct		setfocus;
    XIMPAnyStruct		unsetfocus;
    XIMPClientWindowStruct	clientwin;
    XIMPFocusWindowStruct	focuswin;
    XIMPMoveStruct		move;
    XIMPEventMaskNotifyStruct	evmasknotify;
    XIMPExtensionStruct		extension;
    XIMPReadPropStruct		readprop;
    XIMPResetStruct		reset;
    XIMPCommitStringStruct	commitstring;
    XIMPErrorStruct		error;
    XIMPAnyStruct		geometry_cb;
    XIMPPreeditCBStruct		preedit_cb;
    XIMPStatusCBStruct		status_cb;
    long			pad[24];
} IMPProtocol;

 XIMProtocol(IMPProtocol)構造体の第1のエントリは常に type メンバであり、これは Ximp IMProtocol (Ximp IM プロトコル)の型を表す。

4. IM サーバを実装する

 IMdkit を使用した IM サーバのコードを書く場合、同 IM サーバには以下のことを行わせるものとする。

  1. 読者作成の IM サーバ・プログラムに <X11/Xlib.h> を取り込む。
  2. <X11/Ximd/IMdkit.h> を取り込む。このヘッダ・ファイルには、読者が使う必要のあるデータ型と IMdkit 関数の全てが定義してある。
  3. R6 規格の IM プロトコル を使用する場合、<X11/Ximd/Xi18n.h> を取り込む。あるいは R5 Ximp の IM プロトコルを使用する場合、<X11/Ximd/Ximp.h> を取り込む。
  4. 必要な IMValues (IM 属性)を全て指定して IMOpenIM 関数を呼び出し、接続を初期化する。各 IMValues の名前は、「IM」から始まる大域的なシンボルを持つ。これは、綴りの間違いを見つけやすくするためである。例えば、XIMProtocol モデルを表すために IMModifiers が定義されており、ロケール資源を表すために IMLocale が定義されている。詳しくは、「1.1. IM サービスを開設する」の節と「2. IMValues(IM の属性群)」の章を参照。
  5. 追加の IMValues (IM 属性)を設定する場合、あるいは IMOpenIM で設定した既存の IMValues を書き換える場合、IMSetIMValues を使用する。また、IMGetIMValues を使用して既存の IMValues を調べることができる。一部の IMValues は、IM サービス作成時に設定しなければならず、且つ IMSetIMValues によっては変更できないことに注意。
  6. IMOpenIM 関数あるいは IMSetIMValues 関数にて、引数 IMProtocolHandler を通じて IM プロトコルのコールバック・ルーチンを設定しなければならない。このコールバックは、XIM クライアントによって IM プロトコルが送られてくる度に呼び出される。
  7. ここまで来たら、XSelectInput 関数を用いて必要な X イベント全てを読者が使うウィンドウ群に対して選択し、同ウィンドウ群を XMapWindow 関数を用いてマップし、それから次のようなイベント処理ループに入る。
    for (;;) {
      XEvent event;
      XNextEvent(your_display, &event);
      if (XFilterEvent(&event, NULL) == True)
        continue;
      YourXEventHandler(&event);
    }
  8. ここでは、読者が必要とする IM プロトコルは全て、XFilterEvent 関数による X のフィルタリング機構(濾過機構)を通じて、読者の IM プロトコル・コールバック・ルーチンへ渡される。そして、濾過で残った X イベント(読者が欲するもの)は全て、上記の YourXEventHandler 関数へ渡される。
  9. 読者の IM サーバを libXimd と libX11 (X 本体のライブラリ)にリンク(結合)する。参考のコマンド・ラインを以下に示す。
    cc -o sampleIM sampleIM.c -lXimd -lX11
    

入り口に戻る