2013年12月19日
最新のD3E仕様の変更に伴い、スペースキーや、テンキー上の、数字とEnterキー以外につけられていた、KeyboardEvent.key
用の固有のキー名を削除しました。
今まで、D3E仕様に不明瞭なところがあったので、KeyboardEvent.key
の、プリンタブルキーの値はMozPrintableKey
値を暫定的に設定していましたが、仕様が概ね固まったので、デッドキー以外に関しては最新仕様にあわせたものに修正されました。現行仕様は以下のようになっています。
- 文字列が入力される時
- 入力される文字列
- モディファイアキーにより、文字列が入力されない、もしくは制御文字の場合
-
- OSが参考に提供する文字列が変わる場合(Macのcommandキー押下時)
- その提供された文字列(多くの場合、QWERTY配列のアルファベット)
- AltGrキー、もしくはMacのoptionキーが押されている場合
- AltGrキーを押さなかった場合に入力される文字列
- それ以外のモディファイアキーが押されている場合
- Shiftキーを除いたモディファイアキーが押されていない場合に入力される文字列
また、Geckoでは、Windowsのカナロックは無視します。Macでは、ことえりのかな入力時や、ハングル・中国語IMEではキーボードレイアウトを変更しますが、IME依存の動作でWebアプリにとって互換性テストの負担が大きすぎるので、その時のASCII Capableキーボードレイアウトを利用します。
プラットフォームを問わず、プリンタブルキーが文字を入力しない場合、例えば、テンキーのカンマキー(セパレーターキー)が、ブラジルのポルトガル語レイアウト以外では文字入力にならない場合、空文字列になります。
なお、今回の修正では、QtとOS/2は修正していません。これらのプラットフォームは今後、複雑な修正は行わない予定です。貢献者がパッチを提出してきてくれた場合にはレビューは行いますが。
Geckoや、Firefox等のXULアプリは、DOMイベントをハンドリングすることで、イベントのデフォルトアクションを実装しています。前者で、イベントのディスパッチが完全に終了した後以外にハンドリングした場合には、他の要素がデフォルトアクションを二重実行してしまわないように、Event.preventDefault()
が呼び出されています。これが原因で、イベントを保存しておいて、イベントのディスパッチが終了した後にEvent.defaultPrevented
の値を確認すると、WebアプリがEvent.preventDefault()
を呼び出したわけでもないのに、true
になっている、という奇妙な状態になっていました。
今回の修正で、Event.preventDefault()
が、content権限のJavascriptから呼ばれた場合にのみ、mozilla::EventFlags::mDefaultPreventedByContent
をtrue
にし、content権限のJavascriptがEvent.defaultPrevented
の値を確認した場合には、mozilla::EventFlags::mDefaultPreventedByContent
もtrue
でなければ、true
に見えないようになっています。
つまり、chrome権限で動作している(はず)のアドオンから見ると、動作は一切変わっていませんので、互換性に問題が出ないように配慮しています。
また、Event.defaultPrevented
が提案されるまで、独自に実装していたEvent.getPreventDefault()
は、そもそもWebコンテンツでは利用されるべきではありませんし、これを未だに利用しているWebアプリがこの修正により不具合が出たしてもメンテされる可能性が低いので、互換性維持の観点から、元の動作のままにしてあります。
ファイルやURLを<input>
要素等にドロップしても、タブがそれを読み込んでしまって、ドロップした要素固有の処理にならない、というバグです。
Bug-org 930374の修正時に、ドラッグイベントが利用していたmozilla::EventFlags::mDefaultPreventedByContent
フラグの設定条件を私もレビュアのSmaugも共に誤解していたため、これをそのまま流用したことが原因です。
ドラッグイベントでは、これを、どのコンテキストでEvent.preventDefault()
が呼び出されたのか、ではなく、contentとchrome、どちの要素上にある時に呼び出されたのか、を記録していました。
今回の修正で、WidgetDragEvent::mDefaultPreventedOnContent
を新たに作り、こちらに元通りの条件でtrue
をセットするようにしています。
MacにPC用のキーボードを接続し、コンテキストメニューを開く、アプリケーションキーを押すと、制御文字である、U+0010
が入力され、それがエディタにそのまま表示されてしまうというバグです。
Macでは、キーイベントをハンドリングする際に、controlキーが押されている場合にのみ、制御文字をASCIIアルファベットに変換する処理を行っていましたが、それ以外の場合は素通りしていました。今回、ASCII文字の範囲内にある制御文字が入力された場合には、これを無視するようにしています。CodeInput等で、それ以外の制御文字を入力することは可能なままですが、普通にはあり得ない上に、膨大な調査とコードが必要になるため、それらについては確認しないようにしています。
また、Macでは、PC用のキーボードを接続しても、Macのキーボードにないキーは普通、Aキーと同じ0が仮想キーコードとしてマッピングされ、判別がつかないのですが、アプリケーションキーは固有の数値(0x6E
)にマッピングされているので、他のプラットフォームと同様に、keyCode
や、key
の値を設定するように修正しています。
ただし、他のアプリでも、このキーでコンテキストメニューを開くことはできないので、そのようには今のところは修正していません。
WindowsでwindowlessなFlashにIMEで未確定文字列を入力すると、画面左上に未確定文字列が表示され、視点移動が大きく、非常に見づらい動作でした。これの代表例は、ustreamのチャットの入力欄です。
今回の修正では、未確定文字列をフォーカスを持つプラグインの左下隅を、未確定文字列が表示されるComposition Windowの左上の座標として指定するようにしました。なお、プラグインがスクロールによって、ウインドウ外にある場合は、ウインドウの端に丸め込まれます。
なお、ATOKのみ、未確定文字列の上に、候補ウインドウも重なるという動作になりますが、候補ウインドウ位置を明示的に指定しても動作が変わらなかったので、ATOK側のバグだと思われます。
Android版のnsWindow
がイベントを発行する際に、マウスやタッチイベントでは、一切、モディファイアの情報を設定しておらず、キーイベントでも、Alt、Ctrl、Meta、Shiftしか設定していないというバグです。
今回の修正により、全てのイベントで、CapsLock、NumLock、ScrollLockも設定されるようになりました。Function
というモディファイア状態もFnに反映するように修正していますが、これがどのような場合にアクティブになっているのかは不明です。
ただし、Javascriptから擬似的に生成されている、一文字で確定した場合のキーイベントや、タッチ操作によるマウスイベントは今回の修正では変更されていません。
また、Androidの制約により、AltGrの情報も設定されていません。
より詳しい情報は、MSDNの資料を参考にしてください。
WindowsとMacでは、ネイティブキーイベントをエミュレートして、ネイティブキーイベントのハンドリング処理が行えますが、このAPIが非常に使いにくいため、EventUtils.js
に、synthesizeNativeKey()
ができたことを契機に、パラメータを読みやすいものにし、全てのテストでこのファンクションを使って、APIにアクセスするように修正しました。
これを利用することにより、chrome権限がなくても、ネイティブキーイベントのエミュレーションが手軽にできるようにもなっています。