この日記はMozillaのプロダクトへの貢献者としての私の成果を中心に、気になったバグやWeb界隈の話題について書いていますが、 断り書きがある場合を除き、いかなる団体のオフィシャルな見解ではありません。あくまでも個人的なものです。 Mozilla Foundation、Mozilla Corporation、及び関連企業の公式情報ではないことに注意してください。

現在、XHTML 1.0 (もどき)から、HTML5なコンテンツに修正中です。古い日記は修正が完了していませんので表示が崩れます。 順次、修正していく予定ですのでしばらくお待ちください。

もずはっく日記(2011年1月)

2011年1月24日

Bug-org 610821 IME composition doesn't start by typing a character for searching a tab on Panorama
初回投稿日時: 2011年01月24日15時26分56秒
最終更新日時: 2011年01月24日15時44分34秒
カテゴリ: Firefox Mozilla Core バグ修正
SNS: (list)

Panoramaで文字を入力すると自動的にタブの検索フォームが出現し、エディタに一文字が入力されますが、IMEがオンの状態でもフォーカスがエディタ外だったためにIMEが無効になっている時のキーイベントがそのままリダイレクトされるので、次の文字の入力から初めてIMEを経由することになり、意図通りに入力できない、というバグです。昔からFAYTが抱えているのと同じ問題です。

FAYTの時にも悩みましたが、Windowsの入力イベントの仕様上(Geckoの実装上?)、どうしようもないと思い、今回もUIのデザイン自体の見直しを提案していました。しかし、昨年知ったSendInput() APIが利用可能かもしれないと気づき、実験してみたところうまく動くことが分かりました。

WindowsではメッセージループにWM_KEYDOWNメッセージのみが送信されてきます。これをTranslateMessage() APIに渡すと、WM_CHARがメッセージキューに挿入されますが、このときにIME (IMM)にも処理が渡っているようです。Geckoでは、GetMessage()の後、直接TranslateMessage()を呼んでいて、WM_KEYDOWNをウインドウが受け取る時には既にIMEで処理が始まっていることになります。つまり、現在の設計ではDOMのkeydownイベントが発生した時点で、Windowsでは既にIMEが処理を開始している、もしくは、エディタ以外のIMEが無効になっている状態ではIMEを通さずにWM_CHARが生成されているという状態になっています。

TranslateMessage()をDOMのkeydownイベントの処理結果を見てから呼べという根本的な意見もあるかとは思いますが、開発サイクルのタイミング上、不可能ですし、色々なキーボードレイアウトでテストするにも時間がかかります。そこで、前述のSendInput() APIによってハックすることにしました。

WM_KEYDOWNの処理時に、DOMのkeydownイベントのハンドラがエディタにフォーカスを移動させてIMEが有効になった場合、WM_KEYDOWNのハンドラがSendInput()で再度、ネイティブの入力イベントを低レベルで発生させるようにしました。そして、WM_KEYDOWNのハンドラは次に来たキー入力が期待通りのものだった場合、DOMのkeydownイベントは再生成しません。そして、エディタ上でkeypressイベントか、compositionstartイベントが発生するようになっています。

そして、Panorama側ではkeydownイベントで検索を開始し、フォーカスを移動させるだけにしました。つまり、今までのkeypressイベントのリダイレクト処理は行わなくなっています。

この変更が具体的にWebアプリからみて、どのような影響があるのかはイベントの発生順序が見えるデモで確認してみてください。

当然のことながらIMEがオフの状態では以前と変わっていません。IMEがオンの場合、エディタ以外でキーを押すと、エディタには今までは来ていたkeypressイベントが来なくなっているのが分かるかと思います。その代わりにcompositionstartイベントやtextイベントが発生するようになっています。

ちなみに、Macではもともとこの修正後の動作でした。今回の修正ではWindowsとLinuxの動作をMacにあわせた形になります。もし、この変更でなんらかの悪い影響を受けるWebアプリケーションがあったとすれば、それはMacユーザには元々そのユーザ体験を提供してしまっていたことになります。

また、プラットフォーム関わらず、keydownイベントのpreventDefault()を呼び出してもIMEの動作を妨げることはできません。DOMのイベントモデル的には良くありませんが、そもそもこれが好ましいことかどうかは分かりません。そのようなロジックに依存したWebアプリを書くと、IMにまっさきにネイティブのKeyPressイベントを食われてしまうLinux (GTK2)上では動かなくなってしまうからです。

関連するかもしれないエントリ

bug-org 610821を含むエントリ