カスタム テキスト入力

Windows.UI.Text.Core 名前空間の基本的なテキスト API によって、Windows アプリは、Windows デバイスでサポートされている任意のテキスト サービスからテキスト入力を受け取ることができます。 API は、 Text Services Framework API に似ています。つまり、アプリはテキスト サービスに関する詳細な知識を持っている必要はありません。 これにより、アプリは、キーボード、音声、ペンなどの任意の入力の種類から、任意の言語でテキストを受信できます。

重要な API: Windows.UI.Text.CoreCoreTextEditContext

コア テキスト API を使用する理由

多くのアプリでは、テキスト入力と編集には XAML または HTML テキスト ボックス コントロールで十分です。 ただし、アプリがワープロ アプリなどの複雑なテキスト シナリオを処理する場合は、カスタム テキスト編集コントロールの柔軟性が必要になる場合があります。 CoreWindow キーボード API を使用してテキスト編集コントロールを作成できますが、これらは、東アジア言語をサポートするために必要なコンポジションベースのテキスト入力を受け取る方法を提供しません。

代わりに、カスタム テキスト編集コントロールを作成する必要がある場合は、 Windows.UI.Text.Core API を使用します。 これらの API は、任意の言語でテキスト入力を処理する際に多くの柔軟性を提供し、アプリに最適なテキスト エクスペリエンスを提供できるように設計されています。 コア テキスト API を使用して構築されたテキスト入力および編集コントロールは、Windows デバイス上のすべての既存のテキスト入力メソッドから、 Text Services Framework ベースの入力メソッド エディター (IME) から PC の手書き入力から、モバイル デバイス上の WordFlow キーボード (自動修正、予測、ディクテーションを提供) にテキスト入力を受け取ることができます。

Architecture

テキスト入力システムの単純な表現を次に示します。

  • "アプリケーション" は、基本的なテキスト API を使って構築されたカスタム編集コントロールをホストする Windows アプリを表します。
  • Windows.UI.Text.Core API は、Windows を介したテキスト サービスとの通信を容易にします。 テキスト編集コントロールとテキスト サービス間の通信は、主に、通信を容易にするメソッドとイベントを提供する CoreTextEditContext オブジェクトを介して処理されます。

CoreText アーキテクチャの図

テキスト範囲と選択範囲

編集コントロールはテキスト入力用のスペースを提供し、ユーザーはこのスペース内の任意の場所でテキストを編集することを期待します。 ここでは、コア テキスト API で使用されるテキスト配置システムと、このシステムでの範囲と選択の表現方法について説明します。

アプリケーション キャレットの位置

コア テキスト API で使用されるテキスト範囲は、キャレット位置の観点から表されます。 "Application Caret Position (ACP)" は、次に示すように、キャレットの直前のテキスト ストリームの先頭からの文字数を示す 0 から始まる数値です。

アプリケーション キャレット位置 (ACP) の文字数を示すスクリーンショット

テキスト範囲と選択範囲

テキスト範囲と選択範囲は、次の 2 つのフィールドを含む CoreTextRange 構造体によって表されます。

フィールド データ型 説明
StartCaretPosition Number [JavaScript] | System.Int32 [.NET] | int32 [C++] 範囲の開始位置は、最初の文字の直前の ACP です。
EndCaretPosition Number [JavaScript] | System.Int32 [.NET] | int32 [C++] 範囲の終了位置は、最後の文字の直後の ACP です。

 

たとえば、前に示したテキスト範囲で、範囲 [0, 5] は "Hello" という単語を指します。 StartCaretPosition は常に EndCaretPosition 以下にする必要があります。 範囲 [5, 0] は無効です。

カーソル

カーソルと呼ばれる現在のキャレット位置は、 StartCaretPositionEndCaretPosition と等しく設定することによって表されます。

連続しない選択

一部の編集コントロールでは、連続しない選択がサポートされています。 たとえば、Microsoft Office アプリ では複数の任意の選択がサポートされ、多くのソース コード エディターでは列の選択がサポートされています。 ただし、基本的なテキスト API では連続しない選択範囲はサポートされません。 編集コントロールは、連続した選択を 1 つだけ報告する必要があります。多くの場合、非連続選択のアクティブなサブ範囲です。

たとえば、次の図には、2 つの連続しない選択範囲 ([0, 1] と [6, 11]) を含むテキスト ストリームが示されており、編集コントロールは 1 つのみ ([0, 1] または [6, 11] のいずれか) をレポートする必要があります。

連続していないテキスト選択を示すスクリーンショット。最初の文字と最後の 5 文字が選択されています。

テキストの操作

CoreTextEditContext クラスを使用すると、Windows 間のテキスト フローと、TextUpdating イベント、 TextRequested イベント、および NotifyTextChanged メソッドを使用してコントロールを編集できます。

編集コントロールは、 TextUpdating イベントを介してテキストを受け取ります。イベントは、ユーザーがキーボード、音声、IME などのテキスト入力メソッドを操作するときに生成されます。

たとえば、コントロールにテキストを貼り付けて編集コントロールのテキストを変更する場合は、 NotifyTextChanged を呼び出して Windows に通知する必要があります。

テキスト サービスに新しいテキストが必要な場合は、 TextRequested イベントが発生します。 TextRequested イベント ハンドラーに新しいテキストを指定する必要があります。

