[UWP] さよならTSF、Windows.UI.Text.Coreで簡単日本語入力

# はじめに
Windowsの日本語入力のAPIとしてはIMM32がありましたが、IMM32の後継のText Services Framework (TSF)はインターフェースが100以上もあり非常に複雑でした。

通常の日本語入力ならTextBoxやRichTextBoxなどの入力コントロールを使えばよいのですが、自分でテキストエディタを作ったり、3Dゲームの画面で日本語入力をする場合はテキスト入力APIを使う必要があります。

ユニバーサル Windows プラットフォーム(UWP)では[Windows.UI.Text.Core](https://msdn.microsoft.com/library/windows/apps/windows.ui.text.core.aspx)という新たなテキスト入力APIが追加され簡単に日本語入力ができるようになったので、サンプルアプリを作って動作を調べてみました。

Windows.UI.Text.Coreについては以下のマイクロソフトの記事が参考になります。
[https://msdn.microsoft.com/en-us/windows/uwp/input-and-devices/custom-text-input](https://msdn.microsoft.com/en-us/windows/uwp/input-and-devices/custom-text-input)

### 初期処理
ユーザーが最初にテキスト入力コントロールをクリックしてフォーカスを得たら[GetForCurrentView](https://msdn.microsoft.com/ja-jp/library/windows/apps/windows.ui.text.core.coretextservicesmanager.getforcurrentview.aspx)を呼んで[CoreTextServicesManager](https://msdn.microsoft.com/ja-jp/library/windows/apps/windows.ui.text.core.coretextservicesmanager.aspx)を得ます。
それからCoreTextServicesManagerの[CreateEditContext](https://msdn.microsoft.com/ja-jp/library/windows/apps/windows.ui.text.core.coretextservicesmanager.createeditcontext.aspx)を呼んで[CoreTextEditContext](https://msdn.microsoft.com/ja-jp/library/windows/apps/windows.ui.text.core.coretexteditcontext.aspx)を作成します。

![Init.png](https://qiita-image-store.s3.amazonaws.com/0/118740/b8f1877c-086a-f2af-aa6d-f8ed86bb4c11.png)
イベントハンドラの登録など以降の処理はほとんどCoreTextEditContextに対して行います。

### テキスト入力の流れ

IMM32では変換中のテキストの描画はIMM32側がやってくれたのですが、Windows.UI.Text.Coreではアプリ側が描画する必要があります。
![Format.png](https://qiita-image-store.s3.amazonaws.com/0/118740/de6c9722-26e1-a1b1-0f93-d56e62f70f51.png)



![Intro.png](https://qiita-image-store.s3.amazonaws.com/0/118740/0f3dc9ae-c520-59c9-a243-6760fe056cc9.png)

挿入するテキストは[TextUpdating](https://msdn.microsoft.com/ja-jp/library/windows/apps/windows.ui.text.core.coretexteditcontext.textupdating.aspx)で通知され、下線などのテキストの書式は[FormatUpdating](https://msdn.microsoft.com/ja-jp/library/windows/apps/windows.ui.text.core.coretexteditcontext.formatupdating.aspx)で通知されます。
アプリはこれらの情報を元にテキスト、下線、入力カーソルを描画します。

UI.Text.Coreではアプリ側とシステム側がテキストの内容や挿入位置などの情報を共有して、それらが変化した場合は相手側に通知するような仕組みになっています。

### 変換候補ウインドウ
変換候補ウインドウの描画はシステム側がしますが、変換候補ウインドウの表示位置をシステムに知らせる必要があります。
[LayoutRequested](https://msdn.microsoft.com/ja-jp/library/windows/apps/windows.ui.text.core.coretexteditcontext.layoutrequested.aspx)が呼ばれたらテキストの入力位置を返します。

![Koho.png](https://qiita-image-store.s3.amazonaws.com/0/118740/0f1b5344-d0d5-5e56-99ed-353f904e81bd.png)

### テキスト挿入位置の変更
ユーザーが矢印キー(←,→)などでテキストの挿入位置を変更した場合は[NotifySelectionChanged](https://msdn.microsoft.com/ja-jp/library/windows/apps/windows.ui.text.core.coretexteditcontext.notifyselectionchanged.aspx)でシステムに変更を通知します。
これをしないと次回[TextUpdating](https://msdn.microsoft.com/ja-jp/library/windows/apps/windows.ui.text.core.coretexteditcontext.textupdating.aspx)が呼ばれたときに変な位置からテキストを挿入してしまうことになります。
![Cursor.png](https://qiita-image-store.s3.amazonaws.com/0/118740/faee9ab5-35cc-98fb-294a-19412cc95c1a.png)

同様にDeleteキーなどでテキストを変更した場合は[NotifyTextChanged](https://msdn.microsoft.com/ja-jp/library/windows/apps/windows.ui.text.core.coretexteditcontext.notifytextchanged.aspx)でシステムに変更を通知します。

### 感想
IMM32に比べると手間がかかりますが、TSFに比べるとアプリの実装がはるかに簡単になっています。
UI.Text.Coreの情報はまだほとんどなく試行錯誤をしている状態ですが、これからいろいろとアプリを作ってみたいと思います。

### サンプル
UI.Text.Coreの簡単なサンプルを作ってGitHubに上げてあります。
[https://github.com/teatime77/UI.Text.Core-Sample](https://github.com/teatime77/UI.Text.Core-Sample)
Windows 10のバージョン**1511(10.0.10586.0)**以降でないと動作しないのでご注意ください。

サンプルアプリの画面
![App.png](https://qiita-image-store.s3.amazonaws.com/0/118740/c5cadae0-612d-2b0e-f3b9-c3902df752c0.png)

サンプルの中のTestプロジェクトはUI.Text.Coreの動作を確認するための必要最小限のコードになっています。
単一行の文字入力で左右の矢印キー(← , →)とDeleteキーだけが使えます。
日本語･中国語･韓国語のMS IMEとGoogle日本語入力で動作を確認しています。

Testプロジェクトのメインのコードは以下になります。
[MainPage.xaml.cs](https://github.com/teatime77/UI.Text.Core-Sample/blob/master/Test/MainPage.xaml.cs)

TextEditorプロジェクトは実用的なエディタの雛形になることを目指して作った簡易版のテキストエディタです。
TextEditorの説明は以下をご覧ください。
[テキストエディタを自作する方法](http://lkzf.info/blog/2016/05/15/%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%82%A8%E3%83%87%E3%82%A3%E3%82%BF%E3%82%92%E8%87%AA%E4%BD%9C%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/)