MacOSXのインライン入力用のメモ

以前も調べた気もするが忘れてしまったのでメモ。

TSM には over the spot が無い

MacOSX の 標準 Input Method サービスである TSM (Text Service Manager) だけれど、俗にいう over the spot のモードを持っていない。このためにプリエディット(preedit)中の文字列の管理や表示は、クライアント側のアプリケーションで面倒を見てやる必要がある。標準のテキストオブジェクトを使用すればさほど問題は無いが、Squeak の様に自前でテキスト処理を行うアプリの場合、TSM から変換編集中の文字列を受け取り、俗にいう on the spot で処理してやる必要がある。
参考になるものとしては、CarbonEmacs が上げられる。これは細かに Emacs Lisp 側で Lisp オブジェクトとして処理を行っている。
(その他、Camino などもあるが、これは描画処理に ATUI を用いてグリフレベルからの描画を試みてるので現時点のSqueakにはオーバースペック気味かと思われる)
ちなみに、WindowsX11 も over the spot のモードを IM が持っている。
http://d.hatena.ne.jp/NyaRuRu/20070309/p1

プリエディット領域の実装

インライン入力を実現するためには、このプリエディットをどう実現するかが問題で、方策としては、

  • 案A) Carbon Emacs の様に、Squeak 側で細かにテキスト処理を行う(一種の on the spot )。これを実現した場合のユーザから見た典型的な操作イメージとしては、既存のテキストの途中にキャレットを移動して文字入力をすると、変換中の候補文字列の長さの変化に従いキャレット以降の文字列も伸び縮みをするような感じになる。ちなみに Windows などでは変換処理中は既存のテキストの伸び縮みは発生せず、確定後、一括してテキストの挿入が行われている。
  • 案B) プリエディット文字列用に擬似的に編集表示ウィンドウ(といっても枠は表示しない)を設けてそこで変換編集。確定(変換ハイライト位置の長さで判定可能)後、従来と同様に unicode 文字列として VM のキーイベントバッファに送り込み、Squeak 側で受け取る。

案A の場合、既存の primitive やキーイベント構造体では間に合わないのでこれらを拡張してやる必要があるだろう。
案B の場合、プリエディット用の OS 標準テキストオブジェクトを表示する処理を実装する必要がある。またこの状態(変換中なのか確定済みか変換がキャンセルされたか)を管理する処理も必要だろう。

ハンドラの修正

どちらを採用するかはともかくとして、既存のテキストイベントハンドラーは修正する必要がある。大前提としては、TSMDocument を使用するようにしなければならない。また、TSM から送られてくるイベントに対応した処理を実装する必要がある。
この辺りは id:shortsheeved さんの方で実験されている。

なお、イベント kEventTextInputOffsetToPos には、変換候補(Candidate)ウィンドウの位置を補正する処理を記述する。具体的には、SetEventParameter 関数を、引数イベントに kEventParamTextInputReplyPoint 引数データには変換候補ウィンドウが出現すべき座標(Point構造体)を与えて呼び出す。
また、イベント kEventTextInputUpdateActiveInputArea には、on the spot 処理を記述する。その際、GetEventParameter 関数を用いて文字列の取得や TextRangeArray 構造体を用いてテキストの状態(変換対象の長さなど)を取得してやる必要がある。
この処理を行うことは、従来 イベント kEventTextInputUnicodeForKeyEvent でユニコード文字列を一括で取得していたことが出来なくなるということであり、既存の該当する処理はすべて書き換える必要がある(単に入力文字列の取得だけでなく、ショートカットなどのキーボードイベント処理まで含めて)。
この部分は、以前の CarbonEmacs の inline-patch に基づいた判断である。
http://prdownloads.sourceforge.jp/macemacsjp/20284/inline_patch-20060517.tar.gz
(これは少し古いもの。現在の CarbonEmacs は、本家が TSMDocument 対応したことから、上記のパッチのイベント処理に相当する部分は、本家のEmacsのソースの方に取り込まれている。まだ、そちらは見ていない)


なお、ここまでの話は、手に入る範囲で資料を調べてみた中間結果であって、もしかしたら根本的に誤解していて、もっと簡単にインライン入力を実装することができるのかもしれない。