Bug 1119609 part.5 Compute KeyboardEvent.location and .keyCode if they are 0 r=smaug, sr=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Thu, 19 Feb 2015 15:50:19 +0900
changeset 256959 79a7a9fb13a9aceeebaab24eea9bca5542725a48
parent 256958 4af5d66b1c0bd98d089d4f4ff3b3daa596ce0f37
child 256960 d97c2fcf2bf8155a843123d294a851600e41ea55
push id4610
push userjlund@mozilla.com
push dateMon, 30 Mar 2015 18:32:55 +0000
treeherdermozilla-beta@4df54044d9ef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, smaug
bugs1119609
milestone38.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1119609 part.5 Compute KeyboardEvent.location and .keyCode if they are 0 r=smaug, sr=smaug
dom/base/TextInputProcessor.cpp
dom/base/test/chrome/window_nsITextInputProcessor.xul
dom/interfaces/base/nsITextInputProcessor.idl
widget/TextEvents.h
widget/WidgetEventImpl.cpp
--- a/dom/base/TextInputProcessor.cpp
+++ b/dom/base/TextInputProcessor.cpp
@@ -443,16 +443,48 @@ TextInputProcessor::PrepareKeyboardEvent
       NS_WARN_IF(aKeyboardEvent.mKeyNameIndex == KEY_NAME_INDEX_USE_STRING)) {
     return NS_ERROR_INVALID_ARG;
   }
   if ((aKeyFlags & KEY_FORCE_PRINTABLE_KEY) &&
       aKeyboardEvent.mKeyNameIndex != KEY_NAME_INDEX_USE_STRING) {
     aKeyboardEvent.GetDOMKeyName(aKeyboardEvent.mKeyValue);
     aKeyboardEvent.mKeyNameIndex = KEY_NAME_INDEX_USE_STRING;
   }
+  if (aKeyFlags & KEY_KEEP_KEY_LOCATION_STANDARD) {
+    // If .location is initialized with specific value, using
+    // KEY_KEEP_KEY_LOCATION_STANDARD must be a bug of the caller.
+    // Let's throw an exception for notifying the developer of this bug.
+    if (NS_WARN_IF(aKeyboardEvent.location)) {
+      return NS_ERROR_INVALID_ARG;
+    }
+  } else if (!aKeyboardEvent.location) {
+    // If KeyboardEvent.location is 0, it may be uninitialized.  If so, we
+    // should compute proper location value from its .code value.
+    aKeyboardEvent.location =
+      WidgetKeyboardEvent::ComputeLocationFromCodeValue(
+        aKeyboardEvent.mCodeNameIndex);
+  }
+
+  if (aKeyFlags & KEY_KEEP_KEYCODE_ZERO) {
+    // If .keyCode is initialized with specific value, using
+    // KEY_KEEP_KEYCODE_ZERO must be a bug of the caller.  Let's throw an
+    // exception for notifying the developer of such bug.
+    if (NS_WARN_IF(aKeyboardEvent.keyCode)) {
+      return NS_ERROR_INVALID_ARG;
+    }
+  } else if (!aKeyboardEvent.keyCode &&
+             aKeyboardEvent.mKeyNameIndex > KEY_NAME_INDEX_Unidentified &&
+             aKeyboardEvent.mKeyNameIndex < KEY_NAME_INDEX_USE_STRING) {
+    // If KeyboardEvent.keyCode is 0, it may be uninitialized.  If so, we may
+    // be able to decide a good .keyCode value if the .key value is a
+    // non-printable key.
+    aKeyboardEvent.keyCode =
+      WidgetKeyboardEvent::ComputeKeyCodeFromKeyNameIndex(
+        aKeyboardEvent.mKeyNameIndex);
+  }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TextInputProcessor::Keydown(nsIDOMKeyEvent* aDOMKeyEvent,
                             uint32_t aKeyFlags,
                             uint8_t aOptionalArgc,
                             bool* aDoDefault)
--- a/dom/base/test/chrome/window_nsITextInputProcessor.xul
+++ b/dom/base/test/chrome/window_nsITextInputProcessor.xul
@@ -687,31 +687,31 @@ function runKeyTests()
   reset();
   doDefaultKeydown = TIP.keydown(keyEnter);
 
   ok(doDefaultKeydown,
      description + "TIP.keydown(keyEnter) should return true");
   is(events.length, 2,
      description + "TIP.keydown(keyEnter) should cause keydown and keypress event");
   checkKeyAttrs("TIP.keydown(keyEnter)", events[0],
-                { type: "keydown",  key: "Enter", code: "Enter" });
+                { type: "keydown",  key: "Enter", code: "Enter", keyCode: KeyboardEvent.DOM_VK_RETURN });
   checkKeyAttrs("TIP.keydown(keyEnter)", events[1],
-                { type: "keypress", key: "Enter", code: "Enter" });
+                { type: "keypress", key: "Enter", code: "Enter", keyCode: KeyboardEvent.DOM_VK_RETURN });
   is(input.value, "a",
      description + "input.value should stay \"a\" which was inputted by TIP.keydown(keyA)");
 
   // Emulates releasing Enter key.
   reset();
   doDefaultKeyup = TIP.keyup(keyEnter);
   ok(doDefaultKeyup,
      description + "TIP.keyup(keyEnter) should return true");
   is(events.length, 1,
      description + "TIP.keyup(keyEnter) should cause keyup event");
   checkKeyAttrs("TIP.keyup(keyEnter)", events[0],
-                { type: "keyup",      key: "Enter", code: "Enter" });
+                { type: "keyup",      key: "Enter", code: "Enter", keyCode: KeyboardEvent.DOM_VK_RETURN });
   is(input.value, "a",
      description + "input.value should stay \"a\" which was inputted by TIP.keydown(keyA)");
 
 
   // KEY_DEFAULT_PREVENTED should cause defaultPrevented = true and not cause keypress event
   var keyB = new KeyboardEvent("", { key: "b", code: "KeyB", keyCode: KeyboardEvent.DOM_VK_B });
 
   reset();
