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

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

もずはっく日記(2012年2月)

2012年2月23日

Bug-org 630813 Store the native modifier mask information in GdkKeymap's wrapper class and use it instead of GDK_MOD*_MASK
初回投稿日時: 2012年02月23日11時04分14秒
最終更新日時: 2012年02月23日11時06分06秒
カテゴリ: Mozilla Core Mozilla13 バグ修正
SNS: (list)

1年もかかってしまいましたが、ようやく大物がひとつ片付きました。Linuxのキーイベントの処理のうちのややこしい部分をnsWindowから分離しました。GtkKeymapのラッパーで、名前もそのままに、mozilla::widget::KeymapWrapperです。

GDKでは、正体がよく分かってませんが、GdkDisplay単位でGdkKeymapを管理することができます。一応設計としては、そのような複数のGdkDisplayが存在する環境が当たり前になった場合にも対応できるようにはしていますが、今回の修正では簡略化のためにデフォルトのGdkDisplayGdkKeymapに常にアクセスするようにしています(これは既存の動作のまま)。ですので、もし、この挙動で困る環境があって、修正すべきだと考えられるのであれば、バグを報告してもらって、利用シーンについて説明してもらえれれば対応可能だと思います。

話がそれてしまいましたので戻します。今回の修正では主に、モディファイアキーの処理の改善を目的においていました。Xにおいて、モディファイアの定義というのは抽象化されすぎていて、GDKでは以下のような定数で定義されています。

typedef enum {
  GDK_SHIFT_MASK    = 1 << 0,
  GDK_LOCK_MASK	    = 1 << 1,
  GDK_CONTROL_MASK  = 1 << 2,
  GDK_MOD1_MASK	    = 1 << 3,
  GDK_MOD2_MASK	    = 1 << 4,
  GDK_MOD3_MASK	    = 1 << 5,
  GDK_MOD4_MASK	    = 1 << 6,
  GDK_MOD5_MASK	    = 1 << 7,
  GDK_BUTTON1_MASK  = 1 << 8,
  GDK_BUTTON2_MASK  = 1 << 9,
  GDK_BUTTON3_MASK  = 1 << 10,
  GDK_BUTTON4_MASK  = 1 << 11,
  GDK_BUTTON5_MASK  = 1 << 12,

  /* The next few modifiers are used by XKB, so we skip to the end.
   * Bits 15 - 25 are currently unused. Bit 29 is used internally.
   */
  
  GDK_SUPER_MASK    = 1 << 26,
  GDK_HYPER_MASK    = 1 << 27,
  GDK_META_MASK     = 1 << 28,
  
  GDK_RELEASE_MASK  = 1 << 30,

  GDK_MODIFIER_MASK = 0x5c001fff
} GdkModifierType;

GDK_MOD1_MASKが慣例的にAltとなっていますが、NumLockに関しては定義されていません。

さらに悩ましいことに、他のプラットフォームと違って、モディファイアとモディファイアキーが1対1の関係にはなく、ひとつの物理キーが複数のモディファイアの意味を持つことがあります。例えば、一般的なディストリビューションをインストールして、特にキーボードレイアウトを変更しないまま利用していると、Altキーは、Altにあたるモディファイアの状態を変更しますが、Alt+Shiftだと、モディファイアの状態変更はそのままに、Metaキーが押されたというイベントに変わってしまいます。このままでは他のプラットフォームでの挙動と整合性がとれません。

今回の修正の一点目は、各物理キーが、どのモディファイアのビットを含んでいるのかを予め取得しておき、これをDOMキーイベントの挙動補正に利用するようになりました。以前説明したように、Linuxではアプリケーションがキーイベントを処理している段階では、モディファイアの状態はまだ変更されていませんので、モディファイアキーのkeydownイベントを送信する際には、その押されたキーのもつモディファイアも含めて反映するようになりました。keyupイベント時のモディファイア情報は今まで変わらず補正無しで、他のプラットフォームとは異なり、モディファイアの状態は実際には押されてなくても、DOMキーイベントでは押されたままとなっています。

二点目は、モディファイアキーのDOMキーイベントのkeyCodeは他のモディファイアキーが押されていない状態でのキーを基に、算出されるようになりました。上記のように、Shift+Altで、DOM_VK_METAキーとなっていた環境でも、Altキーのみを押した場合と同様にDOM_VK_ALTキーがkeyCodeに設定されるようになりました。ただし、他のモディファイアキーとの組み合わせで初めてモディファイアキーになるような場合、例えば、JISキーボードレイアウトでは、標準設定のままだと、Shift+英数CapsLockキーになります。このような場合に、keyCode英数キーのものにしてしまうと問題がありますので、CapsLockキーのkeyCodeをそのまま送信します。

三点目は、全てのモディファイアキーを調べられるDOMイベントではこの新しいクラスでisShiftisControlisAltisMetaを設定されるようになりました。これに伴い、isMetaの値がイベントの種類によってまちまちだった状況が改善され、常にfalseになっています。Metaという名前が悪いと思うのですが、これはMacではショートカットキーのコンビネーションで主に利用されるCommandキーが押された場合にtrueになりますので、Mac版でのみテストされたWebアプリケーションでは誤動作する可能性がありました。また、Macのこのキーは明らかにLinuxでのMetaキーとは異なっています。他のプラットフォームには存在せず、また重要ではないモディファイアがWebアプリから簡単に利用できても有害なのでこの情報はDOMイベントには反映されなくなりました。

今回の修正で最も大きな成果は、アクティブなキーボードレイアウトの生存期間のみ生存しているインスタンスができたことです。これにより、今まではパフォーマンスを気にして細かく調べられなかったことを調べ、その結果をキャッシュしておくことが可能になりました。また、単純にnsWindowからの独立は機能を拡張しやすくなったことを意味しています。来週以降、このバグ待ちで止まっていたWindows、Mac、LinuxでのkeyCode算出ルールの統一化の作業を行っていきます。Webコンテンツ的には本来なら必要の無い話なのですが、keyCodeはchrome内のスクリプトにとっては変わらず重要な情報ですのでここを避けて通ることはできません。ですが、これが終わればいよいよこれらのプラットフォームで同時にD3EのKeyboardEventの各属性を順番に実装していく予定です。順調にいけば、来年リリースされる分ぐらいからは、FirefoxのキーボードイベントはD3E仕様をほぼ満たしたものになるのではないかと思います。

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

bug-org 630813を含むエントリ