Opera is bad #7

いろいろ弄っているのでまた wasavi で取り留めのないことを書いてみよう。

テレビ、具体的には公共放送の相撲中継を見ていて気になるのだが、解説の親方はじめ、あまりテレビ慣れしていないと思われる方々はなぜかインタビューされると「そうですね、」というのを最初に付けすぎだと思う。なんなんだ、イエスマン症候群か。

それ系のことに注意してテレビのインタビューを見ていると、能動態と受動態の混乱とか、「~だし、~だし、~だし、……」という「『し』の行進」とか、「○○は、××が△△という○○」みたいな口語ならぎりぎり許されるレベルのへんてこな文構造とか、「~なんですけどー」(けど、何?)という定型的な語尾とか、いろいろ気になり始めるのである。

しかしまあ、気にしたら負けなのだろう。たぶん。

 * * *

ちなみにここまで wasavi on opera で書いてみて、なんか笑っちゃうほど buggy なので結構がっかりしているところである。ああ……。

一応 Opera の名誉のために書いておくと buggy なのは Chrome/Opera/Firefox で同じような動作をさせようとしている wasavi のコードであって、Opera は悪いか悪くないかといえばとりあえず悪くはない。しかし根本的な原因をさかのぼれば、いろいろと回りくどい動作を強いる Opera が悪いのは言うまでもない。

Opera is bad #6

ぼちぼち、Google 日本語入力でも安定して入力できるようになってきた。とはいえまだびみょーにあれ? という点がある。それを洗い出すためにとりとめのないことでも書いてみよう。

今使っているキーボードは Thinkpad USB Keyboard with trackpoint というやつなのだが、最近になってというか昨日のことなのだが「=」キーの効きが悪くなった。押下して、感覚的に入力されるかな? というタイミングで入力されない。そこでキートップを外してみた。

キートップを外すのは割と簡単だ。パンタグラフの四隅が、キートップの裏のそれぞれのかみ合わせに引っかかるようになっている。そこでマイナスドライバーをまずキーの下側の真ん中に差し込み、くるっと回す。同様に上側からもドライバーを差し込み回す。回すのはゆっくりではなく素早くやったほうが良いようだ。

ちなみに tab キーを始めとする横に長めのキーは四隅というにはちょっと中心部分に寄ったところがかみ合わせになっているので、ドライバーでくるっ、も 4 回に分けたほうが無難だ。

というわけで外してみたところ、細い毛がラバーカップの上に乗っていた。こんな微妙な原因でキータッチの感覚が変わってしまうのかー。

などと書いていて早速気づいたが、変換した時に出てくる候補のポップアップが仮入力文字列の上にかぶさっていてとても見にくい。うーんテストページではちゃんと表示されるんだけどな。カーソルの要素が position:fixed なのが問題なのかしらん? とりあえずいろいろ調べて見ることにしよう。

 * * *

どうも Opera のバグのようだ。wasavi の iframe に box-shadow をかけて、さらにその iframe が position:fixed か position:absolute だったとき、おそらく内部的には原点が影の分だけ左上に移動するのだろうが、変換候補ポップアップについてはそれを考慮した補正を忘れている。とそんな感じだと思う。Chrome や Firefox ではそういった現象は起こらない。また、これが起こるのは Windows だけのようだ。

ということでバグレポした。DSK-380712。

Opera が悪い。

Opera is bad #5

勘違いだった。Google 日本語入力でも、イベントの発生の仕方は同じだった。wasavi 側の対応をちょっと修正。input モード時はカーソルを消去しないようにした。

ちなみに、キーボードの入力のテストは http://appsweets.net/wasavi/keytest/index.html で行うことができる。手元には Windows+ATOK とか、Mac OS X の環境がないので確認できない。それらの環境で、compositionstart、compositionupdate、compositionend イベントが Chrome や Firefox と異なる振る舞いをしていたら教えてください。

Ubuntu でも試してみた。iBus+Anthy、iBus+mozc の両方で、仮入力中はなぜか keydown イベントが発生しない。input や keyup イベントは発生する。うーんどういうことなのか。keydown イベントが発生しないとそもそも composition events のエミュレーションを開始すること自体ができないのだけど。これはどうすることもできないかもしれない。

