Hatena::Grouprekken

murawaki の雑記

2009-06-26

Mozilla の add-on で IME を作る

Mozillaadd-on による ime の実装。別に自分で作ったわけではなく、indicime という add-on を調べてわかったこと。

indicime はインド系言語を入力するためのパッケージ。といっても文字処理をやるだけ。日本語と違って入力に言語的な知識は必要ないから。しかも、文字のレンダリングブラウザが適当にやってくれる。結局のところ、やらないといけないのは、利用者の入力に対して、適切な Unicode のポイントを選ぶことだけ。

ウェブページには、JavaScript で ime を実現している例はいろいろある。例えば、The Uyghur - English Dictionary では、ウイグル文字をウイグル文字キーボード配列に従って入力できる。しかし、add-on の場合はどうすればいいのか分からない。

そこで、偶然見つけた indicime を調べることにした。しかし、Firefox 3.0 ではインストールに失敗する。テストしたとサイトで述べられているブラウザFirefox 1.5 とかなので、それ以降の Firefox の仕様変更が影響しているのかもしれない。そこで、ソースコードを眺めて見た。インド系文字は守備範囲外だが、調べるにあたってそれ程問題とならなかった。

まず入力キーから文字への変換テーブル。これは key=value という形式で properties ファイルに記述されている。properties ファイルのロードは XULstringbundle 要素によって行う。しかし mapping が二種類しかない。もっと多くの文字をサポートしていることになっているのに。この疑問にはすぐに答えが見つかった。The Unicode Standard, Version 5.0 の Chapter 9 South Asian Scripts-I に以下の記述がある。

The Unicode Standard encodes Devanagari characters in the same relative positions as those coded in positions A0--F416 in the ISCII-1988 standard. The same character code layout is followed for eight other Indic scripts in the Unicode Standard: Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, and Malayalam. This parallel code layout emphasizes the structural similarities of the Brahmi scripts and follows the stated intention of the Indian coding standards to enable one-to-one mappings between analogous coding positions in different scripts in the family. Sinhala, Tibetan, Thai, Lao, Khmer, Myanmar, and other scripts depart to a greater extent from the Devanagari structural pattern, so the Unicode Standard does not attempt to provide any direct mappings for these scripts to the Devanagari order.

つまり、Devanagari の配置に合わせて他の 8 種類の script の文字も配置されているから、offset をいじるだけで script の切り替えができるらしい。確かに indicime がサポートしている script はこの 1 + 8 個だ。

次はキー入力の処理。キー入力イベントは、window.addEventListener で keypress イベントを登録して捕捉。捕捉した ASCII のキーから変換テーブルを使ったインド系文字のコードポイントを得る。document.createEvent("KeyEvents") で新たな key event を作って event.target.dispatchEvent でその event を dispatch。そして元の keypress イベントは取り消す。意外と簡単。

しかし、実装はいろいろ微妙。まずグローバル変数を作りまくって名前空間を汚染しているのが許せない。

screenshot を見る限り user interface も微妙。でしゃばりすぎ。status bar にアイコン一つでよい。

window.addEventListener によるイベント登録も、最初に一度やってそのまま。だから常に listener が呼び出される。変換するか否かは convertFlag というグローバル変数で管理しており、listener 関数は convertFlag が true でなければ何もしない仕様。たぶん、ずっとイベントを捕捉するのではなく、こまめに addEventListener と removeEventListener を繰り返した方が良い。たぶん。

ソースコードを見る限り、キーボードから ime の on-off の切り替えができない様子。English と 9 種類の script の入力から GUI のメニューで選ぶ仕組みになっている。普通の ime のように、現在選択している言語を保持しておいて、直接入力との toggle をキー入力でできるようにすべき。それを実現するには event listener を使うのではなく、XULkey 要素を使うのが正解なのだろう。