@@ -798,21 +798,21 @@ function runKeyTests()
 
   ok(doDefaultKeydown,
      description + "TIP.keydown(keyWithModifiers) should return true");
   ok(doDefaultKeyup,
      description + "TIP.keyup(keyWithModifiers) should return true");
   is(events.length, 3,
      description + "TIP.keydown(keyWithModifiers) and TIP.keyup(keyWithModifiers) should cause keydown, keypress and keyup event");
   checkKeyAttrs("TIP.keydown(keyWithModifiers) and TIP.keyup(keyWithModifiers)", events[0],
-                { type: "keydown",  key: "Escape", code: "Escape" });
+                { type: "keydown",  key: "Escape", code: "Escape", keyCode: KeyboardEvent.DOM_VK_ESCAPE });
   checkKeyAttrs("TIP.keydown(keyWithModifiers) and TIP.keyup(keyWithModifiers)", events[1],
-                { type: "keypress", key: "Escape", code: "Escape" });
+                { type: "keypress", key: "Escape", code: "Escape", keyCode: KeyboardEvent.DOM_VK_ESCAPE });
   checkKeyAttrs("TIP.keydown(keyWithModifiers) and TIP.keyup(keyWithModifiers)", events[2],
-                { type: "keyup",    key: "Escape", code: "Escape" });
+                { type: "keyup",    key: "Escape", code: "Escape", keyCode: KeyboardEvent.DOM_VK_ESCAPE });
   is(input.value, "Enter",
      description + "input.value should stay \"Enter\" which was inputted by TIP.keydown(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY)");
 
   // Call preventDefault() at keydown
   input.value = "";
   reset();
   doPreventDefaults = [ "keydown" ];
   doDefaultKeydown = TIP.keydown(keyA);
@@ -904,16 +904,256 @@ function runKeyTests()
     checkKeyAttrs("TIP.keyup(keyA) during composition", events[0],
                   { type: "keyup",    key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A, charCode: 0, isComposing: true });
 
   } finally {
     TIP.cancelComposition();
     SpecialPowers.clearUserPref("dom.keyboardevent.dispatch_during_composition");
   }
 
