はじめに
AppleのIME APIはドキュメントを読んだだけでは実装できないと思うので、わりと有用な記事になるかもしれません。
NSTextInputClient
Objective-Cだと10.5以降、Swiftだと10.10以降に対応という楽しいProtocolです。
他のIME APIと同様に、自前のTextViewを作るときくらいにしか使われません。
(https://developer.apple.com/reference/appkit/nstextinputclient?language=objc)
大まかな実装の手順は以下のとおり。
-
NSView<NSTextInputClient>
を継承したViewを作る - このView上に編集対象のテキストを表示可能にする
-
NSTextInputClient
の関数を実装する
これで、IMEを正しく扱うことができます。
WindowsのTSFと比較すると以下の機能には対応していません。
- 複数の文字列選択
- アプリケーション側からの再変換要求
ドキュメントに書かれていないこと
ドキュメントに幾度となく現れるmarked textとselected textですが、ドキュメントではそれらがどういう値を返すべきかという点については記述されていません。
なので初見殺しであろうこれらについて、実装した際の挙動から推測される定義をまとめておきます。
marked textとは何か
- 未確定文字列があるとき
- 未確定文字列の範囲
- 未確定文字列がないとき
- なし:
{NSNotFound, 0}
- なし:
selected textとは何か
- 未確定文字列があるとき
- 未確定文字列中の
setMarkedText
で渡された範囲
- 未確定文字列中の
- 未確定文字列がないとき
- 選択中の文字列の範囲
実装メモ
基本
以下の関数は素直に実装しましょう。
- hasMarkedText
- 未確定文字列の有無
- markedRange
- 未確定文字列の範囲
- selectedRange
- 選択文字列の範囲
- setMarkedText
- 未確定文字列の挿入
- unmarkText
- 未確定文字列の解除
- validAttributesForMarkedText
- 表示可能な装飾
- attributedSubstringForProposedRange
- 指定範囲の文字列
- insertText
- 文字列の挿入
- characterIndexForPoint
- ディスプレイ上の座標に対応する文字のインデックス
- firstRectForCharacterRange
- 指定された範囲の文字列の最前方の矩形
- doCommandBySelector
- 適宜処理する
縦書きのために
縦書きのために必要なことは、drawsVerticallyForCharacterAtIndex
(オプションの関数)でYES
を返すことです。
そのものズバリで簡単ですね。
再変換のために
文字列の再変換のために必要なことは、attributedString
(オプションの関数)を常に返すことです。
つまりNSAttributedString
という文字列長に比例した大きさのオブジェクトを返さなければいけません。
NSAttributedString
が世界最高の文字列クラスなら問題ないのですが、そんなことはないので実装には注意しましょう。
もちろんNSAttributedString
を使うならば何も問題はありません。
(TATEditorのデフォルトではIME側に見せる文字列の範囲をある程度狭めて返すようにしてます)
おわりに
素晴らしきAppleのドキュメントの充実っぷりを味わうことができたかと思います。
さて、明日はIME APIのGTK+編です。