インプット・メソッド・クライアント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を使って利用可能な、種類の異なるインプット・メソッド・クライアントであるアクティブ・クライアント、パッシブ・クライアント、非クライアント、およびピア・テキスト・コンポーネントを実装する方法を示します。