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

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

もずはっく日記(2018年12月)

2018年12月11日

Bug-org 968056 keypress event shouldn't be fired for non-printable keys
初回投稿日時: 2018年12月11日23時35分00秒
最終更新日時: 2018年12月12日00時00分39秒
カテゴリ: Events IME KeyboardEvent Mozilla Core Mozilla65 バグ修正
SNS: (list)

長年、Geckoでは、モディファイアキーを除くキーの入力時に、keypressイベントを発火していました。しかし、UI Events (旧DOM Level 3 Events)ではkeypressは文字の入力時にのみ発火するという定義が(後から)行われました(例えば、aの入力では発火するが、Ctrl+aでは発火しない、また、ArrowDownのように、端から文字を入力しないキーの場合にも発火しない)。このバグ修正は、Geckoの動作をUI Evnetsの仕様通りの動作にあわせたものです。

Geckoではほぼ全てのショートカットキーがkeypressイベントを処理することで実装されています。そこで、まず考えられるのは、全ての内部のkeypressハンドラをkeydownイベントハンドラで書き換えることでした。しかし、ひとつ問題があります。keypressイベントは、keydownpreventDefault()が呼び出されない限りは発火しなくてはいけません。ですので、先行するkeydownイベントでのショートカットキーの実装は無理であると分かりました。

仕方ないので、keypressイベントのリスナを、Gecko内部システムグループに全て書き換えることにしました。Geckoはイベントの発火を毎回2回ずつ行っており、最初の発火でデフォルトグループと呼ばれるリスナ(通常のWebアプリのリスナはすべてこちら)向けに発火し、その後、システムグループのリスナ向けに再発火しています。そう、本来は全てのGeckoもしくはFirefoxのデフォルトアクションは、システムグループのリスナで実装されていなければ、Webアプリのリスナとどちらが先に処理するかというレースが発生してしまうので、これは潜在的だったバグを全て修正していく作業になりました。そしてもちろん、この大きな修正は、大量の自動テストの修正が余儀なくされたり、多くのregressionを出しつつ、潰しつつ、という作業に終始しました。

そして最終的に、上述のデフォルトグループでの発火のみを停止し、Webアプリからはkeypressイベントが、文字の入力がある場合にのみ発火するかのように見えるようになっています。

ちなみに、Enterキーの扱いのみが特殊です。そもそもEnterが押された場合、改行が行われますが、文字が入る訳ではありません。しかし、どのブラウザでもEnterキーが押された場合にはkeypressイベントが発火するので、Geckoもそれにあわせています。しかし、モディファイアキーと組み合わせた場合にkeypressイベントが発火するかどうかはブラウザ依存だったので、GeckoではShift+EnterCtrl+Enterkeypressイベントを発火するようにしています。特にCtrl+EnterはGeckoでは何も起きないのですが。

ちなみに、この修正はGoogleの検索チームから、これを修正しないとFirefox for AndroidのサポートをTier1から外したままにするよっていう宣告が来たのでかなりがんばって修正したんですが、この修正によって一番広範囲に壊れたのはGoogle Closure Libraryと、これをベースにしてるGoogle Docs等、Googleの他のチームのプロダクトだったというのがオチですかね……(Closureのチームと、Google Docsのチームは本当に大変な修正に尽力してくださったことに、あらためてお礼を言っておきます。ありがとうございました。)

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

bug-org 968056を含むエントリ

このエントリへのリンク元

このエントリを参照しているURIはありません。