このドキュメントでは、Java Development Kit リリース 1.2 で採用されている Input Method Framework について説明します。このフレームワークを使うと、テキスト編集コンポーネントの開発者は、大規模な文字セットを持つ言語のテキスト入力を可能にするインプットメソッドと連携するテキスト編集コンポーネントを作成できます。JDK 1.2 では、ホストプラットフォームのネイティブなインプットメソッドとともに、IIIMP アダプタ経由でサーバベースのインプットメソッドも使われます。JDK の将来のバージョンでは Java プログラミング言語で記述されたインプットメソッドも使えるよう、フレームワークは簡単に拡張できるように設計されています。
インプットメソッドの概要およびさまざまなプラットフォームへのインプットメソッドの実装について、このドキュメントの内容だけでは十分ではありません。次の書籍も参考にしてください。
API の詳細な定義については、javadoc で生成された API のドキュメントを参照してください。API の使用方法については、サンプルコードを参照してください。
フィードバックは、java-intl@java.sun.com にお送りください。
インプットメソッドは、キー入力、音声入力、ペンデバイスを使った手書き入力などのユーザ操作を変換し、アプリケーションへのテキスト入力を生成するソフトウェアコンポーネントです。もっとも一般的なインプットメソッドは、中国語や日本語や韓国語など数千の異なる文字を使う言語を、通常のサイズのキーボードで入力できるようにするためのものです。テキストの入力は通常サイズのキーボードで扱える形式 (たとえばローマ字) で行われて、入力されたあとでテキストは目的の言語の形式に変換されます。一般に、複数の文字を入力してから、1 つのかたまりとして変換する必要があります。また、変換候補が 1 つだけではないこともあるので、変換を繰り返し行わなければならない場合があります。同様に、手書き文字の認識では、ユーザは一連の文字を書き、変換し、複数の変換結果候補から正しいテキストを選択します。
この「変換」処理が行われている間、テキストは論理的にはインプットメソッドに属していますが、ユーザに対してはそのまま表示しておく必要があります。そのために、Input Method Framework はインプットメソッドと協調して、少なくとも 2 種類の方法を提供します。最新のテキスト編集コンポーネントの場合は、最終的に配置されることになるドキュメント内の位置に、インプットメソッドによる変換または確定がまだ必要であることを示す形式で、入力テキストを表示できます。この方法を、「オンザスポット編集」と呼びます。また、確定してからでないとテキストを扱えない旧式のテキスト編集コンポーネントの場合は、代替手段として、テキストを別のウィンドウで表示できるようにします。この方法を、「ルートウィンドウ編集」と呼びます。
JDK 1.1 では、インプットメソッドを使ったテキスト入力は、AWT の TextField
コンポーネントと TextArea
コンポーネントについてだけサポートされており、プラットフォームのネイティブなインプットメソッド機能を使っていました。JDK 1.1.6 以降のバージョンでは、軽量テキストコンポーネント (Swing テキストコンポーネントなど) は、ルートウィンドウ形式の入力を使用してインプットメソッドからテキスト入力を受け取れるようになりました。
JDK 1.2 の Input Method Framework で定義されているクラスとインタフェースを使うと、どのようなテキスト編集コンポーネントでも、インプットメソッドを通してテキストを受け取ることができます。コンポーネントでは、インプットメソッドの API を積極的に使って、オンザスポットの入力形式をサポートできます。オンザスポット入力がサポートされていない場合、フレームワークは代替形式としてルートウィンドウの入力形式を提供します。JDK 1.2 では、ホストプラットフォームのネイティブなインプットメソッドとともに、IIIMP (Internet-Intranet Input Method Protocol) 対応のアダプタを通して、サーバベースのインプットメソッドも使います。JDK の将来のバージョンにおける Java プログラミング言語で記述されたインプットメソッドの使用も考慮して、フレームワークは簡単に拡張できるように設計されています。
Input Method Framework を使うテキスト編集コンポーネントは、任意の Java アプリケーション環境で動作し、その Java アプリケーション環境で利用可能なテキストインプットメソッドをサポートします。テキスト編集コンポーネントの変更または再コンパイルは、必要ありません。フレームワークは、プラットフォームに依存しない API をテキスト編集コンポーネントに提供し、ネイティブなインプットメソッドが必要な場合は、プラットフォームの API にマッピングします。
Input Method Framework は、言語に依存しない入力処理用の API を提供し、完全に世界共通のアプリケーションにおけるニーズに応えます。インプットメソッドは、主に東アジア系の言語のテキスト入力に使われますが、ほかの言語に対しても同じように役に立つ場合があります。たとえば、ラテン文字を使ってギリシア文字を入力するための文字変換用インプットメソッドを作ることができます。
フレームワークは、異なる言語のインプットメソッドを同時に処理して、真の多言語テキスト編集を実現します。テキストの言語に対応した操作をアプリケーションで実行できるよう、テキストには言語属性を持たせることができます。
同様に、フレームワークを使うと、テキスト編集コンポーネントは、さまざまなインプットメソッドエンジンの間にある違いから切り離されます。特に、インプットメソッドと対話するための方法として、ただ 1 つのプログラミングモデルが提供されます。これにより、開発者は 1 つのインプットメソッド API に対してだけプログラムを記述すればよく、ユーザは目的に合ったインプットメソッドを選択できます。
ほとんどの開発者にとって言語とエンジンの独立性は重要なことですが、高度な機能を開発する者には、言語またはエンジンに固有の機能が必要になる場合があります。フレームワークではこのような固有機能も利用できますが、アプリケーションの汎用性が犠牲になることは避けられません。
Input Method Framework は、さまざまな入力装置に対応できるように設計されています。現在、テキスト入力の手段はほとんどキーボードですが、ほかの装置の重要性も増しつつあります。テキスト入力の方法として、ペン入力だけを採用しているプラットフォームもあります。また、音声入力も広く普及しつつあります。今後のリリースでは、これらの代替装置のサポートも可能になる予定です。
Input Method Framework は、Java プラットフォームの一部として設計されています。インプットメソッドとテキストコンポーネントの間でのテキスト交換に必要な新しいクラスは、Java 2D や Swing テキストコンポーネントなど、ほかのテキスト関連フレームワークとの間の通信もサポートするように設計されています。Java 2D には、インプットメソッドでの強調描画をサポートする機能が統合されているので、テキストコンポーネントは、変換テキストとほかのテキストを同じように扱うことができ、ほかのスタイルと同じように強調表示スタイルを処理できます。Java 2D は、Input Method Framework と対話し、インプットメソッドの強調表現方法として適切な表示スタイルを、プラットフォームの種類に基づいて決定します。Swing テキストコンポーネントは、Input Method Framework を使用して、最小限の追加のプログラミングで、可能なものの中では最良のユーザインタフェースを実装します。
言語の中には、アプリケーションにテキストを実際に取り込む前に、テキストの編集が必要なものがあります。このような編集を、「入力変換」または「プリエディット」と呼びます。入力テキストを変換する際には、インプットメソッドで入力テキストの一部を強調表示し、処理の対象になっているテキストの部分を示す必要があります。強調表示を使ってテキストを入力する処理を「入力テキストの変換」と呼び、生成される中間テキストを「変換 (入力) テキスト」と呼びます。
ユーザが入力テキストの変換を終えると、最終的な入力テキストがアプリケーションに送られます。このような操作を入力テキストの「確定」といい、生成された最終的な入力テキストを「確定 (入力) テキスト」と呼びます。
変換された入力テキストの描画では、変換テキストの全体を表示できない場合があります。そのような場合、現在もっとも重要で表示しておく必要があるのは変換テキストの中のどの部分かということを示すヒントを、インプットメソッドからアプリケーションに提供できます。フレームワークは、インプットメソッドからアプリケーションにこの情報を渡します。
一般に、キャレット位置とは、アプリケーションのバッキングストアでの挿入位置のことです。一方、入力テキストの変換処理の場合は、キャレット位置は変換テキストの中にあり、インプットメソッドがその位置を管理します。インプットメソッドは、現在のキャレット位置をアプリケーションに通知します。
Input Method Framework は、アプリケーションで発生する異なるレベルのニーズをサポートする必要があります。インプットメソッドを使う必要のないテキストアプリケーションもあれば、最善のユーザインタフェースを提供するためにインプットメソッドのサポートを必要とするアプリケーションもあります。ゲームなどのプログラムの中には、インプットメソッドの介入を受けずに、低レベルのキーボード入力を直接受け取るものもあります。フレームワークでは、次に示すテキスト入力サポートのレベルから、プログラムが適切なものを選択できるようになっています。
東アジア地域の言語での使用を目的として作れられている最近のプログラムは、通常、完全に統合化されたユーザインタフェースを持つテキスト入力操作機能を備えており、変換テキストはドキュメントテキストに埋め込まれて表示されます。テキストの変換では、現在の候補は強調表示されていて、ユーザが別の候補を選択すると、前の候補テキストは新しい候補テキストに置き換えられます。インプットメソッドに対するこのようなユーザインタフェースサポートは、「オンザスポット」モードまたは「インライン」モードと呼ばれています。Input Method Framework の API を使うと、このようなユーザインタフェースをテキスト編集コンポーネントに実装できます。
テキスト入力操作用のユーザインタフェースを扱う必要のないプログラムでは、最終的な入力テキストだけがアプリケーションに送られます。この場合、フレームワークが入力操作に提供するユーザインタフェースは、アプリケーションの外部にある独立した変換用ウィンドウになります。この方法は、「ルートウィンドウ」モード (X Window の用語) として知られています。ユーザにとっては、入力ウィンドウとアプリケーションウィンドウの間で視線を移す必要があるため、使い勝手が悪くなります。
この方式の場合、アプリケーションは、一連のキーイベントとして入力テキストを受け取ります。したがって、入力テキストに関する情報 (文法情報など) を受け取る方法はありません。また、Unicode Standard Version 2.0 で定義されているサロゲートペアは、2 つの独立したキーイベントとして受信されます。
ゲームソフトウェアなど一部のアプリケーションでは、変換されないキー入力だけが必要で、インプットメソッドのサポートを必要としない場合があります。フレームワークでは、インプットメソッドのサポートを明示的に無効にする手段が提供されています。
Input Method Framework の環境では、アプリケーションは、並行して行われる複数の入力操作をサポートできます。個々の入力操作の状態は、個別に保持されます。たとえば、ドキュメントにテキストを入力している最中でも、ファイルを扱う必要がある場合は、別の入力操作でファイル名を入力できます。
次の図は、フレームワークとそのクライアントの全体的な構造を示しています。太枠で示されている部分だけが、JDK 1.2 の一部として Input Method Framework と実際に統合されます。
インプットメソッド API で定義されているクラスとインタフェースを使うと、テキスト編集コンポーネントでオンザスポットテキスト入力を実装できます。2 つのAWT テキストコンポーネント TextArea
と TextField
は、実装方法によって、オンザスポット編集またはオーバーザスポット編集の機能を提供します。Swing テキストコンポーネントは、オンザスポット編集機能を提供します。コンテキスト管理は、テキスト編集コンポーネントとインプットメソッドの間の通信経路を管理します。基本的に、JDK 1.2 は、ホストのインプットメソッドマネージャと統合されたネイティブなインプットメソッドを使います。ネイティブなインプットメソッドで使われるデータモデルと Input Method Framework で使われるデータモデルの間で交換される情報は、アダプタによって変換されます。フレームワークは、ネイティブなインプットメソッドマネージャとも連携し、テキスト変換のユーザインタフェースの部分 (特にルートウィンドウの機能) を提供します。JDK 1.2 には、IIIMP を通してサーバベースのインプットメソッドを使えるようにするアダプタも付属しています。JDK の将来のバージョンでは、インプットメソッドエンジン API により、Java プログラミング言語で記述されたインプットメソッドがサポートされるようになります。
Input Method Framework のクライアントは、あらゆる種類のテキスト編集コンポーネントです。フレームワークのためのアプリケーションは、実際には存在しません。前述のサービスレベルに応じて、3 種類のコンポーネントがあります。
オンザスポット編集をサポートするテキストコンポーネントとサポートしないコンポーネントを、同じウィンドウの中に混在させることができます。したがって、Input Method Framework は、テキストコンポーネントの機能を判断し、コンポーネント間をフォーカスが移動する際には、オンザスポット編集とルートウィンドウ編集を切り替える必要があります。
候補リストの描画、またはインプットメソッドの動作を制御するユーザインタフェース要素の処理は、テキストコンポーネントの役割ではありません。プラットフォームの種類により、インプットメソッド、ホストのインプットメソッドマネージャ、または Input Method Framework が、この処理を行います。
InputContext
のインスタンスは、クライアントコンポーネントとインプットメソッドの間の通信コンテキストを管理します。入力コンテキストの主な機能は、現在のテキストコンポーネントから現在のインプットメソッドへの接続を維持することです。入力コンテキストは、キーイベントやマウスイベントなどの入力イベントをコンポーネントから現在のインプットメソッドにディスパッチし、インプットメソッドのイベントをインプットメソッドからクライアントコンポーネントにディスパッチします。また、インプットメソッドからクライアントコンポーネントへの情報の要求もディスパッチします。
さらに、このクラスは次の機能も提供します。
InputContext
オブジェクトに保存されて、コンポーネントから同じインプットメソッドの要求があると、元のオブジェクトに復帰する
デフォルトでは、ウィンドウのインスタンスごとに 1 つの InputContext
のインスタンスが作成されて、ウィンドウの包含関係の階層に含まれるすべてのコンポーネントで共有されます。必要に応じて、コンポーネントはプライベートな入力コンテキストを作成できます。独自の入力コンテキストを持たないコンポーネントは、親が使っている入力コンテキストを使います。
入力コンテキストは、クライアントコンポーネントが使う必要のあるインプットメソッドエンジンごとに、インプットメソッドのインスタンスを作成します。インスタンスは、ウィンドウが閉じるまで残っているので、ウィンドウで入力されたテキストについての情報を保持できます。
多くの場合、入力時の変換処理は必要なく、コンポーネントのキーイベントリスナーがキーイベントを直接処理しなければなりません。たとえば、ドイツ語のテキストをキーボードで入力するときのように、これが一時的な状況の場合は、ホストの切り替え機構を使ってインプットメソッドから標準のキーボード処理に切り替えることで、JDK 1.2 の中で処理されます。キーを直接解釈する必要のあるゲームプログラムなどのように、コンポーネントで入力変換を使うことがまったくない場合は、インプットメソッドを無効にできます。
オンザスポット編集をサポートしないテキストコンポーネントに対しては、入力コンテキストが、テキスト変換用のデフォルトのユーザインタフェースを提供します。このようなテキストコンポーネントのためにインプットメソッドがテキストの変換を始める時点で、入力コンテキストは、ルートウィンドウ形式の入力のための入力ウィンドウを開きます。確定テキストは、一連のキーイベントとしてテキストコンポーネントに送られます。入力ウィンドウ内のテキストがすべて確定されると、ウィドウは閉じます。フォーカスが設定されたテキストコンポーネントを含むウィンドウが、テキストの変換を行なっている最中にフォーカスを失うと、ウィンドウがフォーカスを再び取得するまで入力ウィンドウは非表示状態になるので、ビューの中に同時に 2 つの入力ウィンドウが存在することはありません。
次の図は、Input Method Framework でのイベントの流れを示しています。アクティブクライアント、パッシブクライアント、非クライアントのそれぞれで、イベントフローは異なります。
非クライアントには入力コンテキストがないので、すべてのイベントがコンポーネントのリスナー (次の図ではキーリスナー) に直接届きます。
アクティブクライアントとパッシブクライアントの場合、KeyEvent
や MouseEvent
などの入力イベントは、InputContext
オブジェクトを通して現在のインプットメソッドに送られます。入力イベントが入力テキストサービスの処理で使われる場合、入力イベントはインプットメソッドで処理されて、コンポーネントに対するインプットメソッドイベントが生成されます。
アクティブクライアントでは、インプットメソッドから送られてくる InputMethodEvent
を処理できるよう、InputMethodListener
を登録しておく必要があります。変換されて確定されたテキストは、インプットメソッドイベントとしてインプットメソッドリスナーに送られます。
パッシブクライアントにはインプットメソッドリスナーがないので、インプットメソッドイベントはルートウィンドウに渡されて、そこで擬似的にアクティブクライアントの処理が行われます。ルートウィンドウでは、確定テキストは、クライアントの実際のキーイベントリスナーに対するキーイベントに変換されます。KEY_TYPED イベントだけが送信されます。ホストのインプットメソッドの場合は、通常、ホストのインプットメソッドマネージャがルートウィンドウを用意します。
JDK 1.2 は、ホストのインプットメソッドマネージャと統合されているネイティブなインプットメソッドをサポートしています。このようなインプットメソッドマネージャとしては、Win32 の Input Method Manager、MacOS の Text Services Manager、Solaris の XIM があります。ホストのインプットメソッドアダプタは、Input Method Framework 内でのインプットメソッドの役割を果たし、AWT と Input Method Framework の側で使われるデータモデルと、ホストのインプットメソッドマネージャの側で使われるデータモデルの間で、イベントと要求の変換を行います。また、ルートウィンドウの管理では、入力コンテキストとも連携します。一般に、ホストのインプットメソッドでは、ホストのインプットメソッドマネージャが提供するルートウィンドウが使われます。アダプタは特定のインプットメソッドへの要求をホストに渡しますが、ホストの選択機構を使ってユーザがインプットメソッドを選択することもできます。
InputContext
のインスタンスごとに個別のホストアダプタのインスタンスが作成されるので、各 InputContext
のインスタンスは、ホストシステムの入力データ構造の独自のインスタンスにミラー化されます。
サーバベースのインプットメソッドに対し、JDK 1.2 は、IIIMP 用のクライアント側アダプタを提供します。ネットワークプロトコルの IIIMP を使うと、クライアントアプリケーションは、ネットワーク経由でサーバベースのインプットメソッドを使用できます。IIIMP を初めてクライアント側に実装したものが、現在、JavaOS で使われています。JDK 1.2 のアダプタは、JavaOS での実装のサブセットになっています。このアダプタは、プロトコルを完全に実装し、ステータスとルックアップ選択情報についてのユーザインタフェースサポートを提供していますが、軽量インプットメソッドはサポートしていません。JDK 1.2 の IIIMP アダプタは独立した拡張機能として提供されており、JDK 1.2 から作られた Java アプリケーション環境のすべてに IIIMP アダプタが含まれているとは限りません。
IIIMP サーバについての情報をプロパティファイルに記述し、クライアントアダプタに提供する必要があります。プロパティファイルは、.iiimp という名前でユーザのホームディレクトリに置くか、または iiimp.properties という名前で JDK の lib ディレクトリに置きます。両方のファイルが存在する場合は、ユーザのホームディレクトリにあるものが優先的に使われます。ファイルには、次の 1 行を記述します。
iiimp.server=iiimp://servername:portid
servername は IIIMP サーバを実行しているホストの名前で、portid は IIIMP サーバが使うポートの ID です。
Java のアプリケーション環境に拡張機能が含まれていて、有効なサーバ情報が存在する場合、ホストプラットフォームのインプットメソッドとサーバベースのインプットメソッドのどちらかを選択できるユーザインタフェースが、JDK から提供されます。Windows システムと Motif システムでは、ウィンドウタイトルに付随するメニュー (Windows ではシステムメニュー、Motif ではウィンドウメニュー) に、メニュー項目が追加されます。このメニュー項目を選択すると、ポップアップメニューが開き、そこでホストのインプットメソッド (グループとして) またはサーバベースのインプットメソッド (ロケールごと) を選択できます。このあとでも、ホストシステムの選択機構を使って、異なるホストインプットメソッドを選択できます。
InputContext
のインスタンスごとに独立した IIIMP アダプタのインスタンスが作成されるので、各 InputContext
のインスタンスは、その所有するサーバの入力コンテキストデータ構造のインスタンスによってミラー化されます。
フレームワークには、インプットメソッドからコンポーネントのメソッドを呼び出し(コールバックともいう)、入力テキストの変更をコンポーネントに通知したりコンポーネントに情報を要求したりする機構が必要です。このフレームワークでは、2 種類の呼び出しモデルが使われています。
InputMethodEvent
は通常、コンポーネントのメソッドに同期的にディスパッチされるのに対し、ほかの AWT イベントのディスパッチはイベントキューを通して非同期に行われる
InputMethodRequests
を定義し、クライアントコンポーネントがそれを実装するという方法。インプットメソッドは、インタフェースのメソッドを呼び出し、クライアントコンポーネントに情報を要求する。この呼び出しは、同期的に行われる。インプットメソッドのイベントディスパッチと同様に、要求メソッドは入力コンテキストを通して間接的に呼び出される
フレームワークは、java.text.AttributedCharacterIterator
インタフェースを使って、クライアントコンポーネントとインプットメソッドの間でやり取りされるテキストを表現します。文字属性と範囲属性の両方が、インプットメソッドでの強調表示に使われる場合があります。また、範囲属性は、インプットメソッドや言語などに依存する情報の表現に使われる場合もあります。
テキストコンポーネントで次の処理を行うには、インプットメソッドの API を使います。
デフォルトでは、キーイベントを処理するコンポーネントはすべて、Input Method Framework のクライアントになります。つまり、コンポーネントではインプットメソッドのサポートが有効になります。場合によっては、インプットメソッドによる処理を受けない入力が、コンポーネントで必要になることがあります。たとえば、ゲームでは、キーボードイベントを直接解釈しなければならない場合があります。このようなコンポーネントでは、enableInputMethods(false)
を呼び出し、イベントがインプットメソッドに転送されないようにします。
インプットメソッド API を使うと、クライアントコンポーネントにオンザスポット編集の機能を実装できます。API によって定義されるイベントとメソッドにより、クライアントコンポーネントとインプットメソッドの間での円滑な通信が行われます。また、API を使うと、クライアントコンポーネントは、特定の言語のためのインプットメソッドを要求できます。
API では、テキストが描画される方法や場所についての前提はないので、オーバーザスポット編集など、ほかの入力形式の実装に API を使うこともできます。オーバーザスポット編集の入力形式では、変換されるテキストは、前後のテキストと統合されてフォーマットされるのではなく、周囲のテキストを覆い隠すように上に描画されます。
クライアントコンポーネントのどのクラスでも、次の手順を実行してインプットメソッド API のアクティブクライアントとなり、オンザスポット編集をサポートできます。
InputMethodListener
インタフェースを実装して現在のインプットメソッドによって生成された InputMethodEvents
の着信を処理し、リスナーを登録する
InputMethodRequests
インタフェースを実装して getInputMethodRequests
をオーバーライドし、要求ハンドラを返す
InputMethodHighlight
属性を格納し、それを描画ルーチンに渡す
クライアントコンポーネントでは、必要に応じて次の機能も使用できます。
入力コンテキストのセットアップ、コンテキストの起動と停止、インプットメソッドへのイベントのディスパッチなどはすべて AWT が自動的に処理するので、クライアントコンポーネントが処理する必要はありません。
JDK 1.1 AWT のイベントに加えて、Input Method Framework では新しいイベントクラス InputMethodEvent
が提供されています。このイベントクラスは、インプットメソッドとテキストコンポーネントの間の通信をサポートするためのものです。クラスには、2 種類の異なるイベント、テキスト変更とキャレット変更があります。新しいイベントのリスナーインタフェース InputMethodListener
は、この 2 種類のイベントをサポートしています。アクティブクライアントのコンポーネントは、InputMethodListener
インタフェースを実装し、リスナーを登録して、両方のイベントを処理する必要があります。
ユーザの入力テキストが変化すると、または変換されているテキストの内部のキャレットの位置が変わると、InputMethodEvent
のインスタンスがクライアントコンポーネントに送られます。キャレットだけが変化したときに送信されるイベントは、テキスト変更のイベントからテキスト情報だけが除かれて簡略化されたものなので、以下ではテキスト変更イベントについて説明します。
テキスト変更を伝えるイベントには、変換されたテキストと確定されたテキストのどちらか一方あるいは両方を表す AttributedCharacterIterator
のインスタンスへの参照が含まれています。
テキストの変換時には、ユーザが表示に加えた変更はすべて、変換された入力テキストとしてクライアントコンポーネントに送られます。変換されたテキストがまだない場合は、新しく変換されたテキストを、コンポーネントのテキストの現在の挿入位置に挿入する必要があります。変換されたテキストがすでにある場合は、それまでのテキスト全体を、送られてきた新しい変換テキストで置き換える必要があります。更新されたテキストの再描画は、クライアントコンポーネントが行います。
変換されたテキストをユーザが確認するなどして変換テキストが確定されると、インプットメソッドによって確定テキストが形成されます。それまでの変換テキスト全体を、この確定テキストで置き換える必要があります。また、挿入位置は、この確定テキストの末尾に移動します。
変換テキストの一部が確定されている場合は、確定テキストと残りの変換テキストが、1 つの InputMethodEvent
で送信されます。この場合、クライアントコンポーネントは、先に確定テキストを処理し、次に残りの変換テキストを処理する必要があります。このイベント処理手順には、次のような意味があります。
上のような状態は、確定された文字数の値を調べることで判断できます。値が 0 の場合は、テキスト全体が変換テキストです。値が反復子のテキストの長さと等しい場合は、テキスト全体が確定されています。それ以外の場合は、文字数の値が部分的に確定されたテキストの長さを表し、テキストの残りは変換テキストです。
イベントには、変換テキスト内のキャレットの現在位置 (キャレットを表示しない場合は null) についての情報、および変換テキストの中で表示する必要のあるもっとも重要な部分 (インプットメソッドによる推奨部分がない場合は null) についての情報も含まれます。
通常、テキストコンポーネントは、標準のテキストレイアウトと描画機能を使い、編集されているテキストの一部として変換テキストを描画します。ただし、変換の現在の状態を示すため、強調表示スタイルの属性を変換テキストに追加する必要があります。フレームワークでは、これらのスタイル属性は抽象的なスタイル (変換されておらず選択されていないテキスト、変換されていて選択されているテキストなど) として定義されており、プラットフォームに依存する具体的なスタイル (たとえば、灰色で 2 ピクセルの下線) に内部的にマッピングされます。
抽象的な強調表示スタイルは、InputMethodHighlight
クラスで表されます。このクラスのインスタンスは、変換テキストを表す AttributedCharacterIterator のインスタンスの属性値として使われます。テキストコンポーネントは、変換テキストとともにこれらの属性を格納し、変換テキストを描画する際には、テキストと属性を描画ルーチンに渡します。AttributedCharacterIterator を受け付ける新しい drawString メソッドを使うことも、反復子から TextLayout を作成してその描画メソッドを使うことも、どちらも可能です。新しい描画メソッドは、Input Method Framework と通信し、抽象的な強調スタイルを具体的な強調表示スタイルにマッピングします。したがって、これらのメソッドを使うテキストコンポーネントは、通常、インプットメソッドでの強調表示の内部的な詳細に関わる必要がありません。
以下は、テキストコンポーネントのためのさらに具体的な情報です。InputMethodHighlight
には、boolean 型の selected
、整数型の state
、および整数型の variation
という 3 つのフィールドがあります。Selected
フィールドは、テキストの範囲がインプットメソッドによって現在処理されている部分かどうかを示します。たとえば、変換候補が現在メニューに表示されているセグメントなどです。State
フィールドは、変換の状態を示します。状態の値は Input Method Framework で定義されていて、抽象的なスタイルから具体的なスタイルへのすべてのマッピングにおいて、区別されなければなりません。現在定義されている状態値は、未変換と変換済みです。variation
フィールドは、Java プログラム言語で記述される将来のインプットメソッドが変換結果についての追加情報を設定できるよう、用意されています。レンダラーは、具体的なスタイルについてインプットメソッドとネゴシエーションを行うか、またはこのフィールドを無視する必要があります。
インプットメソッドによっては、強調表示を「注釈」として扱う場合があります。注釈は、指定された範囲のテキストに適用される属性ですが、部分範囲または範囲の連結に対しては適用されません。これらは、InputMethodHighlight
のインスタンスを java.text.Annotation
のインスタンス内にラップして表されます。インプットメソッドは、注釈の強調表示を使って複数のテキストセグメントに区切り、ユニットごとに変換することもできます。セグメントを明示するために、セグメント間の短い区切りに加えて下線を使うなどして、強調表示を描画するプラットフォームもあります。テキストコンポーネントは、インプットメソッドの強調表示を、それが Annotation
のインスタンス内にラップされるかどうかにかかわりなく、処理できなければなりません。テキストコンポーネントが行の折り返しを実装する場合は、強調表示の注釈が適用される範囲が、行境界を超えるときに特に注意する必要があります。java.text.AttributedString
内で実装される場合などの通常の動作では、属性が部分範囲に適用されないため、属性を放棄します。しかしこの場合は、表示上の区切りがあるだけで論理上の区切りはないので、強調表示を保存する必要があります。この強調表示は、別の行に描画される部分範囲に適用されたかのように扱う必要があります。
これは、目的の範囲の部分範囲に対しても強調表示の注釈を返す方法で java.text.AttributedCharacterIterator
を実装することにより実現できます。
入力操作を行うためには、インプットメソッドはコンポーネントの情報にアクセスする必要があります。たとえば、選択肢のリストを表示できる場所を知る必要があります。
したがって、アクティブクライアントコンポーネントは、InputMethodRequests
インタフェースを実装し、getInputMethodRequests
をオーバーライドして、要求ハンドラを返す必要があります。このインタフェースには、次のメソッドが含まれています。
通常、インプットメソッドは、入力操作を終了させるユーザの行為を認識します。たとえば、未確定のすべてのテキストを確定する操作などです。ただし、入力操作の終了が必要な操作を開始するユーザの行為の中には、インプットメソッドが認識できないものもあります。テキストを含むドキュメントの保存は、インプットメソッドが認識できない行為の例です。そのような場合、コンポーネントは、入力コンテキストの endComposition
メソッドを明示的に呼び出す必要があります。
インプットメソッドは、テキストコンポーネントに送るテキストに、強調表示情報以外の属性を付加する場合があります。このような属性の中には、コンポーネントにとって有用な情報が含まれています。また、InputMethodRequest
メソッドで返すことにより、インプットメソッドの性能が向上する場合もあります。後者の理由から、テキストコンポーネントには、テキストの編集が行われている間この属性情報を保持し、要求されたテキストとともにこの情報を返すことが推奨されます。
AttributedCharacterIterator.Attribute
クラスでは、次の共通属性が定義されています。
LANGUAGE
- テキストの言語、Locale オブジェクトとして指定される
READING
- 音声表現 (日本語での「読み」)、String オブジェクトとして指定される
INPUT_METHOD_SEGMENT
- インプットメソッドが使うセグメンテーション情報
Java プログラミング言語で記述される将来のインプットメソッドでは、属性が追加される可能性があります。
デフォルトでは、ウィンドウのインスタンスごとに 1 つの InputContext
のインスタンスが作成されて、ウィンドウの包含関係の階層に含まれるすべてのコンポーネントがこの入力コンテキストを共有します。これにより、全体で作成されるインスタンスの数が減り、インプットメソッドは、このウィンドウで入力されるすべてのテキストについての情報を組み合わせて利用できます。インプットメソッドでは、それまでの入力されたテキストについての情報を使って、変換の精度を高めています。ただし、このことは、1 つのウィンドウの中では一度に 1 つの入力操作しか許されず、あるテキストコンポーネントから別のテキストコンポーネントにフォーカスが移る際にはテキストの確定が必要であることを意味します。このような動作が適切でない場合は、テキストコンポーネントで独自の入力コンテキストのインスタンスを作成し、getInputContext
をオーバーライドして、作成したインスタンスを返すことができます。独自の入力コンテキストを持たないコンポーネントは、親の入力コンテキストを使います。
テキストコンポーネントでは、入力コンテキストの selectInputMethod
オペレーションを使って、特定の言語またはロケールに対するインプットメソッドを選択できます。たとえば、テキストの中のある部分をユーザがクリックした場合、その個所と同じ言語での入力操作の継続をユーザが希望していると考えられるので、インプットメソッド選択の機能が役に立ちます。または、特定の言語によるテキスト入力だけをアプリケーションが許可していることを、テキストコンポーネントが認識している場合もあります。
テキストコンポーネントでは、入力コンテキストの setCharacterSubsets
オペレーションを使って、入力値として有効な文字をインプットメソッドに通知できます。たとえば、データベースアプリケーションでは、フィールドによって、平仮名だけ、アルファベットだけ、または任意の種類の文字というように、入力を受け付ける文字が決まっている場合があります。インプットメソッドにこの情報を渡すことで、入力できる文字の範囲を制限したり、特定の文字サブセットだけを専門にサポートする別の入力モードに切り替えたりする処理を、インプットメソッドが行えるようになります。ただし、ホストのすべてのインプットメソッドにこの設定を渡すことはできないため、アプリケーションは、目的の効果をこの呼び出しだけで実現することはできません。アプリケーションでは、やはり、独自に文字の妥当性検査を行う必要があります。
この章では、Input Method Framework を統合するために行われた、JDK 1.2 のほかの Java プラットフォームフレームワークに対する変更点についてまとめます。
属性が付加されたテキスト情報をフレームワーク間で交換するための標準的な手段として、AttributedCharacterIterator
インタフェースが追加されています。これにより、テキストを読み取る側は、情報提供側でのテキストの格納方法を知らなくても、テキストにアクセスできます。属性情報には、フォントやスタイルの属性だけでなく、言語タグや文法に関する注釈も含まれる場合があります。
Window
クラスは、ウィンドウの初期入力コンテキストを作成し、ウィンドウが破棄される時点でその初期入力コンテキストを破棄するように、変更されています。入力コンテキストを明示的に破棄することで、ネイティブなインプットメソッドに割り当てられていて、時にかなりの大きさになるリソースを解放できます。
Component
クラスには、入力コンテキストとインプットメソッド要求ハンドラを処理するための新しいメソッドが追加されています。ウィンドウ以外の新しく作成された Component
のインスタンスは、最初、含んでいるウィンドウの入力コンテキストを共有します。Component クラスでのイベント処理は、受け取ったイベントをコンポーネントに関連する入力コンテキストにリダイレクトするように変更されていて、イベントがインプットメソッドで使われない場合は、コンポーネントのリスナーにイベントを渡す処理だけを行います。入力コンテキストがインプットメソッドを起動または停止できるよう、フォーカスの変更は入力コンテキストに通知されます。
イベントまたはリスナーのクラスについての情報を持っているクラスは、新しい InputMethodEvent
クラスと InputMethodListener
クラスを処理するように変更されています。
Graphics
クラスと Graphics2D
クラスには、入力として AttributedCharacterIterator
のインスタンスを受け付ける新しい drawString
メソッドが追加されています。新しい TextLayout
クラスのインスタンスは、AttributedCharacterIterator
のインスタンスから生成でき、インプットメソッドの強調表示を付加したテキストの描画に使用できます。どちらのテキスト描画方法も、テキストに対する範囲属性としてインプットメソッドの強調表示を認識し、Input Method Framework にコールバックして、抽象的な強調スタイルを具体的な強調表示スタイルに変換します。
JDK 1.2 の Swing テキストコンポーネントは、デフォルトでは Input Method Framework のアクティブなクライアントです。つまり、これらのテキストコンポーネントを使うアプリケーションは、デフォルトでオンザスポット入力モードを使用します。しかし、テキストの確定が必要な別の操作が開始された場合は、アプリケーションの開発者が入力操作を終了する必要があります。Input Method Framework のメソッドを使って、プライベートな入力コンテキストの作成、インプットメソッドの選択、または有効な文字サブセットの設定も可能です。
JDK の今後のリリースでは、以下の機能拡張が計画されています。拡張項目の順番は、機能の優先順位を示すものではありません。
この API を使うと、Java プログラミング言語でインプットメソッドエンジンを実装できるようになります。また、この API には、Java アプリケーション環境で複数のインプットメソッドを管理する機能も含まれています。
TextArea
と TextField
でのネイティブ以外のインプットメソッドの使用現在、TextArea
と TextField
は、プラットフォームピアを使用しています。したがって、テキスト入力にはプラットフォームのテキスト入力システムを使用します。Java プログラミング言語で実装されたインプットメソッドは使用できません。最終的には、Swing と AWT が統合されることで、TextArea
と TextField
は軽量コンポーネントになります。その時点で、Java プログラミング言語で実装されたインプットメソッドによる入力が、利用できるようになります。
多層インプットメソッドをこのフレームワークでサポートできるようにする必要があります。たとえば、手書き文字認識用のインプットメソッドを通して入力されたテキストの場合も、テキスト確定の前に、かな漢字変換での処理が必要な場合があります。