Bug 1119609 part.5 Compute KeyboardEvent.location and .keyCode if they are 0 r=smaug, sr=smaug

This commit is contained in:
Masayuki Nakano 2015-02-19 15:50:19 +09:00
parent b6df689270
commit a05a4768db
5 changed files with 525 additions and 7 deletions

View File

@ -448,6 +448,38 @@ TextInputProcessor::PrepareKeyboardEventToDispatch(
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;
}

View File

@ -692,9 +692,9 @@ function runKeyTests()
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)");
@ -706,7 +706,7 @@ function runKeyTests()
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)");
@ -803,11 +803,11 @@ function runKeyTests()
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)");
@ -909,6 +909,246 @@ function runKeyTests()
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);
@ -1116,6 +1356,46 @@ function runErrorTests()
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()

View File

@ -199,7 +199,7 @@ interface nsITextInputProcessorCallback;
* }
*/
[scriptable, builtinclass, uuid(60371ca6-a8a7-4e24-bf02-e262aa74ba5a)]
[scriptable, builtinclass, uuid(16144d6e-a97a-4733-aa6a-3a1287cfe539)]
interface nsITextInputProcessor : nsISupports
{
/**
@ -373,6 +373,17 @@ interface nsITextInputProcessor : nsISupports
// 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
@ -380,6 +391,16 @@ interface nsITextInputProcessor : nsISupports
* 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.
@ -397,6 +418,8 @@ interface nsITextInputProcessor : nsISupports
* #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

View File

@ -190,8 +190,21 @@ public:
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,

View File

@ -470,4 +470,174 @@ WidgetKeyboardEvent::ComputeLocationFromCodeValue(CodeNameIndex aCodeNameIndex)
}
}
/* 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