+  // Test .location computation
+  const kCodeToLocation = [
+    { code: "BracketLeft",              location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+    { code: "BracketRight",             location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+    { code: "Comma",                    location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+    { code: "Digit0",                   location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+    { code: "Digit1",                   location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+    { code: "Digit2",                   location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+    { code: "Digit3",                   location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+    { code: "Digit4",                   location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+    { code: "Digit5",                   location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+    { code: "Digit6",                   location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+    { code: "Digit7",                   location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+    { code: "Digit8",                   location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+    { code: "Digit9",                   location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+    { code: "Equal",                    location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+    { code: "Minus",                    location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+    { code: "Period",                   location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+    { code: "Slash",                    location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+    { code: "AltLeft",                  location: KeyboardEvent.DOM_KEY_LOCATION_LEFT },
+    { code: "AltRight",                 location: KeyboardEvent.DOM_KEY_LOCATION_RIGHT },
+    { code: "CapsLock",                 location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+    { code: "ContextMenu",              location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+    { code: "ControlLeft",              location: KeyboardEvent.DOM_KEY_LOCATION_LEFT },
+    { code: "ControlRight",             location: KeyboardEvent.DOM_KEY_LOCATION_RIGHT },
+    { code: "Enter",                    location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+    { code: "OSLeft",                   location: KeyboardEvent.DOM_KEY_LOCATION_LEFT },
+    { code: "OSRight",                  location: KeyboardEvent.DOM_KEY_LOCATION_RIGHT },
+    { code: "ShiftLeft",                location: KeyboardEvent.DOM_KEY_LOCATION_LEFT },
+    { code: "ShiftRight",               location: KeyboardEvent.DOM_KEY_LOCATION_RIGHT },
+    { code: "Space",                    location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+    { code: "Tab",                      location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+    { code: "ArrowDown",                location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+    { code: "ArrowLeft",                location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+    { code: "ArrowRight",               location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+    { code: "ArrowUp",                  location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+    { code: "NumLock",                  location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+    { code: "Numpad0",                  location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+    { code: "Numpad1",                  location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+    { code: "Numpad2",                  location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+    { code: "Numpad3",                  location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+    { code: "Numpad4",                  location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+    { code: "Numpad5",                  location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+    { code: "Numpad6",                  location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+    { code: "Numpad7",                  location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+    { code: "Numpad8",                  location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+    { code: "Numpad9",                  location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+    { code: "NumpadAdd",                location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+    { code: "NumpadBackspace",          location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+    // { code: "NumpadClear",              location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+    // { code: "NumpadClearEntry",         location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+    { code: "NumpadComma",              location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+    { code: "NumpadDecimal",            location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+    { code: "NumpadDivide",             location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+    { code: "NumpadEnter",              location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+    { code: "NumpadEqual",              location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+    // { code: "NumpadMemoryAdd",          location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+    // { code: "NumpadMemoryClear",        location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+    // { code: "NumpadMemoryRecall",       location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+    // { code: "NumpadMemoryStore",        location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+    { code: "NumpadMemorySubtract",     location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+    { code: "NumpadMultiply",           location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+    // { code: "NumpadParenLeft",          location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+    // { code: "NumpadParenRight",         location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+    { code: "NumpadSubtract",           location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+  ];
+  for (var i = 0; i < kCodeToLocation.length; i++) {
+    var keyEvent = new KeyboardEvent("", { code: kCodeToLocation[i].code });
+    reset();
+    doPreventDefaults = [ "keypress" ];
+    // If the location isn't initialized or initialized with 0, it should be computed from the code value.
+    TIP.keydown(keyEvent);
+    TIP.keyup(keyEvent);
+    var longDesc = description + "testing computation of .location of \"" + kCodeToLocation[i].code + "\", ";
+    is(events.length, 3,
+       longDesc + "keydown, keypress and keyup events should be fired");
+    for (var j = 0; j < events.length; j++) {
+      is(events[j].location, kCodeToLocation[i].location,
+         longDesc + " type=\"" + events[j].type + "\", location value is wrong");
+    }
+    // However, if KEY_KEEP_KEY_LOCATION_STANDARD is specified, .location value should be kept as DOM_KEY_LOCATION_STANDARD (0).
+    reset();
+    doPreventDefaults = [ "keypress" ];
+    TIP.keydown(keyEvent, TIP.KEY_KEEP_KEY_LOCATION_STANDARD);
+    TIP.keyup(keyEvent, TIP.KEY_KEEP_KEY_LOCATION_STANDARD);
+    var longDesc = description + "testing if .location is forcibly set to DOM_KEY_LOCATION_STANDARD, ";
+    is(events.length, 3,
+       longDesc + "keydown, keypress and keyup events should be fired");
+    for (var j = 0; j < events.length; j++) {
+      is(events[j].location, KeyboardEvent.DOM_KEY_LOCATION_STANDARD,
+         longDesc + " type=\"" + events[j].type + "\", location value is not 0");
+    }
+    // If .location is initialized with non-zero value, the value shouldn't be computed again.
+    var keyEventWithLocation = new KeyboardEvent("", { code: kCodeToLocation[i].code, location: 0xFF });
+    reset();
+    doPreventDefaults = [ "keypress" ];
+    TIP.keydown(keyEventWithLocation);
+    TIP.keyup(keyEventWithLocation);
+    longDesc = description + "testing if .location is not computed for \"" + kCodeToLocation[i].location + "\", ";
+    is(events.length, 3,
+       longDesc + "keydown, keypress and keyup events should be fired");
+    for (var j = 0; j < events.length; j++) {
+      is(events[j].location, 0xFF,
+         longDesc + " type=\"" + events[j].type + "\", location shouldn't be computed if it's initialized with non-zero value");
+    }
+  }
+
+  // Test .keyCode value computation
+  const kKeyToKeyCode = [
+    { key: "Cancel",                    keyCode: KeyboardEvent.DOM_VK_CANCEL },
+    { key: "Help",                      keyCode: KeyboardEvent.DOM_VK_HELP },
+    { key: "Backspace",                 keyCode: KeyboardEvent.DOM_VK_BACK_SPACE },
+    { key: "Tab",                       keyCode: KeyboardEvent.DOM_VK_TAB },
+    { key: "Clear",                     keyCode: KeyboardEvent.DOM_VK_CLEAR },
+    { key: "Enter",                     keyCode: KeyboardEvent.DOM_VK_RETURN },
+    { key: "Shift",                     keyCode: KeyboardEvent.DOM_VK_SHIFT,              isModifier: true },
+    { key: "Control",                   keyCode: KeyboardEvent.DOM_VK_CONTROL,            isModifier: true },
+    { key: "Alt",                       keyCode: KeyboardEvent.DOM_VK_ALT,                isModifier: true },
+    { key: "Pause",                     keyCode: KeyboardEvent.DOM_VK_PAUSE },
+    { key: "CapsLock",                  keyCode: KeyboardEvent.DOM_VK_CAPS_LOCK,          isModifier: true },
+    { key: "Hiragana",                  keyCode: KeyboardEvent.DOM_VK_KANA },
+    { key: "Katakana",                  keyCode: KeyboardEvent.DOM_VK_KANA },
+    { key: "HiraganaKatakana",          keyCode: KeyboardEvent.DOM_VK_KANA },
+    { key: "KanaMode",                  keyCode: KeyboardEvent.DOM_VK_KANA },
+    { key: "HangulMode",                keyCode: KeyboardEvent.DOM_VK_HANGUL },
+    { key: "Eisu",                      keyCode: KeyboardEvent.DOM_VK_EISU },
+    { key: "JunjaMode",                 keyCode: KeyboardEvent.DOM_VK_JUNJA },
+    { key: "FinalMode",                 keyCode: KeyboardEvent.DOM_VK_FINAL },
+    { key: "HanjaMode",                 keyCode: KeyboardEvent.DOM_VK_HANJA },
+    { key: "KanjiMode",                 keyCode: KeyboardEvent.DOM_VK_KANJI },
+    { key: "Escape",                    keyCode: KeyboardEvent.DOM_VK_ESCAPE },
+    { key: "Convert",                   keyCode: KeyboardEvent.DOM_VK_CONVERT },
+    { key: "NonConvert",                keyCode: KeyboardEvent.DOM_VK_NONCONVERT },
+    { key: "Accept",                    keyCode: KeyboardEvent.DOM_VK_ACCEPT },
+    { key: "ModeChange",                keyCode: KeyboardEvent.DOM_VK_MODECHANGE },
+    { key: "PageUp",                    keyCode: KeyboardEvent.DOM_VK_PAGE_UP },
+    { key: "PageDown",                  keyCode: KeyboardEvent.DOM_VK_PAGE_DOWN },
+    { key: "End",                       keyCode: KeyboardEvent.DOM_VK_END },
+    { key: "Home",                      keyCode: KeyboardEvent.DOM_VK_HOME },
+    { key: "ArrowLeft",                 keyCode: KeyboardEvent.DOM_VK_LEFT },
+    { key: "ArrowUp",                   keyCode: KeyboardEvent.DOM_VK_UP },
+    { key: "ArrowRight",                keyCode: KeyboardEvent.DOM_VK_RIGHT },
+    { key: "ArrowDown",                 keyCode: KeyboardEvent.DOM_VK_DOWN },
+    { key: "Select",                    keyCode: KeyboardEvent.DOM_VK_SELECT },
+    { key: "Print",                     keyCode: KeyboardEvent.DOM_VK_PRINT },
+    { key: "Execute",                   keyCode: KeyboardEvent.DOM_VK_EXECUTE },
+    { key: "PrintScreen",               keyCode: KeyboardEvent.DOM_VK_PRINTSCREEN },
+    { key: "Insert",                    keyCode: KeyboardEvent.DOM_VK_INSERT },
+    { key: "Delete",                    keyCode: KeyboardEvent.DOM_VK_DELETE },
+    { key: "OS",                        keyCode: KeyboardEvent.DOM_VK_WIN,                isModifier: true },
+    { key: "ContextMenu",               keyCode: KeyboardEvent.DOM_VK_CONTEXT_MENU },
+    { key: "F1",                        keyCode: KeyboardEvent.DOM_VK_F1 },
+    { key: "F2",                        keyCode: KeyboardEvent.DOM_VK_F2 },
+    { key: "F3",                        keyCode: KeyboardEvent.DOM_VK_F3 },
+    { key: "F4",                        keyCode: KeyboardEvent.DOM_VK_F4 },
+    { key: "F5",                        keyCode: KeyboardEvent.DOM_VK_F5 },
+    { key: "F6",                        keyCode: KeyboardEvent.DOM_VK_F6 },
+    { key: "F7",                        keyCode: KeyboardEvent.DOM_VK_F7 },
+    { key: "F8",                        keyCode: KeyboardEvent.DOM_VK_F8 },
+    { key: "F9",                        keyCode: KeyboardEvent.DOM_VK_F9 },
+    { key: "F10",                       keyCode: KeyboardEvent.DOM_VK_F10 },
+    { key: "F11",                       keyCode: KeyboardEvent.DOM_VK_F11 },
+    { key: "F12",                       keyCode: KeyboardEvent.DOM_VK_F12 },
+    { key: "F13",                       keyCode: KeyboardEvent.DOM_VK_F13 },
+    { key: "F14",                       keyCode: KeyboardEvent.DOM_VK_F14 },
+    { key: "F15",                       keyCode: KeyboardEvent.DOM_VK_F15 },
+    { key: "F16",                       keyCode: KeyboardEvent.DOM_VK_F16 },
+    { key: "F17",                       keyCode: KeyboardEvent.DOM_VK_F17 },
+    { key: "F18",                       keyCode: KeyboardEvent.DOM_VK_F18 },
+    { key: "F19",                       keyCode: KeyboardEvent.DOM_VK_F19 },
+    { key: "F20",                       keyCode: KeyboardEvent.DOM_VK_F20 },
+    { key: "F21",                       keyCode: KeyboardEvent.DOM_VK_F21 },
+    { key: "F22",                       keyCode: KeyboardEvent.DOM_VK_F22 },
+    { key: "F23",                       keyCode: KeyboardEvent.DOM_VK_F23 },
+    { key: "F24",                       keyCode: KeyboardEvent.DOM_VK_F24 },
+    { key: "NumLock",                   keyCode: KeyboardEvent.DOM_VK_NUM_LOCK,           isModifier: true },
+    { key: "ScrollLock",                keyCode: KeyboardEvent.DOM_VK_SCROLL_LOCK,        isModifier: true },
+    { key: "VolumeMute",                keyCode: KeyboardEvent.DOM_VK_VOLUME_MUTE },
+    { key: "VolumeDown",                keyCode: KeyboardEvent.DOM_VK_VOLUME_DOWN },
+    { key: "VolumeUp",                  keyCode: KeyboardEvent.DOM_VK_VOLUME_UP },
+    { key: "Meta",                      keyCode: KeyboardEvent.DOM_VK_META,               isModifier: true },
+    { key: "AltGraph",                  keyCode: KeyboardEvent.DOM_VK_ALTGR,              isModifier: true },
+    { key: "Attn",                      keyCode: KeyboardEvent.DOM_VK_ATTN },
+    { key: "CrSel",                     keyCode: KeyboardEvent.DOM_VK_CRSEL },
+    { key: "ExSel",                     keyCode: KeyboardEvent.DOM_VK_EXSEL },
+    { key: "EraseEof",                  keyCode: KeyboardEvent.DOM_VK_EREOF },
+    { key: "Play",                      keyCode: KeyboardEvent.DOM_VK_PLAY },
+    { key: "ZoomToggle",                keyCode: KeyboardEvent.DOM_VK_ZOOM },
+    { key: "ZoomIn",                    keyCode: KeyboardEvent.DOM_VK_ZOOM },
+    { key: "ZoomOut",                   keyCode: KeyboardEvent.DOM_VK_ZOOM },
+    { key: "Unidentified",              keyCode: 0 },
+    { key: "a",                         keyCode: 0, isPrintable: true },
+    { key: "A",                         keyCode: 0, isPrintable: true },
+    { key: " ",                         keyCode: 0, isPrintable: true },
+    { key: "",                          keyCode: 0, isPrintable: true },
+  ];
+
+  for (var i = 0; i < kKeyToKeyCode.length; i++) {
+    var keyEvent = new KeyboardEvent("", { key: kKeyToKeyCode[i].key });
+    var causeKeypress = !kKeyToKeyCode[i].isModifier;
+    var baseFlags = kKeyToKeyCode[i].isPrintable ? 0 : TIP.KEY_NON_PRINTABLE_KEY;
+    reset();
+    doPreventDefaults = [ "keypress" ];
+    // If the keyCode isn't initialized or initialized with 0, it should be computed from the key value only when it's a printable key.
+    TIP.keydown(keyEvent, baseFlags);
+    TIP.keyup(keyEvent, baseFlags);
+    var longDesc = description + "testing computation of .keyCode of \"" + kKeyToKeyCode[i].key + "\", ";
+    is(events.length, causeKeypress ? 3 : 2,
+       longDesc + "keydown" + (causeKeypress ? ", keypress" : "") + " and keyup events should be fired");
+    for (var j = 0; j < events.length; j++) {
+      is(events[j].keyCode, events[j].type == "keypress" && kKeyToKeyCode[i].isPrintable ? 0 : kKeyToKeyCode[i].keyCode,
+         longDesc + " type=\"" + events[j].type + "\", keyCode value is wrong");
+    }
+    // However, if KEY_KEEP_KEYCODE_ZERO is specified, .keyCode value should be kept as 0.
+    reset();
+    doPreventDefaults = [ "keypress" ];
+    TIP.keydown(keyEvent, TIP.KEY_KEEP_KEYCODE_ZERO | baseFlags);
+    TIP.keyup(keyEvent, TIP.KEY_KEEP_KEYCODE_ZERO | baseFlags);
+    var longDesc = description + "testing if .keyCode is forcibly set to KEY_KEEP_KEYCODE_ZERO, ";
+    is(events.length, causeKeypress ? 3 : 2,
+       longDesc + "keydown" + (causeKeypress ? ", keypress" : "") + " and keyup events should be fired");
+    for (var j = 0; j < events.length; j++) {
+      is(events[j].keyCode, 0,
+         longDesc + " type=\"" + events[j].type + "\", keyCode value is not 0");
+    }
+    // If .keyCode is initialized with non-zero value, the value shouldn't be computed again.
+    var keyEventWithLocation = new KeyboardEvent("", { key: kKeyToKeyCode[i].key, keyCode: 0xFF });
+    reset();
+    doPreventDefaults = [ "keypress" ];
+    TIP.keydown(keyEventWithLocation, baseFlags);
+    TIP.keyup(keyEventWithLocation, baseFlags);
+    longDesc = description + "testing if .keyCode is not computed for \"" + kKeyToKeyCode[i].key + "\", ";
+    is(events.length, causeKeypress ? 3 : 2,
+       longDesc + "keydown" + (causeKeypress ? ", keypress" : "") + " and keyup events should be fired");
+    for (var j = 0; j < events.length; j++) {
+      is(events[j].keyCode, events[j].type == "keypress" && kKeyToKeyCode[i].isPrintable ? 0 : 0xFF,
+         longDesc + " type=\"" + events[j].type + "\", keyCode shouldn't be computed if it's initialized with non-zero value");
+    }
+  }
+
   window.removeEventListener("keydown", handler, false);
   window.removeEventListener("keypress", handler, false);
   window.removeEventListener("keyup", handler, false);
 }
 
 function runErrorTests()
 {
   var description = "runErrorTests(): ";
@@ -1111,16 +1351,56 @@ function runErrorTests()
        description + "TIP.keyup(keyInvalidKey, TIP.KEY_NON_PRINTABLE_KEY) should cause throwing an exception because its key value is not registered");
   } catch (e) {
     ok(e.message.contains("NS_ERROR_ILLEGAL_VALUE"),
        description + "keyup(keyInvalidKey, TIP.KEY_NON_PRINTABLE_KEY) should cause throwing an exception including NS_ERROR_ILLEGAL_VALUE");
   } finally {
     is(input.value, "",
        description + "The input element should not be modified");
   }
+
+  // KEY_KEEP_KEY_LOCATION_STANDARD flag should be used only when .location is not initialized with non-zero value.
+  try {
+    var keyEvent = new KeyboardEvent("", { code: "Enter", location: KeyboardEvent.DOM_KEY_LOCATION_LEFT });
+    TIP.keydown(keyEvent, TIP.KEY_KEEP_KEY_LOCATION_STANDARD);
+    ok(false,
+       description + "keydown(KEY_KEEP_KEY_LOCATION_STANDARD) should fail if the .location of the key event is initialized with non-zero value");
+  } catch (e) {
+    ok(e.message.contains("NS_ERROR_ILLEGAL_VALUE"),
+       description + "keydown(KEY_KEEP_KEY_LOCATION_STANDARD) should cause NS_ERROR_ILLEGAL_VALUE if the .location of the key event is initialized with nonzero value");
+  }
+  try {
+    var keyEvent = new KeyboardEvent("", { code: "Enter", location: KeyboardEvent.DOM_KEY_LOCATION_LEFT });
+    TIP.keyup(keyEvent, TIP.KEY_KEEP_KEY_LOCATION_STANDARD);
+    ok(false,
+       description + "keyup(KEY_KEEP_KEY_LOCATION_STANDARD) should fail if the .location of the key event is initialized with non-zero value");
+  } catch (e) {
+    ok(e.message.contains("NS_ERROR_ILLEGAL_VALUE"),
+       description + "keyup(KEY_KEEP_KEY_LOCATION_STANDARD) should cause NS_ERROR_ILLEGAL_VALUE if the .location of the key event is initialized with nonzero value");
+  }
+
+  // KEY_KEEP_KEYCODE_ZERO flag should be used only when .keyCode is not initialized with non-zero value.
+  try {
+    var keyEvent = new KeyboardEvent("", { key: "Enter", keyCode: KeyboardEvent.DOM_VK_RETURN });
+    TIP.keydown(keyEvent, TIP.KEY_KEEP_KEYCODE_ZERO);
+    ok(false,
+       description + "keydown(KEY_KEEP_KEYCODE_ZERO) should fail if the .keyCode of the key event is initialized with non-zero value");
+  } catch (e) {
+    ok(e.message.contains("NS_ERROR_ILLEGAL_VALUE"),
+       description + "keydown(KEY_KEEP_KEYCODE_ZERO) should cause NS_ERROR_ILLEGAL_VALUE if the .keyCode of the key event is initialized with nonzero value");
+  }
+  try {
+    var keyEvent = new KeyboardEvent("", { key: "Enter", keyCode: KeyboardEvent.DOM_VK_RETURN });
+    TIP.keyup(keyEvent, TIP.KEY_KEEP_KEYCODE_ZERO);
+    ok(false,
+       description + "keyup(KEY_KEEP_KEYCODE_ZERO) should fail if the .keyCode of the key event is initialized with non-zero value");
+  } catch (e) {
+    ok(e.message.contains("NS_ERROR_ILLEGAL_VALUE"),
+       description + "keyup(KEY_KEEP_KEYCODE_ZERO) should cause NS_ERROR_ILLEGAL_VALUE if the .keyCode of the key event is initialized with nonzero value");
+  }
 }
 
 function runCommitCompositionTests()
 {
   var description = "runCommitCompositionTests(): ";
 
   var TIP = createTIP();
   ok(TIP.beginInputTransactionForTests(window),
--- a/dom/interfaces/base/nsITextInputProcessor.idl
+++ b/dom/interfaces/base/nsITextInputProcessor.idl
@@ -194,17 +194,17 @@ interface nsITextInputProcessorCallback;
  *   }
  *
  *   // Even if keydown event was consumed, keyup event should be dispatched.
  *   if (TIP.keyup(keyEvent)) {
  *     // Handle its default action
  *   }
  */
 
-[scriptable, builtinclass, uuid(60371ca6-a8a7-4e24-bf02-e262aa74ba5a)]
+[scriptable, builtinclass, uuid(16144d6e-a97a-4733-aa6a-3a1287cfe539)]
 interface nsITextInputProcessor : nsISupports
 {
   /**
    * When you create an instance, you must call beginInputTransaction() first
    * except when you created the instance for automated tests.
    *
    * @param aWindow         A DOM window.  The instance will look for a top
    *                        level widget from this.
@@ -368,23 +368,44 @@ interface nsITextInputProcessor : nsISup
   // If KEY_NON_PRINTABLE_KEY is specified and the .key value isn't valid
   // key name, the methods will throws an exception.  In other words, this
   // flag prevents to dispatch key events with wrong key values and to cause
   // such key events input the key values as text.
   const unsigned long KEY_NON_PRINTABLE_KEY                        = 0x00000002;
   // If KEY_FORCE_PRINTABLE_KEY is specified and even if the .key value is a
   // registered key name, it's treated as inputting text value.
   const unsigned long KEY_FORCE_PRINTABLE_KEY                      = 0x00000004;
+  // If KEY_KEEP_KEY_LOCATION_STANDARD is specified when its .location is not
+  // initialized or initialized with 0, the value isn't computed with .code
+  // value.  Note that if .location is initialized with non-zero value,
+  // this flag causes throwing an exception.
+  // NOTE: This is not recommended to use except for tests.
+  const unsigned long KEY_KEEP_KEY_LOCATION_STANDARD               = 0x00000008;
+  // If KEY_KEEP_KEYCODE_ZERO is specified when its .keyCode is not initialized
+  // or initialized with 0, the value isn't computed with .key value when it
+  // represents non-printable key.  Note that if .keyCode is initialized with
+  // non-zero value, this flag causes throwing an exception.
+  const unsigned long KEY_KEEP_KEYCODE_ZERO                        = 0x00000010;
 
   /**
    * keydown() may dispatch a keydown event and some keypress events if
    * preceding keydown event isn't consumed and they are necessary.
    * Note that even if this is called during composition, key events may not
    * be dispatched.  In this case, this returns false.
    *
+   * You should initialize at least .key value and .code value of the event.
+   * Additionally, if you try to emulate a printable key, .keyCode value should
+   * be specified if there is proper key value.  See the comment of above
+   * example how to decide .keyCode value of a printable key.  On the other
+   * hand, .keyCode value is automatically computed when you try to emulate
+   * non-printable key.  However, if you try to emulate physical keyboard of
+   * desktop platform, you need to specify proper value explicitly because
+   * the mapping table of this API isn't enough to emulate the behavior of
+   * Gecko for desktop platforms.
+   *
    * NOTE: Even if this has composition, JS-Keyboard should call keydown() and
    *       keyup().  Although, with the default preferences and normal
    *       conditions, DOM key events won't be fired during composition.
    *       However, they MAY be dispatched for some reasons, e.g., the web
    *       content listens only key events, or if the standard DOM event spec
    *       will be changed in the future.
    *
    * @param aKeyboardEvent  Must be a keyboard event which should be dispatched
@@ -392,16 +413,18 @@ interface nsITextInputProcessor : nsISup
    *                        #1 Note that you don't need to set charCode value
    *                        because it's computed from its key value.
    *                        #2 If code value is set properly and location value
    *                        isn't specified (i.e., 0), the location value will
    *                        be guessed from the code value.
    *                        #3 Non-defined code names are not allowed. If your
    *                        key isn't registered, file a bug. If your key isn't
    *                        defined by any standards, use "" (empty string).
+   *                        #4 .keyCode is guessed from .key value if the key
+   *                        name is registered and .keyCode isn't initialized.
    * @param aKeyFlags       Special flags.  The values can be some of KEY_*
    *                        constants.
    * @return                true if neither the keydown event or following
    *                        keypress events is *not* consumed.
    *                        Otherwise, i.e., preventDefault() is called, false.
    */
   [optional_argc]
     boolean keydown(in nsIDOMKeyEvent aKeyboardEvent,
--- a/widget/TextEvents.h
+++ b/widget/TextEvents.h
@@ -185,18 +185,31 @@ public:
       aCodeName = mCodeValue;
       return;
     }
     GetDOMCodeName(mCodeNameIndex, aCodeName);
   }
 
   static void Shutdown();
 
+  /**
+   * ComputeLocationFromCodeValue() returns one of .location value
+   * (nsIDOMKeyEvent::DOM_KEY_LOCATION_*) which is the most preferred value
+   * for the specified specified code value.
+   */
   static uint32_t ComputeLocationFromCodeValue(CodeNameIndex aCodeNameIndex);
 
+  /**
+   * ComputeKeyCodeFromKeyNameIndex() return a .keyCode value which can be
+   * mapped from the specified key value.  Note that this returns 0 if the
+   * key name index is KEY_NAME_INDEX_Unidentified or KEY_NAME_INDEX_USE_STRING.
+   * This means that this method is useful only for non-printable keys.
+   */
+  static uint32_t ComputeKeyCodeFromKeyNameIndex(KeyNameIndex aKeyNameIndex);
+
   static void GetDOMKeyName(KeyNameIndex aKeyNameIndex,
                             nsAString& aKeyName);
   static void GetDOMCodeName(CodeNameIndex aCodeNameIndex,
                              nsAString& aCodeName);
 
   static KeyNameIndex GetKeyNameIndex(const nsAString& aKeyValue);
   static CodeNameIndex GetCodeNameIndex(const nsAString& aCodeValue);
 
--- a/widget/WidgetEventImpl.cpp
+++ b/widget/WidgetEventImpl.cpp
@@ -465,9 +465,179 @@ WidgetKeyboardEvent::ComputeLocationFrom
     // case CODE_NAME_INDEX_NumpadParenRight:
     case CODE_NAME_INDEX_NumpadSubtract:
       return nsIDOMKeyEvent::DOM_KEY_LOCATION_NUMPAD;
     default:
       return nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD;
   }
 }
 
+/* static */ uint32_t
+WidgetKeyboardEvent::ComputeKeyCodeFromKeyNameIndex(KeyNameIndex aKeyNameIndex)
+{
+  switch (aKeyNameIndex) {
+    case KEY_NAME_INDEX_Cancel:
+      return nsIDOMKeyEvent::DOM_VK_CANCEL;
+    case KEY_NAME_INDEX_Help:
+      return nsIDOMKeyEvent::DOM_VK_HELP;
+    case KEY_NAME_INDEX_Backspace:
+      return nsIDOMKeyEvent::DOM_VK_BACK_SPACE;
+    case KEY_NAME_INDEX_Tab:
+      return nsIDOMKeyEvent::DOM_VK_TAB;
+    case KEY_NAME_INDEX_Clear:
+      return nsIDOMKeyEvent::DOM_VK_CLEAR;
+    case KEY_NAME_INDEX_Enter:
+      return nsIDOMKeyEvent::DOM_VK_RETURN;
+    case KEY_NAME_INDEX_Shift:
+      return nsIDOMKeyEvent::DOM_VK_SHIFT;
+    case KEY_NAME_INDEX_Control:
+      return nsIDOMKeyEvent::DOM_VK_CONTROL;
+    case KEY_NAME_INDEX_Alt:
+      return nsIDOMKeyEvent::DOM_VK_ALT;
+    case KEY_NAME_INDEX_Pause:
+      return nsIDOMKeyEvent::DOM_VK_PAUSE;
+    case KEY_NAME_INDEX_CapsLock:
+      return nsIDOMKeyEvent::DOM_VK_CAPS_LOCK;
+    case KEY_NAME_INDEX_Hiragana:
+    case KEY_NAME_INDEX_Katakana:
+    case KEY_NAME_INDEX_HiraganaKatakana:
+    case KEY_NAME_INDEX_KanaMode:
+      return nsIDOMKeyEvent::DOM_VK_KANA;
+    case KEY_NAME_INDEX_HangulMode:
+      return nsIDOMKeyEvent::DOM_VK_HANGUL;
+    case KEY_NAME_INDEX_Eisu:
+      return nsIDOMKeyEvent::DOM_VK_EISU;
+    case KEY_NAME_INDEX_JunjaMode:
+      return nsIDOMKeyEvent::DOM_VK_JUNJA;
+    case KEY_NAME_INDEX_FinalMode:
+      return nsIDOMKeyEvent::DOM_VK_FINAL;
+    case KEY_NAME_INDEX_HanjaMode:
+      return nsIDOMKeyEvent::DOM_VK_HANJA;
+    case KEY_NAME_INDEX_KanjiMode:
+      return nsIDOMKeyEvent::DOM_VK_KANJI;
+    case KEY_NAME_INDEX_Escape:
+      return nsIDOMKeyEvent::DOM_VK_ESCAPE;
+    case KEY_NAME_INDEX_Convert:
+      return nsIDOMKeyEvent::DOM_VK_CONVERT;
+    case KEY_NAME_INDEX_NonConvert:
+      return nsIDOMKeyEvent::DOM_VK_NONCONVERT;
+    case KEY_NAME_INDEX_Accept:
+      return nsIDOMKeyEvent::DOM_VK_ACCEPT;
+    case KEY_NAME_INDEX_ModeChange:
+      return nsIDOMKeyEvent::DOM_VK_MODECHANGE;
+    case KEY_NAME_INDEX_PageUp:
+      return nsIDOMKeyEvent::DOM_VK_PAGE_UP;
+    case KEY_NAME_INDEX_PageDown:
+      return nsIDOMKeyEvent::DOM_VK_PAGE_DOWN;
+    case KEY_NAME_INDEX_End:
+      return nsIDOMKeyEvent::DOM_VK_END;
+    case KEY_NAME_INDEX_Home:
+      return nsIDOMKeyEvent::DOM_VK_HOME;
+    case KEY_NAME_INDEX_ArrowLeft:
+      return nsIDOMKeyEvent::DOM_VK_LEFT;
+    case KEY_NAME_INDEX_ArrowUp:
+      return nsIDOMKeyEvent::DOM_VK_UP;
+    case KEY_NAME_INDEX_ArrowRight:
+      return nsIDOMKeyEvent::DOM_VK_RIGHT;
+    case KEY_NAME_INDEX_ArrowDown:
+      return nsIDOMKeyEvent::DOM_VK_DOWN;
+    case KEY_NAME_INDEX_Select:
+      return nsIDOMKeyEvent::DOM_VK_SELECT;
+    case KEY_NAME_INDEX_Print:
+      return nsIDOMKeyEvent::DOM_VK_PRINT;
+    case KEY_NAME_INDEX_Execute:
+      return nsIDOMKeyEvent::DOM_VK_EXECUTE;
+    case KEY_NAME_INDEX_PrintScreen:
+      return nsIDOMKeyEvent::DOM_VK_PRINTSCREEN;
+    case KEY_NAME_INDEX_Insert:
+      return nsIDOMKeyEvent::DOM_VK_INSERT;
+    case KEY_NAME_INDEX_Delete:
+      return nsIDOMKeyEvent::DOM_VK_DELETE;
+    case KEY_NAME_INDEX_OS:
+    // case KEY_NAME_INDEX_Super:
+    // case KEY_NAME_INDEX_Hyper:
+      return nsIDOMKeyEvent::DOM_VK_WIN;
+    case KEY_NAME_INDEX_ContextMenu:
+      return nsIDOMKeyEvent::DOM_VK_CONTEXT_MENU;
+    case KEY_NAME_INDEX_Standby:
+      return nsIDOMKeyEvent::DOM_VK_SLEEP;
+    case KEY_NAME_INDEX_F1:
+      return nsIDOMKeyEvent::DOM_VK_F1;
+    case KEY_NAME_INDEX_F2:
+      return nsIDOMKeyEvent::DOM_VK_F2;
+    case KEY_NAME_INDEX_F3:
+      return nsIDOMKeyEvent::DOM_VK_F3;
+    case KEY_NAME_INDEX_F4:
+      return nsIDOMKeyEvent::DOM_VK_F4;
+    case KEY_NAME_INDEX_F5:
+      return nsIDOMKeyEvent::DOM_VK_F5;
+    case KEY_NAME_INDEX_F6:
+      return nsIDOMKeyEvent::DOM_VK_F6;
+    case KEY_NAME_INDEX_F7:
+      return nsIDOMKeyEvent::DOM_VK_F7;
+    case KEY_NAME_INDEX_F8:
+      return nsIDOMKeyEvent::DOM_VK_F8;
+    case KEY_NAME_INDEX_F9:
+      return nsIDOMKeyEvent::DOM_VK_F9;
+    case KEY_NAME_INDEX_F10:
+      return nsIDOMKeyEvent::DOM_VK_F10;
+    case KEY_NAME_INDEX_F11:
+      return nsIDOMKeyEvent::DOM_VK_F11;
+    case KEY_NAME_INDEX_F12:
+      return nsIDOMKeyEvent::DOM_VK_F12;
+    case KEY_NAME_INDEX_F13:
+      return nsIDOMKeyEvent::DOM_VK_F13;
+    case KEY_NAME_INDEX_F14:
+      return nsIDOMKeyEvent::DOM_VK_F14;
+    case KEY_NAME_INDEX_F15:
+      return nsIDOMKeyEvent::DOM_VK_F15;
+    case KEY_NAME_INDEX_F16:
+      return nsIDOMKeyEvent::DOM_VK_F16;
+    case KEY_NAME_INDEX_F17:
+      return nsIDOMKeyEvent::DOM_VK_F17;
+    case KEY_NAME_INDEX_F18:
+      return nsIDOMKeyEvent::DOM_VK_F18;
+    case KEY_NAME_INDEX_F19:
+      return nsIDOMKeyEvent::DOM_VK_F19;
+    case KEY_NAME_INDEX_F20:
+      return nsIDOMKeyEvent::DOM_VK_F20;
+    case KEY_NAME_INDEX_F21:
+      return nsIDOMKeyEvent::DOM_VK_F21;
+    case KEY_NAME_INDEX_F22:
+      return nsIDOMKeyEvent::DOM_VK_F22;
+    case KEY_NAME_INDEX_F23:
+      return nsIDOMKeyEvent::DOM_VK_F23;
+    case KEY_NAME_INDEX_F24:
+      return nsIDOMKeyEvent::DOM_VK_F24;
+    case KEY_NAME_INDEX_NumLock:
+      return nsIDOMKeyEvent::DOM_VK_NUM_LOCK;
+    case KEY_NAME_INDEX_ScrollLock:
+      return nsIDOMKeyEvent::DOM_VK_SCROLL_LOCK;
+    case KEY_NAME_INDEX_VolumeMute:
+      return nsIDOMKeyEvent::DOM_VK_VOLUME_MUTE;
+    case KEY_NAME_INDEX_VolumeDown:
+      return nsIDOMKeyEvent::DOM_VK_VOLUME_DOWN;
+    case KEY_NAME_INDEX_VolumeUp:
+      return nsIDOMKeyEvent::DOM_VK_VOLUME_UP;
+    case KEY_NAME_INDEX_Meta:
+      return nsIDOMKeyEvent::DOM_VK_META;
+    case KEY_NAME_INDEX_AltGraph:
+      return nsIDOMKeyEvent::DOM_VK_ALTGR;
+    case KEY_NAME_INDEX_Attn:
+      return nsIDOMKeyEvent::DOM_VK_ATTN;
+    case KEY_NAME_INDEX_CrSel:
+      return nsIDOMKeyEvent::DOM_VK_CRSEL;
+    case KEY_NAME_INDEX_ExSel:
+      return nsIDOMKeyEvent::DOM_VK_EXSEL;
+    case KEY_NAME_INDEX_EraseEof:
+      return nsIDOMKeyEvent::DOM_VK_EREOF;
+    case KEY_NAME_INDEX_Play:
+      return nsIDOMKeyEvent::DOM_VK_PLAY;
+    case KEY_NAME_INDEX_ZoomToggle:
+    case KEY_NAME_INDEX_ZoomIn:
+    case KEY_NAME_INDEX_ZoomOut:
+      return nsIDOMKeyEvent::DOM_VK_ZOOM;
+    default:
+      return 0;
+  }
+}
+
 } // namespace mozilla