LoginSignup
9

More than 5 years have passed since last update.

IMEを使う(macOS編)

Posted at

はじめに

AppleのIME APIはドキュメントを読んだだけでは実装できないと思うので、わりと有用な記事になるかもしれません。

NSTextInputClient

Objective-Cだと10.5以降、Swiftだと10.10以降に対応という楽しいProtocolです。
他のIME APIと同様に、自前のTextViewを作るときくらいにしか使われません。
https://developer.apple.com/reference/appkit/nstextinputclient?language=objc)

大まかな実装の手順は以下のとおり。

  1. NSView<NSTextInputClient>を継承したViewを作る
  2. このView上に編集対象のテキストを表示可能にする
  3. 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+編です。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
9