インプットメソッドクライアント API を使うと、オンザスポット入力などの統合テキスト入力ユーザーインタフェースをクライアントコンポーネントに実装できます。API によって定義されるイベントとメソッドにより、クライアントコンポーネントとインプットメソッドの間での円滑な通信が行われます。また、API を使うと、クライアントコンポーネントは、特定の言語のためのインプットメソッドを要求できます。
API では、テキストが描画される方法や場所についての前提はないので、オーバーザスポット編集など、ほかの入力形式の実装に API を使うこともできます。オーバーザスポット編集の入力形式では、変換されるテキストは、前後のテキストと統合されてフォーマットされるのではなく、周囲のテキストを覆い隠すように上に描画されます。
任意のクライアントコンポーネントクラスは、インプットメソッドクライアント API のアクティブクライアントになることができ、次のステップを実行して統合テキスト入力ユーザーインタフェースをサポートできます。
InputMethodListener
インタフェースを実装して現在のインプットメソッドによって生成された InputMethodEvents
の着信を処理し、リスナーを登録する。InputMethodRequests
インタフェースを実装して getInputMethodRequests
をオーバーライドし、要求ハンドラを返す。InputMethodHighlight
属性を格納し、それを描画ルーチンに渡す。クライアントコンポーネントでは、必要に応じて次の機能も使用できます。
入力コンテキストのセットアップ、コンテキストの起動と停止、インプットメソッドへのイベントのディスパッチなどはすべて AWT が自動的に処理するので、クライアントコンポーネントが処理する必要はありません。
Input Method Framework は、イベントクラス InputMethodEvent
を提供し、インプットメソッドとテキストコンポーネント間の通信をサポートします。クラスには、2 種類の異なるイベント、テキスト変更とキャレット変更があります。イベントリスナーインタフェース InputMethodListener
は、これら 2 つのイベントをサポートしています。アクティブクライアントのコンポーネントは、InputMethodListener
インタフェースを実装し、リスナーを登録して、両方のイベントを処理する必要があります。
ユーザーの入力テキスト (反転表示) が変化すると、または変換されているテキストの内部のキャレットの位置が変わると、InputMethodEvent
のインスタンスがクライアントコンポーネントに送られます。キャレットだけが変化したときに送信されるイベントは、テキスト変更のイベントからテキスト情報だけが除かれて簡略化されたものなので、次ではテキスト変更イベントについて説明します。
テキスト変更を伝えるイベントには、変換テキストと確定テキストのどちらか一方あるいは両方を表す AttributedCharacterIterator
のインスタンスへの参照が含まれています。イベントの確定文字数の値は、イテレータの範囲内のいくつの文字が確定されたテキストかを指定します。残りの文字はすべて変換テキストです。確定テキストは構成テキストよりも常に優先されます。コンポーネントに以前の変換テキストがない場合は、確定され変換されたテキストは選択された任意のテキストに置き換わるか、コンポーネントのテキストの現在の挿入位置に挿入されます。以前の変換テキストがある場合は、その以前の変換テキスト全体が、新しく確定され変換されたテキストに置き換えられます。挿入ポイントが、確定テキストの最後に移動します。更新されたテキストの再描画は、クライアントコンポーネントが行います。
イベントには、変換テキスト内のキャレットの現在位置 (キャレットを表示しない場合は null) についての情報、および変換テキストの中で表示する必要のあるもっとも重要な部分 (インプットメソッドによる推奨部分がない場合は null) についての情報も含まれます。
通常、テキストコンポーネントは、標準のテキストレイアウトと描画機能を使い、編集されているテキストの一部として変換テキストを描画します。ただし、変換の現在の状態を示すため、反転表示スタイルの属性を変換テキストに追加する必要があります。フレームワークでは、これらのスタイル属性は抽象的なスタイル (変換されておらず選択されていないテキスト、変換されていて選択されているテキストなど) として定義されており、プラットフォームに依存する具体的なスタイル (たとえば、灰色で 2 ピクセルの下線) に内部的にマッピングされます。
反転表示属性は、InputMethodHighlight
クラスによって表されます。このクラスのインスタンスは、変換テキストを表す AttributedCharacterIterator のインスタンスの属性値として使われます。テキストコンポーネントは、変換テキストとともにこれらの属性を格納し、変換テキストを描画する際には、テキストと属性を描画ルーチンに渡します。AttributedCharacterIterator
を受け付ける drawString
メソッドを使うことも、イテレータから TextLayout
を作成してその描画メソッドを使うことも、どちらも可能です。これらの描画メソッドは、Input Method Framework と通信し、抽象的から具体的な反転表示スタイルにマッピングします。したがって、これらのメソッドを使うテキストコンポーネントは、通常、インプットメソッドでの反転表示の内部的な詳細にかかわる必要がありません。テキストコンポーネントがほかのメカニズムを使ってテキストをレンダリングする場合は、インプットメソッドの反転表示で具体的なスタイルに関する情報を調べ、情報がなければ、 Toolkit.mapInputMethodHighlight
を使って具体的なスタイルにマッピングする必要があります。
インプットメソッドによっては、強調表示を「注釈」として扱う場合があります。注釈は、指定された範囲のテキストに適用される属性ですが、部分範囲または範囲の連結に対しては適用されません。注釈は、InputMethodHighlight
インスタンスを Annotation
インスタンスにラップすることによって表されます。インプットメソッドは、注釈の反転表示を使って複数のテキストセグメントに区切り、ユニットごとに変換することもできます。セグメントを明示するために、セグメント間の短い区切りに加えて下線を使うなどして、反転表示をレンダリングするプラットフォームもあります。テキストコンポーネントは、インプットメソッドの反転表示を、それが Annotation
のインスタンス内にラップされるかどうかにかかわらず、処理できなければなりません。テキストコンポーネントが行の折り返しを実装する場合は、反転表示の注釈が適用される範囲が、行境界を越えるときに特に注意する必要があります。AttributedString
内で実装される場合などの通常の動作では、属性が部分範囲に適用されないため、属性を放棄します。しかしこの場合は、表示上の区切りがあるだけで論理上の区切りはないので、反転表示を保存する必要があります。この反転表示は、別の行にレンダリングされる部分範囲に適用されたかのように扱う必要があります。これは、目的の範囲の部分範囲に対しても反転表示の注釈を返す方法で 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 API を介して利用可能にできない機能をクライアントコンポーネントに提供することがあります。これは、インプットメソッドコントロールオブジェクトによって可能になります。インプットメソッドの開発者は、これらのオブジェクトのインタフェースを公開する必要があります。追加の機能を利用するクライアントコンポーネントは、 InputContext.getInputMethodControlObject
を呼び出し、返されたオブジェクトが既知のコントロールオブジェクトクラスのインスタンスであるかどうかを確認し、そうである場合は、そのメソッドを呼び出します。
デフォルトでは、キーイベントを処理するコンポーネントはすべて、Input Method Framework のクライアントになります。つまり、コンポーネントではインプットメソッドのサポートが有効になります。場合によっては、インプットメソッドによる処理を受けない入力が、コンポーネントで必要になることがあります。たとえば、ゲームでは、キーボードイベントを直接解釈しなければならない場合があります。このようなコンポーネントでは、enableInputMethods(false)
を呼び出し、イベントがインプットメソッドに転送されないようにします。
このサンプルコードでは、Input Method Framework を使って利用可能な、種類の異なるインプットメソッドクライアントであるアクティブクライアント、パッシブクライアント、非クライアント、およびピアテキストコンポーネントを実装する方法を示します。