D3Eで定義された、KeyboardEvent
のコンストラクタを実装しよう、というバグです。
このバグの修正により、コンストラクタを利用して、全ての属性を初期化しつつ、untrustedイベントを生成することができます。
var keydown =
new KeyboardEvent("keydown", { bubbles: true, cancelable: true,
view: window, detail: 0,
keyCode: 65, charCode: 0, which: 65,
key: "a", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD };
var keypress =
new KeyboardEvent("keypress", { bubbles: true, cancelable: true,
view: window, detail: 0,
keyCode: 0, charCode: 97, which: 97,
key: "a", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD };
var keyup =
new KeyboardEvent("keyup", { bubbles: true, cancelable: true,
view: window, detail: 0,
keyCode: 65, charCode: 0, which: 65,
key: "a", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD };
例えば、この例では、Geckoのaキーを押した時と同じイベントを生成しています。これを利用して、エディタ等を更新することはできませんが、Webアプリのイベントハンドラの自動テストには使いやすいかと思います。
なお、あわせて、このバグの修正時に、D3Eで定義されている、KeyboardEvent.initKeyboardEvent()
も一応、実装しておきました。これの実装義務はもはや無いので、あくまでも、IE向けのコードとの互換性のためでしかありません。ですが、このメソッドはブラウザ毎に仕様が異なっているので要注意です。ちなみに、Geckoには昔から、KeyEvent.initKeyEvent()
というメソッドも存在していますので、あわせて紹介しておきましょう。
ブラウザ | 実装しているメソッド |
DOM Level 3 Events |
void initKeyboardEvent(DOMString typeArg,
boolean canBubbleArg,
boolean cancelableArg,
window? viewArg,
long detailArg,
DOMString keyArg,
unsigned long locationArg,
DOMString modifiersListArg,
boolean repeatArg)
|
Gecko |
void initKeyEvent(DOMString typeArg,
boolean canBubbleArg,
boolean cancelableArg,
window? viewArg,
boolean ctrlKeyArg,
boolean altKeyArg,
boolean shiftKeyArg,
boolean metaKeyArg,
unsigned long keyCodeArg,
unsigned long charCodeArg)
|
void initKeyboardEvent(DOMString typeArg,
boolean canBubbleArg,
boolean cancelableArg,
window? viewArg,
long detailArg,
DOMString keyArg,
unsigned long locationArg,
DOMString modifiersListArg,
boolean repeatArg)
|
IE |
void initKeyboardEvent(DOMString typeArg,
boolean canBubbleArg,
boolean cancelableArg,
window? viewArg,
long detailArg,
DOMString keyArg,
unsigned long locationArg,
DOMString modifiersListArg,
boolean repeatArg,
DOMString localeArg)
|
Blink |
void initKeyboardEvent(DOMString typeArg,
boolean canBubbleArg,
boolean cancelableArg,
window? viewArg,
DOMString keyIdentifierArg,
boolean ctrlKeyArg,
boolean altKeyArg,
boolean shiftKeyArg,
boolean metaKeyArg,
boolean altGraphKeyArg)
|
WebKit |
このように、互換性は最悪な状況です。IEは、D3Eにかつて存在していた、locale
属性を初期化する引数が、現在の標準仕様の最後に追加されている形になっています。この引数を指定した場合でも、Geckoでは、エラーなく動くことは確認済みで、自動テストにも含めていますので、IE向けのコードはGeckoでそのまま動きます。ただし、Geckoはlocale
属性をサポートしていませんので、この引数は無視されます。
Blink/WebKitでは、過去の仕様案に従っているのか、現在からは考えられないような引数構成になっています。detail
属性は初期化できない上、key
属性ではなく、独自のkeyIdentifier
属性を初期化する引数があり、さらに、AltGrキーの状態を指定する引数が最後にあります。
幸い、Blinkでは、コンストラクタをサポートしていることを確認していますので、コンストラクタが存在しない場合に、try-catchを利用して、フォールバックしていく以外に、スマートなやり方はなさそうです。
最後に、keyCode
、charCode
、which
属性の値について、注意があるので書いておきます。
これらのレガシー属性は、Blinkのコンストラクタを利用しても初期化できないことは確認しています。つまり、今のところ、これらの属性値を初期化できるのは、Geckoのみということになります。
ですが、Geckoにも少し、癖があります。まず、コンストラクタで初期化した場合、初期化時に指定した値がそのままセットされます。未指定時には初期値の0になります。
それに対し、initKeyEvent
で初期化した場合、keyCode
属性は、イベントのtype
属性値が、keydown
もしくはkeyup
でない場合、無視され、0がセットされます。ただし、keypress
の場合は、charCode
がゼロの場合のみ、無視されません。
同様に、initKeyEvent
で初期化した場合、charCode
属性は、イベントのtype
属性値が、keypress
以外の場合、無視され、0がセットされます。
initKeyEvent
で初期化した場合、which
属性値は直接初期化できませんが、keyCode
属性値、もしくは、charCode
属性値と同じものがセットされます。type
属性値が、keydown
、もしくは、keyup
の場合は、keyCode
属性値がセットされ、keypress
の場合は、keyCode
値が、DOM_VK_RETURN
(0x0D
)、もしくは、DOM_VK_BACK_SPACE
(0x08
)の場合は、keyCode
属性値がセットされ、それ以外の場合は、charCode
属性値がセットされます。type
属性値がこれらのいずれでもない場合は、常に0となります。
initKeyEvent()
で初期化した場合の挙動は、trustedイベントの挙動と全く同じものなので、この様に、複雑なものとなっています。今回の修正で単純化も考えましたが、そもそも、このようなレガシーなメソッドを利用しているコードの互換性を壊すのも意味が無いことなので、コンストラクタでの初期化時のみ、その動作を単純化しています。
KeyboardEvent.initKeyboardEvent()
の実装は取りやめになりました。IEのものと互換性が無いことが分かったため、feature detectionを完全に壊してしまうことがその理由です。GeckoとIEでは、コンストラクタを利用し、WebKitとBlinkでは、非標準のinitKeyboardEvent()
を利用するようにしてください。