いやー本当に、Opera は、ダメなブラウザだ。Opera が悪い。

Opera is bad #4

wasavi の設定は、基本的には exrc、つまりエクステンションが保持する localstorage の項目に書いておく。しかしこれだけだといろいろと煩雑だ。また、wasavi を使用するのは何かを送信するフォーム内の textarea というケースが最も多いと思うが、ajax を駆使したフォームでもない限り送信することでページが更新されるので、送信前の wasavi でテンポラリ的に :set なんちゃらした値は送信と共に失われてしまう。

これをなんとかしたい。つまり、wasavi の実行中に動的に変更したオプションを、ページの更新を超えて自動的に再現したい。

ここで難しいのは、ページ更新前に与えた wasavi の設定が、更新後の html 内のどの textarea に対応するか、という判定だと思う。たとえば textarea に id が振られていれば、それを判断の材料にできる。しかし id に頼るのは危険かもしれない。論理的には更新前後で同じ textarea だったとしても、サーバ側の都合で異なる id を振られている場合が考えられるからだ。

id ではなく、たとえば html のルート要素から textarea へ至るパスを頼るのはどうか。つまり html->body->div->textarea みたいな感じの文字列をキーにしたハッシュを保持して、それに設定を書いておく。実際は、html(1)->body(1)->div(3)->textarea(1) みたいに要素のインデックスも必要かも。

この構造が更新ごとにダイナミック、あるいは微妙に変化する html ページってあるかなあ。たとえば更新ごとに div 内の最初に textarea が配置されたり最後に配置されたりするページ。ないとは言えないか。そうすると、ノード名を単語とみなした sentence similarity measure を測ったりする必要があるかもしれない。めんどうだなー。

 * * *

よく考えたらこの話題は別に Opera に文句をつけるものではなかった。まあいいか! Opera が悪いのは事実だし!

Opera is bad #3

Opera で擬似的に composition events を実装する場合、様々な処理を最終的に keyup ハンドラ内で行うことになる。これはひとつ奇妙な振る舞いを引き起こす。キー入力は、基本的には keydown -> keypress -> input -> keyup の流れでイベントを発生させるのだが、しかし高速にキーボードを捌いたりすると、複数のキー入力の各サイクルがオーバーラップしてしまうことがある。

といっても Opera に問題があるわけではなく、つまりキーボードの打ち方の問題で、例えばあるキーを離す前に次のキーを押したりした場合だ。そうすると keydown -> keydown -> keyup -> keyup みたいな感じでイベントが発生する。

これを考慮しないと、正しく composition を認識できない。ので、考慮するようにした。

 * * *

keydown および input イベントの引数 e を蓄えておくキュー、keyup イベントの引数 e を蓄えておくキューを保持する。前者のキューの 1 項目は、

{
keyDownEvent: { ... },
currentString: '',
inputEvent: [ ... ]
}

てな具合。keydown イベントハンドラで、keyCode が 229 だったら IME に対する入力とみなし、ハンドラ本体の本来の処理はせず、キューに必要な情報を埋めるだけにする。keyup イベントハンドラで、keydown キューの長さ – 1 == keyup キューの長さではない場合、つまり keydown イベントが複数回連続して発生した状況である場合は、keyup キューに必要な情報を埋めるだけにする。

keydown キューと keyup キューのバランスが正しい場合は keyup ハンドラ本来の処理を行うが、それに先駆けて溜まったキューを処理する。イベントの引数 e をもって keydown、input イベントハンドラを直接呼ぶ。

 * * *

composition 文字列が更新されるごとに直前の文字列の長さを覚えておくようにし、暗黙的確定のようであれば直前の compositon 文字列のほうを採るようにした。つまり暗黙的確定にも対応した。

しかしだからといって Opera でも IME に対応しました! とはとても言えない。だいたい IME に対する入力時の keyCode、229 って何なのかさっぱりわからない(IE に準じているっぽいが)し、明示的確定では input イベントが連続して 2 回、暗黙的確定では 3 回とかどこにも文書化されてもおらずそもそもバグの産物なのかも知れず未来のバージョンでもそれが維持されるかもおぼつかない。ダメダメすぎる。Opera が悪い。