テキストの更新を受け入れる

通常、編集コントロールは、ユーザーが入力するテキストを表しているため、テキスト更新要求を受け入れる必要があります。 TextUpdating イベント ハンドラーでは、編集コントロールに次のアクションが必要です。

  1. CoreTextTextUpdatingEventArgs.Text で指定したテキストを、CoreTextTextUpdatingEventArgs.Range で指定された位置に挿入します。
  2. CoreTextTextUpdatingEventArgs.NewSelection で指定した位置に選択範囲を配置します。
  3. CoreTextTextUpdatingEventArgs.ResultCoreTextTextUpdatingResult.Succeeded に設定して、更新が成功したことをシステムに通知します。

たとえば、ユーザーが "d" を入力する前の編集コントロールの状態です。 挿入ポイントは [10, 10] にあります。

挿入前の [10, 10]の挿入ポイントを示すテキスト ストリーム図のスクリーンショット

ユーザーが "d" を入力すると、次の CoreTextTextUpdatingEventArgs データで TextUpdating イベントが発生します。

編集コントロールで、指定した変更を適用し、 ResultSucceeded に設定します。 変更が適用された後のコントロールの状態を次に示します。

挿入後の \[11, 11\] の挿入ポイントを示すテキスト ストリーム図のスクリーンショット

テキストの更新を拒否する

要求された範囲が変更すべきでない編集コントロールの領域内にあるため、テキスト更新を適用できない場合があります。 この場合は、変更を適用しないでください。 代わりに、 CoreTextTextUpdatingEventArgs.ResultCoreTextTextUpdatingResult.Failed に設定して、更新が失敗したことをシステムに通知します。

たとえば、電子メール アドレスのみを受け入れる編集コントロールがあるとします。 電子メール アドレスにスペースを含めることはできませんので、スペース キーに対して TextUpdating イベントが発生した場合は、編集コントロールで ResultFailed に設定するだけで済みます。

テキスト変更の通知

場合によっては、テキストの貼り付け時や自動修正時など、編集コントロールによってテキストが変更されることがあります。 このような場合は、 NotifyTextChanged メソッドを呼び出して、これらの変更をテキスト サービスに通知する必要があります。

たとえば、ユーザーが "World" を貼り付ける前の編集コントロールの状態です。 挿入ポイントは [6, 6] にあります。

挿入前の [6, 6] の挿入ポイントを示すテキスト ストリーム図のスクリーンショット

ユーザーは、変更が適用された後に貼り付け操作と編集コントロールを実行します。

挿入後の \[11, 11\] の挿入ポイントを示すテキスト ストリーム図のスクリーンショット

このような場合は、次の引数を指定して NotifyTextChanged を呼び出す必要があります。

  • modifiedRange = [6, 6]
  • newLength = 5
  • newSelection = [11, 11]

1 つ以上の TextRequested イベントが続きます。このイベントは、テキスト サービスが操作しているテキストを更新するために処理します。

テキスト更新のオーバーライド

編集コントロールでは、テキスト更新をオーバーライドして自動修正機能を提供できます。

たとえば、収縮を形式化する修正機能を提供する編集コントロールがあるとします。 これは、ユーザーがスペース キーを入力して修正をトリガーする前の編集コントロールの状態です。 挿入ポイントは [3, 3] にあります。

挿入前の [3, 3]の挿入ポイントを示すテキスト ストリーム図のスクリーンショット

ユーザーが Space キーを押すと、対応する TextUpdating イベントが発生します。 編集コントロールは、テキストの更新を受け入れます。 これは、修正が完了するまでの少しの間、編集コントロールの状態です。 挿入ポイントは [4, 4] にあります。

挿入後の [4, 4]の挿入ポイントを示すテキスト ストリーム図のスクリーンショット

TextUpdating イベント ハンドラーの外部では、編集コントロールは次の修正を行います。 これは、修正が完了した後の編集コントロールの状態です。 挿入ポイントは [5, 5] にあります。

[5, 5] の挿入ポイントを示すテキスト ストリーム図のスクリーンショット

このような場合は、次の引数を指定して NotifyTextChanged を呼び出す必要があります。

  • modifiedRange = [1, 2]
  • newLength = 2
  • newSelection = [5, 5]

1 つ以上の TextRequested イベントが続きます。このイベントは、テキスト サービスが操作しているテキストを更新するために処理します。

要求されたテキストの提供

テキスト サービスでは、自動修正や予測などの機能を提供する適切なテキストを用意することが重要です。特に、ドキュメントの読み込み (たとえば、編集コントロールに既に存在するテキスト)、または前のセクションで説明したように編集コントロールによって挿入されたテキストの場合です。 したがって、 TextRequested イベントが発生するたびに、指定した範囲の編集コントロールに現在テキストを指定する必要があります。

CoreTextTextRequestRangeで、編集コントロールがそのまま対応できない範囲を指定する場合があります。 たとえば、 Range は、 TextRequested イベントの時点での編集コントロールのサイズよりも大きいか、 Range の末尾が範囲外です。 このような場合は、意味のある範囲 (通常は要求された範囲のサブセット) を返す必要があります。

サンプル

サンプルのアーカイブ