Gecko Keypress Event

Gecko 1.9 のキーハンドリングは Beta 5 後に大きく変更されました (バグ 359638バグ 429510 と、その関連バグ参照)。この変更はリスクが大きく、また、リリーススケジュール上、遅すぎるものでしたが、多くのキーハンドリングバグを修正するために必要なものでした。

DOM keypress イベントの charCode

もし、keypress イベントがモディファイアキー (<kbd>Ctrl</kbd>/<kbd>Alt</kbd>(<kbd>Option</kbd>)/<kbd>Meta</kbd>(<kbd>Win</kbd>/<kbd>Command</kbd>) 無しで生成された場合、そのイベントのプロパティ値は Gecko 1.8.1 から変更がありません。つまり、charCode プロパティの値は、現在選択されているキーボードレイアウトで入力された Unicode 文字 ( <kbd>CapsLock</kdb> と <kbd>NumLock</kbd> の状態も考慮されます) です。

keypress イベントがモディファイアキーと共に生成された場合、charCode の値は以下のルールによって、ASCII 文字に置換されます。

accel キーとはプラットフォームによって実際のキーが変わるもので、Windows と Linux では <kbd>Ctrl</kbd> キーが accel キーです。Mac では <kbd>Meta</kbd> (つまり、<kbd>Command</kbd>) キーが accel キーです。

この accel キーが押されている時、keypress イベントの charCode は、そのキーボードレイアウトから入力された文字が非 ASCII 文字の場合にのみラテンキーボードレイアウトとして考えた場合の文字で置換されます。

この挙動は独自のショートカットキーを持つ Web アプリケーションの国際化を助けます。もし Gecko が charCode を ASCII 文字で置換しないと、Web アプリケーションの開発者は世界中の非ラテンキーボードレイアウト (アラビア語、ギリシャ語、ヘブライ語、ロシア語のキーボードレイアウト等) から入力される文字をハンドリングしなければいけません。

charCode 値は <kbd>CapsLock</kbd> と <kbd>NumLock</kbd> の状態に依存します (ただし、Mac で <kbd>Alt</kbd> (<kbd>Option</kbd>) が押されている場合には現在のビルドでは無視されます。バグ 432953にバグとして登録されています)。また、プラットフォーム毎に若干の違いがあるので、以下のセクションで説明します。

Windows

charCode は <kbd>Ctrl</kbd> が押されていて、なおかつ <kbd>Alt</kbd> キーが押されていない場合にのみ置換されます。

そのイベントで入力された文字が <kbd>Ctrl</kbd> キー無しで入力できない場合、Gecko はその文字を置換しません。例えば、ペルシャ語のキーボードレイアウトでは <kbd>Ctrl+Shift+'2'</kbd> で ZWNJ 文字を入力できますが、<kbd>Shift+'2'</kbd>では '@' が入力されます。もし、Gecko がこのような条件下で charCode を置換してしまうと、ユーザは ZWNJ を入力できなくなってしまいます (バグ 414130)。

それ以外の場合、Gecko は charCode 値を置換できますが、実際に置換するのはそのキーがアルファベットを入力するキー (VK_A から VK_Z) である場合と、数字 (VK_0 から VK_9)、プラス記号 (VK_OEM_PLUS)、マイナス記号 (VK_OEM_MINUS) の場合のみです。

オリジナルの (非 ASCII) 文字をこれらのキーの場合に置換するということは、非ラテンキーボードレイアウトユーザが多くの非 ASCII 文字をショートカットキーとしては利用できないというアクセシビリティ上の問題があることに注意してください。つまり、Web アプリケーションの開発者はアルファベットと、ASCII の数字、プラス記号、マイナス記号のみを独自のショートカットキーとして使うべきです。

Linux

charCode は <kbd>Ctrl</kbd> が押されていて、なおかつ <kbd>Alt</kbd> と <kbd>Meta</kbd> キーが押されていない場合にのみ置換されます。

もし、そのイベントで入力された文字が <kbd>Ctrl</kbd> キー無しで入力できない場合、Gecko は (Windows 版と同様) 置換を行いません。

Mac

charCode は <kbd>Meta</kbd> (<kbd>Command</kbd>) or <kbd>Ctrl</kbd> が押されている場合に置換されます。

もしキーボードレイアウトが Dvorak-QWERTY レイアウトか、非ラテンレイアウトの場合、<kbd>Command</kbd> キーはキーボードレイアウトを US QWERTY キーボードレイアウトに一時的に変更します。Gecko はこのレイアウトで入力される文字を <kbd>Ctrl</kbd> キーが押されている時にも利用します。

ですが、<kbd>Ctrl</kbd> が押されている場合、Gecko 1.9 では現在、押されたキーがアルファベットの場合にのみ、charCode を置換します。この挙動はバグで、将来のメジャーバージョンアップの際に修正されます (バグ 432951)。

内部キーハンドリングのための代替 charCode

このセクションでは Gecko 内部の keypress イベントのハンドリングについて解説しています。ですから、Web アプリケーションの開発者はこのセクションを読む必要はありません。

Gecko は DOM keypress イベントでは、アクセラレーションキーハンドリングのために charCode を置換しますが、これだけでは全ての問題を解決できません。

問題点 1

Firefox のズームインのショートカットキーは <key key="+" modifiers="accel"/> と定義されています。しかし、US キーボードレイアウトでは <kbd>'+'</kbd> の入力には、<kbd>Shift</kbd> キーが必要です。このため、ハンドラ内でモディファイアキーの比較を行う際に Shift キーが、定義に対してミスマッチの原因となってしまいます。

US キーボードレイアウトのために、<key key="=" modifiers="accel"/> もあわせて定義されていますので、US キーボードレイアウトを利用している場合にはズームインのショートカットを利用する際に Shift キーは不要です。ですが、これでは他のキーボードレイアウトのユーザには問題があります。例えば日本語キーボードの場合、<kbd>'+'</kbd> は <kbd>Shift+';'</kbd>で入力されるためです (バグ 339723)。

問題点 2

メニュー項目のアクセスキーはローカライズされたビルドでは、ローカライズされた文字で定義されています。これらのローカライズされたアクセスキーはその言語のキーボードレイアウトでは動作します。

ですが、非ラテンキーボードレイアウトのユーザは英語版のビルド (ナイトリービルド含む) を利用する場合に、キーボードレイアウトを変更することなくラテン文字のアクセスキーを利用できるべきです (バグ 399939)。

問題点 3

非ラテンキーボードレイアウトのユーザは Web ページのラテン文字のアクセスキーにキーボードレイアウトの変更無しで利用できるべきです (バグ 429510)。

問題点 4

Windows と Linux で Web コンテンツのアクセスキーを利用するには (デフォルト設定では) <kbd>Shift</kbd> キーを押す必要があります。これは (Shift モディファイアが 二つの文字からひとつを選択する場合に) 同じキーで二つの異なる文字のアクセスキーのどちらにユーザがアクセスしようとしたのかを判断することはできません。どのような文字の組み合わせが同じキーの上に設定されているのかは、キーボードレイアウトに依存します。

(バグ 359638 ではキーの両方の文字でアクセスするようになりました。ですが、バグ 303192 はより完璧な解決方法になるでしょう。)

解決策

以下の規則を用いることにしました:

  • キーハンドラはそのイベントのキーの持つ全ての文字の情報を得られるべきです。
  • 外側の要素が完全に一致するハンドラを持っていても、内側の要素が不完全に一致するハンドラを持つ場合、そのイベントは内側の要素によって処理されるべきです (バグ 433192)。
  • Web コンテンツのアクセスキーを処理する時、そのキーの(<kbd>Shift</kbd> が押されていない時、押されている時)両方の文字を利用すべきです。この際、<kbd>Shift</kbd> が押されていない場合の文字を優先します。(メニューのアクセスキーを含む、chrome のアクセスキーハンドリングもほぼ同様ですが、この仕組みが利用されるべきではありません。chrome のアクセスキーとして、句読点や括弧等の記号は Shift キーが必要になるかもしれないので利用されるべきではありません。)
  • アクセラレーションキーハンドリングの際、<kbd>Shift</kbd> が押されていて、charCode がケース変更可能な文字ではない場合(つまり、大文字、小文字の区別が無い文字の場合)に、完全にモディファイアキーがマッチするハンドラが存在しない場合には、<kbd>Shift</kbd> の状態は無視されるべきです。(Mac で <kbd>Option</kbd> (<kbd>Alt</kbd>) が押されている場合、<kbd>Alt</kbd> も同様に無視されるべきですが、Gecko 1.9 ではそのように実装されていません。これは バグ 306585 で登録されています)。
  • アクセラレーションキーハンドリングの際、入力された文字がケース変更可能な文字の場合、<kbd>Shift</kbd> は無視されるべきではありません。つまり、<kbd>Ctrl+Shift+'C'</kbd> は <kbd>Ctrl+'C'</kbd> のコマンドを実行すべきではありません (バグ 433192)。
  • アクセラレーションキーハンドリングの際に <kbd>Shift</kbd> が押されていない場合で、なおかつ <kbd>Shift</kbd> が押されていない場合の文字が数字以外で、<kbd>Shift</kbd> が押されている場合の文字が数字の場合、そのキーはフランス語の AZERTY キーボードレイアウトか、それに類似したレイアウトの一番上の列の数字のキーだと考えられます。数字はショートカットキーでは利用されるので、これらのキーでの数字は優先度が低めのショートカットキーの候補の一つとして扱うべきです (バグ 429219)。

これらの条件はとても複雑なものです。そして、これらの規則は新しい問題が見つかる度に変更されていくことになります。そのため、XUL アプリケーションの開発者は key 要素をアクセラレーションキーハンドリングに利用すべきです。この要素を利用したハンドリングでは、これらのロジックが自動的に用いられるためです。XUL アプリケーションは keypress イベントでハンドリングするように実装するべきではありません。同様に、アプリケーションはアクセスキーの処理には keypress イベントでハンドリングしようとせずに、accesskey 属性を用いるべきです。

もし XUL アプリケーションがショートカットキーを自前で処理しようとする場合、各実装部分は上記の規則が変更された場合に毎回コードを書き直す必要があります。

実装

ネイティブ keypress イベントで、キーが入力可能な文字を nsGUIEvent.hnsKeyEvent::alternativeCharCodes に保存します。ですが、これらは直接外部からアクセスされるべきではありません。アクセラレーションキーハンドリングの場合は nsContentUtils::GetAccelKeyCandidates() 経由で、アクセスキーハンドリングの場合は nsContentUtils::GetAccessKeyCandidates() 経由でアクセスすることによって、上記の規則が適用された候補のリストを取得することができます (nsContentUtils.hnsContentUtils.cpp 参照)。

Document Tags and Contributors

Contributors to this page: Masayuki, Potappo
最終更新者: Potappo,