Opera is bad #2

しかしそうも言っていられない。Opera が対応している keypress、keydown、keyup、input イベントでなんとか擬似的に composition events を再現できないか。

ということでそれっぽくできた。一応このエントリも、今まさに wasavi で書いている。しかし問題は山積している:

  • 結局のところ、例の暗黙的確定には対応できない。
  • 上記のイベントの、Opera 12.12 上での動作にきわめて依存した構成なので、安定してるともいえない。

つまり人様にお出しするにはちょっと……という出来である。どうしよう。

ちなみに擬似 composition events の実現手法だが、Opera で IME の仮入力は、keydown、input、keypress の順でイベントが発生する。このとき、input イベントは場合によっては複数回発生する。仮入力中は、keydown 時の keycode は 229 で固定。keyup 時の keycode は本来押されたキーのコードが入っている。

IME がアクティブな時の様々な動作の特徴は以下の通り:

  • 明示的確定: 仮入力後変換候補を出している状態で、enter キー押下により確定する動作。keydown(229)、input が 2 回、keyup(13)
  • 暗黙的確定: 仮入力後変換候補を出している状態で、変換に使用しないキーの押下により暗黙的に確定する動作。たとえば「漢字」と変換した状態でそのまま続けて HENKAN と打つと、「漢字」は自動的に確定され、かつ確定に使用した文字「H」が次の仮入力に持ち越される。この動作は composition events でなければ正しく認識できない。keydown(229)、input が 3 回、keyup(暗黙的確定に使用した文字のキーコード)
  • 仮入力の取り消し: 取り消しには 2 パターンの方法がある。escape キーを押すか、backspace で仮入力文字を全削除するか。前者は keydown(229)、keyup(最後に入力した文字のキーコード)。つまり input イベントが発生しない。後者は発生する。さらに、IME がアクティブで、かつ仮入力文字列が空かどうかで判断する
  • その他の仮入力、変換操作: keydown(229)、input が 1 回、keyup(最後に入力した文字のキーコード)

keydown、input、keyup をリスンし、keydown 時のキーコードおよび input が発生した回数を覚えておく。上記の場合分けはすべて keyup のハンドラで行う。

その他の仮入力、変換操作で、IME がアクティブ(これは実際の IME の状態ではなく、javascript 上のフラグ)でなければ、compositionstart イベントを発火し、IME がアクティブ状態であるとする。それから、compositionupdate イベントを発火する。

2 種の確定動作で確定された文字列を取り出し、compositionend イベントを発火し、IME が非アクティブ状態であるとする。

Opera is bad

UAX #14 に準拠した段落の再フォーマットを実装したということは、つまり日本語を初めとする latin-1 以外の文字を含んだ段落もそれなりに処理してくれるということなのだが、さて wasavi と日本語の入力という点を考えてみると、要するにというか例によってというか DOM3 Composition Events の話になるのだが、一応実装してあるものの、あまり詰めているわけではない。これはいまだに Composition Events を実装していない Opera が悪い。

Composition Events の他に、エクステンションからシステムのクリップボードを読み書きすることも Opera 版 wasavi ではまだ不可能だ。Opera が悪い。

辛うじて、Opera も input イベントは実装しているので、擬似的に compositionend イベントをエミュレートすることはできなくもない。しかし前にも書いた気がするが、これだと仮入力して変換候補を出している状態で、変換に使用する以外のキーを押して暗黙的に確定をした際の正確なタイミングをキャッチできない。Opera が悪い。

あまりエラソーなことも言いたくないが、Opera の中の人は IME を使用する言語圏のことはどうでもいいの? やる気ないの? 特に Opera の日本支社のヒトは何をしているの? と思わざるを得ない。みすみすニーズを逃している。Opera が悪い。

Composition Events が実装されるのを待って、かれこれ 3 年になろうとしている。そういえば XMLHttpRequest#overrideMimeType が実装されるまでにも相当待ったのを思い出した。もうちょっと開発者の声に耳を傾けていただきたいものだ。

Opera が悪い。