Bug 1119609 part.13 EventUtils.synthesizeComposition() and synthesizeCompositionChange() should take KeyboardEvent for emulating composition state change caused by a key operation rs=smaug

This commit is contained in:
Masayuki Nakano 2015-02-19 15:50:20 +09:00
parent 60d702a190
commit d837b657fd
4 changed files with 413 additions and 88 deletions

View File

@ -565,34 +565,28 @@ function synthesizeKey(aKey, aEvent, aWindow)
{
var utils = _getDOMWindowUtils(aWindow);
if (utils) {
var keyCode = 0, charCode = 0;
if (aKey.indexOf("VK_") == 0) {
keyCode = KeyEvent["DOM_" + aKey];
if (!keyCode) {
throw "Unknown key: " + aKey;
}
} else {
charCode = aKey.charCodeAt(0);
keyCode = _computeKeyCodeFromChar(aKey.charAt(0));
}
var keyEventDict = _createKeyboardEventDictionary(aKey, aEvent);
var keyCode = keyEventDict.dictionary.keyCode;
var charCode =
(aKey.indexOf("VK_") == 0) ?
0 : ((keyEventDict.dictionary.key != "") ?
keyEventDict.dictionary.key.charCodeAt(0) : 0);
var modifiers = _parseModifiers(aEvent);
var flags = 0;
if (aEvent.location != undefined) {
switch (aEvent.location) {
case KeyboardEvent.DOM_KEY_LOCATION_STANDARD:
flags |= utils.KEY_FLAG_LOCATION_STANDARD;
break;
case KeyboardEvent.DOM_KEY_LOCATION_LEFT:
flags |= utils.KEY_FLAG_LOCATION_LEFT;
break;
case KeyboardEvent.DOM_KEY_LOCATION_RIGHT:
flags |= utils.KEY_FLAG_LOCATION_RIGHT;
break;
case KeyboardEvent.DOM_KEY_LOCATION_NUMPAD:
flags |= utils.KEY_FLAG_LOCATION_NUMPAD;
break;
}
switch (keyEventDict.dictionary.location) {
case KeyboardEvent.DOM_KEY_LOCATION_STANDARD:
flags |= utils.KEY_FLAG_LOCATION_STANDARD;
break;
case KeyboardEvent.DOM_KEY_LOCATION_LEFT:
flags |= utils.KEY_FLAG_LOCATION_LEFT;
break;
case KeyboardEvent.DOM_KEY_LOCATION_RIGHT:
flags |= utils.KEY_FLAG_LOCATION_RIGHT;
break;
case KeyboardEvent.DOM_KEY_LOCATION_NUMPAD:
flags |= utils.KEY_FLAG_LOCATION_NUMPAD;
break;
}
if (!("type" in aEvent) || !aEvent.type) {
@ -897,6 +891,279 @@ function _getTIP(aWindow, aCallback)
return tip;
}
function _guessKeyNameFromKeyCode(aKeyCode)
{
switch (aKeyCode) {
case KeyboardEvent.DOM_VK_CANCEL:
return "Cancel";
case KeyboardEvent.DOM_VK_HELP:
return "Help";
case KeyboardEvent.DOM_VK_BACK_SPACE:
return "Backspace";
case KeyboardEvent.DOM_VK_TAB:
return "Tab";
case KeyboardEvent.DOM_VK_CLEAR:
return "Clear";
case KeyboardEvent.DOM_VK_RETURN:
return "Enter";
case KeyboardEvent.DOM_VK_SHIFT:
return "Shift";
case KeyboardEvent.DOM_VK_CONTROL:
return "Control";
case KeyboardEvent.DOM_VK_ALT:
return "Alt";
case KeyboardEvent.DOM_VK_PAUSE:
return "Pause";
case KeyboardEvent.DOM_VK_EISU:
return "Eisu";
case KeyboardEvent.DOM_VK_ESCAPE:
return "Escape";
case KeyboardEvent.DOM_VK_CONVERT:
return "Convert";
case KeyboardEvent.DOM_VK_NONCONVERT:
return "NonConvert";
case KeyboardEvent.DOM_VK_ACCEPT:
return "Accept";
case KeyboardEvent.DOM_VK_MODECHANGE:
return "ModeChange";
case KeyboardEvent.DOM_VK_PAGE_UP:
return "PageUp";
case KeyboardEvent.DOM_VK_PAGE_DOWN:
return "PageDown";
case KeyboardEvent.DOM_VK_END:
return "End";
case KeyboardEvent.DOM_VK_HOME:
return "Home";
case KeyboardEvent.DOM_VK_LEFT:
return "ArrowLeft";
case KeyboardEvent.DOM_VK_UP:
return "ArrowUp";
case KeyboardEvent.DOM_VK_RIGHT:
return "ArrowRight";
case KeyboardEvent.DOM_VK_DOWN:
return "ArrowDown";
case KeyboardEvent.DOM_VK_SELECT:
return "Select";
case KeyboardEvent.DOM_VK_PRINT:
return "Print";
case KeyboardEvent.DOM_VK_EXECUTE:
return "Execute";
case KeyboardEvent.DOM_VK_PRINTSCREEN:
return "PrintScreen";
case KeyboardEvent.DOM_VK_INSERT:
return "Insert";
case KeyboardEvent.DOM_VK_DELETE:
return "Delete";
case KeyboardEvent.DOM_VK_WIN:
return "OS";
case KeyboardEvent.DOM_VK_CONTEXT_MENU:
return "ContextMenu";
case KeyboardEvent.DOM_VK_SLEEP:
return "Standby";
case KeyboardEvent.DOM_VK_F1:
return "F1";
case KeyboardEvent.DOM_VK_F2:
return "F2";
case KeyboardEvent.DOM_VK_F3:
return "F3";
case KeyboardEvent.DOM_VK_F4:
return "F4";
case KeyboardEvent.DOM_VK_F5:
return "F5";
case KeyboardEvent.DOM_VK_F6:
return "F6";
case KeyboardEvent.DOM_VK_F7:
return "F7";
case KeyboardEvent.DOM_VK_F8:
return "F8";
case KeyboardEvent.DOM_VK_F9:
return "F9";
case KeyboardEvent.DOM_VK_F10:
return "F10";
case KeyboardEvent.DOM_VK_F11:
return "F11";
case KeyboardEvent.DOM_VK_F12:
return "F12";
case KeyboardEvent.DOM_VK_F13:
return "F13";
case KeyboardEvent.DOM_VK_F14:
return "F14";
case KeyboardEvent.DOM_VK_F15:
return "F15";
case KeyboardEvent.DOM_VK_F16:
return "F16";
case KeyboardEvent.DOM_VK_F17:
return "F17";
case KeyboardEvent.DOM_VK_F18:
return "F18";
case KeyboardEvent.DOM_VK_F19:
return "F19";
case KeyboardEvent.DOM_VK_F20:
return "F20";
case KeyboardEvent.DOM_VK_F21:
return "F21";
case KeyboardEvent.DOM_VK_F22:
return "F22";
case KeyboardEvent.DOM_VK_F23:
return "F23";
case KeyboardEvent.DOM_VK_F24:
return "F24";
case KeyboardEvent.DOM_VK_NUM_LOCK:
return "NumLock";
case KeyboardEvent.DOM_VK_SCROLL_LOCK:
return "ScrollLock";
case KeyboardEvent.DOM_VK_VOLUME_MUTE:
return "VolumeMute";
case KeyboardEvent.DOM_VK_VOLUME_DOWN:
return "VolumeDown";
case KeyboardEvent.DOM_VK_VOLUME_UP:
return "VolumeUp";
case KeyboardEvent.DOM_VK_META:
return "Meta";
case KeyboardEvent.DOM_VK_ALTGR:
return "AltGraph";
case KeyboardEvent.DOM_VK_ATTN:
return "Attn";
case KeyboardEvent.DOM_VK_CRSEL:
return "CrSel";
case KeyboardEvent.DOM_VK_EXSEL:
return "ExSel";
case KeyboardEvent.DOM_VK_EREOF:
return "EraseEof";
case KeyboardEvent.DOM_VK_PLAY:
return "Play";
default:
return "Unidentified";
}
}
function _createKeyboardEventDictionary(aKey, aKeyEvent)
{
var result = { dictionary: null, flags: 0 };
var keyCodeIsDefined = "keyCode" in aKeyEvent;
var keyCode =
(keyCodeIsDefined && aKeyEvent.keyCode >= 0 && aKeyEvent.keyCode <= 255) ?
aKeyEvent.keyCode : 0;
var keyName = "Unidentified";
if (aKey.indexOf("KEY_") == 0) {
keyName = aKey.substr("KEY_".length);
result.flags |= _EU_Ci.nsITextInputProcessor.KEY_NON_PRINTABLE_KEY;
} else if (aKey.indexOf("VK_") == 0) {
keyCode = KeyEvent["DOM_" + aKey];
if (!keyCode) {
throw "Unknown key: " + aKey;
}
keyName = _guessKeyNameFromKeyCode(keyCode);
result.flags |= _EU_Ci.nsITextInputProcessor.KEY_NON_PRINTABLE_KEY;
} else if (aKey != "") {
keyName = aKey;
if (!keyCodeIsDefined) {
keyCode = _computeKeyCodeFromChar(aKey.charAt(0));
}
if (!keyCode) {
result.flags |= _EU_Ci.nsITextInputProcessor.KEY_KEEP_KEYCODE_ZERO;
}
result.flags |= _EU_Ci.nsITextInputProcessor.KEY_FORCE_PRINTABLE_KEY;
}
var locationIsDefined = "location" in aKeyEvent;
if (locationIsDefined && aKeyEvent.location === 0) {
result.flags |= _EU_Ci.nsITextInputProcessor.KEY_KEEP_KEY_LOCATION_STANDARD;
}
result.dictionary = {
key: keyName,
code: "code" in aKeyEvent ? aKeyEvent.code : "",
location: locationIsDefined ? aKeyEvent.location : 0,
repeat: "repeat" in aKeyEvent ? aKeyEvent.repeat : false,
keyCode: keyCode,
};
return result;
}
function _emulateToActivateModifiers(aTIP, aKeyEvent)
{
if (!aKeyEvent) {
return null;
}
var modifiers = {
normal: [
{ key: "Alt", attr: "altKey" },
{ key: "AltGraph", attr: "altGraphKey" },
{ key: "Control", attr: "ctrlKey" },
{ key: "Fn", attr: "fnKey" },
{ key: "Meta", attr: "metaKey" },
{ key: "OS", attr: "osKey" },
{ key: "Shift", attr: "shiftKey" },
{ key: "Symbol", attr: "symbolKey" },
{ key: (navigator.platform.indexOf("Mac") >= 0) ? "Meta" : "Control",
attr: "accelKey" },
],
lockable: [
{ key: "CapsLock", attr: "capsLockKey" },
{ key: "FnLock", attr: "fnLockKey" },
{ key: "NumLock", attr: "numLockKey" },
{ key: "ScrollLock", attr: "scrollLockKey" },
{ key: "SymbolLock", attr: "symbolLockKey" },
]
}
for (var i = 0; i < modifiers.normal.length; i++) {
if (!aKeyEvent[modifiers.normal[i].attr]) {
continue;
}
if (aTIP.getModifierState(modifiers.normal[i].key)) {
continue; // already activated.
}
var event = new KeyboardEvent("", { key: modifiers.normal[i].key });
aTIP.keydown(event,
aTIP.KEY_NON_PRINTABLE_KEY | aTIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT);
modifiers.normal[i].activated = true;
}
for (var i = 0; i < modifiers.lockable.length; i++) {
if (!aKeyEvent[modifiers.lockable[i].attr]) {
continue;
}
if (aTIP.getModifierState(modifiers.lockable[i].key)) {
continue; // already activated.
}
var event = new KeyboardEvent("", { key: modifiers.lockable[i].key });
aTIP.keydown(event,
aTIP.KEY_NON_PRINTABLE_KEY | aTIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT);
aTIP.keyup(event,
aTIP.KEY_NON_PRINTABLE_KEY | aTIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT);
modifiers.lockable[i].activated = true;
}
return modifiers;
}
function _emulateToInactivateModifiers(aTIP, aModifiers)
{
if (!aModifiers) {
return;
}
for (var i = 0; i < aModifiers.normal.length; i++) {
if (!aModifiers.normal[i].activated) {
continue;
}
var event = new KeyboardEvent("", { key: aModifiers.normal[i].key });
aTIP.keyup(event,
aTIP.KEY_NON_PRINTABLE_KEY | aTIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT);
}
for (var i = 0; i < aModifiers.lockable.length; i++) {
if (!aModifiers.lockable[i].activated) {
continue;
}
if (!aTIP.getModifierState(aModifiers.lockable[i].key)) {
continue; // who already inactivated this?
}
var event = new KeyboardEvent("", { key: aModifiers.lockable[i].key });
aTIP.keydown(event,
aTIP.KEY_NON_PRINTABLE_KEY | aTIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT);
aTIP.keyup(event,
aTIP.KEY_NON_PRINTABLE_KEY | aTIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT);
}
}
/**
* Synthesize a composition event.
*
@ -909,6 +1176,11 @@ function _getTIP(aWindow, aCallback)
* the composition event. Note that the |data| is
* ignored if the event type is "compositionstart"
* or "compositioncommitasis".
* If |key| is specified, the key event may be
* dispatched. This can emulates changing
* composition state caused by key operation.
* Its key value should start with "KEY_" if the
* value is non-printable key name defined in D3E.
* @param aWindow Optional (If null, current |window| will be used)
* @param aCallback Optional (If non-null, use the callback for
* receiving notifications to IME)
@ -919,15 +1191,32 @@ function synthesizeComposition(aEvent, aWindow, aCallback)
if (!TIP) {
return false;
}
switch (aEvent.type) {
case "compositionstart":
return TIP.startComposition();
case "compositioncommitasis":
return TIP.commitComposition();
case "compositioncommit":
return TIP.commitComposition(null, 0, aEvent.data);
default:
return false;
var modifiers = _emulateToActivateModifiers(TIP, aEvent.key);
var ret = false;
var keyEventDict =
"key" in aEvent ?
_createKeyboardEventDictionary(aEvent.key.key, aEvent.key) :
{ dictionary: null, flags: 0 };
var keyEvent =
"key" in aEvent ?
new KeyboardEvent(aEvent.type === "keydown" ? "keydown" : "",
keyEventDict.dictionary) :
null;
try {
switch (aEvent.type) {
case "compositionstart":
ret = TIP.startComposition(keyEvent, keyEventDict.flags);
break;
case "compositioncommitasis":
ret = TIP.commitComposition(keyEvent, keyEventDict.flags);
break;
case "compositioncommit":
ret = TIP.commitComposition(keyEvent, keyEventDict.flags,
aEvent.data);
break;
}
} finally {
_emulateToInactivateModifiers(TIP, modifiers);
}
}
/**
@ -947,8 +1236,9 @@ function synthesizeComposition(aEvent, aWindow, aCallback)
* | +-- length
* | +-- attr
* +-- caret
* +-- start
* +-- length
* | +-- start
* | +-- length
* +-- key
*
* Set the composition string to |composition.string|. Set its
* clauses information to the |clauses| array.
@ -969,6 +1259,11 @@ function synthesizeComposition(aEvent, aWindow, aCallback)
* caret. However, current nsEditor doesn't support wide
* caret, therefore, you should always set 0 now.
*
* If |key| is specified, the key event may be dispatched.
* This can emulates changing composition state caused by key
* operation. Its key value should start with "KEY_" if the
* value is non-printable key name defined in D3E.
*
* @param aWindow Optional (If null, current |window| will be used)
* @param aCallback Optional (If non-null, use the callback for receiving
* notifications to IME)
@ -1011,7 +1306,21 @@ function synthesizeCompositionChange(aEvent, aWindow, aCallback)
TIP.setCaretInPendingComposition(aEvent.caret.start);
}
TIP.flushPendingComposition();
var modifiers = _emulateToActivateModifiers(TIP, aEvent.key);
try {
var keyEventDict =
"key" in aEvent ?
_createKeyboardEventDictionary(aEvent.key.key, aEvent.key) :
{ dictionary: null, flags: 0 };
var keyEvent =
"key" in aEvent ?
new KeyboardEvent(aEvent.type === "keydown" ? "keydown" : "",
keyEventDict.dictionary) :
null;
TIP.flushPendingComposition(keyEvent, keyEventDict.flags);
} finally {
_emulateToInactivateModifiers(TIP, modifiers);
}
}
// Must be synchronized with nsIDOMWindowUtils.

View File

@ -86,7 +86,6 @@ nsDoTestsForAutoCompleteWithComposition.prototype = {
{ description: "compositionstart shouldn't open the popup",
completeDefaultIndex: false,
execute: function (aWindow) {
synthesizeKey("m", { type: "keydown", shiftKey: true }, aWindow);
synthesizeCompositionChange(
{ "composition":
{ "string": "M",
@ -95,7 +94,9 @@ nsDoTestsForAutoCompleteWithComposition.prototype = {
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 1, "length": 0 }
"caret": { "start": 1, "length": 0 },
"key": { key: "M", code: "KeyM", keyCode: KeyboardEvent.DOM_VK_M,
shiftKey: true },
}, aWindow);
}, popup: false, value: "M", searchString: ""
},
@ -110,15 +111,16 @@ nsDoTestsForAutoCompleteWithComposition.prototype = {
{ "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 2, "length": 0 }
"caret": { "start": 2, "length": 0 },
"key": { key: "o", code: "KeyO", keyCode: KeyboardEvent.DOM_VK_O },
}, aWindow);
}, popup: false, value: "Mo", searchString: ""
},
{ description: "compositionend should open the popup",
completeDefaultIndex: false,
execute: function (aWindow) {
synthesizeComposition({ type: "compositioncommitasis" }, aWindow);
synthesizeKey("VK_RETURN", { type: "keyup" }, aWindow);
synthesizeComposition({ type: "compositioncommitasis",
key: { key: "KEY_Enter", code: "Enter" } }, aWindow);
}, popup: true, value: "Mo", searchString: "Mo"
},
// If composition starts when popup is shown, the compositionstart event
@ -126,7 +128,6 @@ nsDoTestsForAutoCompleteWithComposition.prototype = {
{ description: "compositionstart should close the popup",
completeDefaultIndex: false,
execute: function (aWindow) {
synthesizeKey("z", { type: "keydown" }, aWindow);
synthesizeCompositionChange(
{ "composition":
{ "string": "z",
@ -135,7 +136,8 @@ nsDoTestsForAutoCompleteWithComposition.prototype = {
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 1, "length": 0 }
"caret": { "start": 1, "length": 0 },
"key": { key: "z", code: "KeyZ", keyCode: KeyboardEvent.DOM_VK_Z },
}, aWindow);
}, popup: false, value: "Moz", searchString: "Mo"
},
@ -150,22 +152,22 @@ nsDoTestsForAutoCompleteWithComposition.prototype = {
{ "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 2, "length": 0 }
"caret": { "start": 2, "length": 0 },
"key": { key: "i", code: "KeyI", keyCode: KeyboardEvent.DOM_VK_I },
}, aWindow);
}, popup: false, value: "Mozi", searchString: "Mo"
},
{ description: "compositionend should research the result and open the popup",
completeDefaultIndex: false,
execute: function (aWindow) {
synthesizeComposition({ type: "compositioncommitasis" }, aWindow);
synthesizeKey("VK_RETURN", { type: "keyup" }, aWindow);
synthesizeComposition({ type: "compositioncommitasis",
key: { key: "KEY_Enter", code: "Enter" } }, aWindow);
}, popup: true, value: "Mozi", searchString: "Mozi"
},
// If composition is cancelled, the value shouldn't be changed.
{ description: "compositionstart should reclose the popup",
completeDefaultIndex: false,
execute: function (aWindow) {
synthesizeKey("l", { type: "keydown" }, aWindow);
synthesizeCompositionChange(
{ "composition":
{ "string": "l",
@ -174,7 +176,8 @@ nsDoTestsForAutoCompleteWithComposition.prototype = {
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 1, "length": 0 }
"caret": { "start": 1, "length": 0 },
"key": { key: "l", code: "KeyL", keyCode: KeyboardEvent.DOM_VK_L },
}, aWindow);
}, popup: false, value: "Mozil", searchString: "Mozi"
},
@ -189,7 +192,8 @@ nsDoTestsForAutoCompleteWithComposition.prototype = {
{ "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 2, "length": 0 }
"caret": { "start": 2, "length": 0 },
"key": { key: "l", code: "KeyL", keyCode: KeyboardEvent.DOM_VK_L },
}, aWindow);
}, popup: false, value: "Mozill", searchString: "Mozi"
},
@ -211,8 +215,8 @@ nsDoTestsForAutoCompleteWithComposition.prototype = {
{ description: "cancled compositionend should reopen the popup",
completeDefaultIndex: false,
execute: function (aWindow) {
synthesizeComposition({ type: "compositioncommit", data: "" }, aWindow);
synthesizeKey("VK_ESCAPE", { type: "keyup" }, aWindow);
synthesizeComposition({ type: "compositioncommit", data: "",
key: { key: "KEY_Escape", code: "Escape" } }, aWindow);
}, popup: true, value: "Mozi", searchString: "Mozi"
},
// But if composition replaces some characters and canceled, the search
@ -222,7 +226,6 @@ nsDoTestsForAutoCompleteWithComposition.prototype = {
execute: function (aWindow) {
synthesizeKey("VK_LEFT", { shiftKey: true }, aWindow);
synthesizeKey("VK_LEFT", { shiftKey: true }, aWindow);
synthesizeKey("z", { type: "keydown" }, aWindow);
synthesizeCompositionChange(
{ "composition":
{ "string": "z",
@ -231,7 +234,8 @@ nsDoTestsForAutoCompleteWithComposition.prototype = {
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 1, "length": 0 }
"caret": { "start": 1, "length": 0 },
"key": { key: "z", code: "KeyZ", keyCode: KeyboardEvent.DOM_VK_Z },
}, aWindow);
}, popup: false, value: "Moz", searchString: "Mozi"
},
@ -246,7 +250,8 @@ nsDoTestsForAutoCompleteWithComposition.prototype = {
{ "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 2, "length": 0 }
"caret": { "start": 2, "length": 0 },
"key": { key: "i", code: "KeyI", keyCode: KeyboardEvent.DOM_VK_I },
}, aWindow);
}, popup: false, value: "Mozi", searchString: "Mozi"
},
@ -268,8 +273,8 @@ nsDoTestsForAutoCompleteWithComposition.prototype = {
{ description: "canceled compositionend should seach the result with the latest value",
completeDefaultIndex: false,
execute: function (aWindow) {
synthesizeComposition({ type: "compositioncommitasis" }, aWindow);
synthesizeKey("VK_ESCAPE", { type: "keyup" }, aWindow);
synthesizeComposition({ type: "compositioncommitasis",
key: { key: "KEY_Escape", code: "Escape" } }, aWindow);
}, popup: true, value: "Mo", searchString: "Mo"
},
//If all characters are removed, the popup should be closed.
@ -284,7 +289,6 @@ nsDoTestsForAutoCompleteWithComposition.prototype = {
{ description: "compositionstart shouldn't open the popup",
completeDefaultIndex: false,
execute: function (aWindow) {
synthesizeKey("m", { type: "keydown", shiftKey: true }, aWindow);
synthesizeCompositionChange(
{ "composition":
{ "string": "M",
@ -293,7 +297,9 @@ nsDoTestsForAutoCompleteWithComposition.prototype = {
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 1, "length": 0 }
"caret": { "start": 1, "length": 0 },
"key": { key: "m", code: "KeyM", keyCode: KeyboardEvent.DOM_VK_M,
shiftKey: true },
}, aWindow);
}, popup: false, value: "M", searchString: ""
},
@ -308,7 +314,8 @@ nsDoTestsForAutoCompleteWithComposition.prototype = {
{ "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 2, "length": 0 }
"caret": { "start": 2, "length": 0 },
"key": { key: "o", code: "KeyO", keyCode: KeyboardEvent.DOM_VK_O },
}, aWindow);
}, popup: false, value: "Mo", searchString: ""
},
@ -330,8 +337,8 @@ nsDoTestsForAutoCompleteWithComposition.prototype = {
{ description: "canceled compositionend shouldn't open the popup if it was closed",
completeDefaultIndex: false,
execute: function (aWindow) {
synthesizeComposition({ type: "compositioncommitasis" }, aWindow);
synthesizeKey("VK_ESCAPE", { type: "keyup" }, aWindow);
synthesizeComposition({ type: "compositioncommitasis",
key: { key: "KEY_Escape", code: "Escape" } }, aWindow);
}, popup: false, value: "", searchString: ""
},
// Down key should open the popup even if the editor is empty.
@ -346,7 +353,6 @@ nsDoTestsForAutoCompleteWithComposition.prototype = {
{ description: "compositionstart shouldn't open the popup",
completeDefaultIndex: false,
execute: function (aWindow) {
synthesizeKey("m", { type: "keydown", shiftKey: true }, aWindow);
synthesizeCompositionChange(
{ "composition":
{ "string": "M",
@ -355,7 +361,9 @@ nsDoTestsForAutoCompleteWithComposition.prototype = {
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 1, "length": 0 }
"caret": { "start": 1, "length": 0 },
"key": { key: "M", code: "KeyM", keyCode: KeyboardEvent.DOM_VK_M,
shiftKey: true },
}, aWindow);
}, popup: false, value: "M", searchString: ""
},
@ -370,7 +378,8 @@ nsDoTestsForAutoCompleteWithComposition.prototype = {
{ "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 2, "length": 0 }
"caret": { "start": 2, "length": 0 },
"key": { key: "o", code: "KeyO", keyCode: KeyboardEvent.DOM_VK_O },
}, aWindow);
}, popup: false, value: "Mo", searchString: ""
},
@ -392,8 +401,8 @@ nsDoTestsForAutoCompleteWithComposition.prototype = {
{ description: "canceled compositionend should open the popup if it was opened",
completeDefaultIndex: false,
execute: function (aWindow) {
synthesizeComposition({ type: "compositioncommitasis" }, aWindow);
synthesizeKey("VK_ESCAPE", { type: "keyup" }, aWindow);
synthesizeComposition({ type: "compositioncommitasis",
key: { key: "KEY_Escape", code: "Escape" } }, aWindow);
}, popup: true, value: "", searchString: ""
},
// Type normally, and hit escape, the popup should be closed.
@ -411,7 +420,6 @@ nsDoTestsForAutoCompleteWithComposition.prototype = {
{ description: "compositionstart shouldn't open the popup",
completeDefaultIndex: false,
execute: function (aWindow) {
synthesizeKey("z", { type: "keydown", shiftKey: true }, aWindow);
synthesizeCompositionChange(
{ "composition":
{ "string": "z",
@ -420,7 +428,8 @@ nsDoTestsForAutoCompleteWithComposition.prototype = {
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 1, "length": 0 }
"caret": { "start": 1, "length": 0 },
"key": { key: "z", code: "KeyZ", keyCode: KeyboardEvent.DOM_VK_Z },
}, aWindow);
}, popup: false, value: "Moz", searchString: "Mo"
},
@ -435,7 +444,8 @@ nsDoTestsForAutoCompleteWithComposition.prototype = {
{ "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 2, "length": 0 }
"caret": { "start": 2, "length": 0 },
"key": { key: "i", code: "KeyI", keyCode: KeyboardEvent.DOM_VK_I },
}, aWindow);
}, popup: false, value: "Mozi", searchString: "Mo"
},
@ -457,8 +467,8 @@ nsDoTestsForAutoCompleteWithComposition.prototype = {
{ description: "canceled compositionend shouldn't open the popup if the popup was closed",
completeDefaultIndex: false,
execute: function (aWindow) {
synthesizeComposition({ type: "compositioncommitasis" }, aWindow);
synthesizeKey("VK_ESCAPE", { type: "keyup" }, aWindow);
synthesizeComposition({ type: "compositioncommitasis",
key: { key: "KEY_Escape", code: "Escape" } }, aWindow);
}, popup: true, value: "Mo", searchString: "Mo"
},
// House keeping...
@ -473,7 +483,6 @@ nsDoTestsForAutoCompleteWithComposition.prototype = {
{ description: "compositionstart shouldn't open the popup (completeDefaultIndex is true)",
completeDefaultIndex: true,
execute: function (aWindow) {
synthesizeKey("m", { type: "keydown", shiftKey: true }, aWindow);
synthesizeCompositionChange(
{ "composition":
{ "string": "M",
@ -482,7 +491,9 @@ nsDoTestsForAutoCompleteWithComposition.prototype = {
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 1, "length": 0 }
"caret": { "start": 1, "length": 0 },
"key": { key: "M", code: "KeyM", keyCode: KeyboardEvent.DOM_VK_M,
shiftKey: true },
}, aWindow);
}, popup: false, value: "M", searchString: ""
},
@ -497,15 +508,16 @@ nsDoTestsForAutoCompleteWithComposition.prototype = {
{ "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 2, "length": 0 }
"caret": { "start": 2, "length": 0 },
"key": { key: "o", code: "KeyO", keyCode: KeyboardEvent.DOM_VK_O },
}, aWindow);
}, popup: false, value: "Mo", searchString: ""
},
{ description: "compositionend should open the popup (completeDefaultIndex is true)",
completeDefaultIndex: true,
execute: function (aWindow) {
synthesizeComposition({ type: "compositioncommitasis" }, aWindow);
synthesizeKey("VK_RETURN", { type: "keyup" }, aWindow);
synthesizeComposition({ type: "compositioncommitasis",
key: { key: "KEY_Enter", code: "Enter" } }, aWindow);
}, popup: true, value: "Mozilla", searchString: "Mo"
},
// House keeping...

View File

@ -172,9 +172,9 @@ const kTests = [
{ description: "WidgetKeyboardEvent (keyup during composition)",
targetID: "input-text", eventType: "keyup",
dispatchEvent: function () {
SpecialPowers.setBoolPref("dom.keyboardevent.dispatch_during_composition", true);
document.getElementById(this.targetID).value = "";
document.getElementById(this.targetID).focus();
synthesizeKey("a", { type: "keydown" });
synthesizeCompositionChange({ "composition":
{ "string": "\u306D",
"clauses":
@ -182,10 +182,11 @@ const kTests = [
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 1, "length": 0 }
"caret": { "start": 1, "length": 0 },
"key": { key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A },
});
synthesizeKey("a", { type: "keyup" });
synthesizeComposition({ type: "compositioncommitasis" });
SpecialPowers.clearUserPref("dom.keyboardevent.dispatch_during_composition");
},
canRun: function () {
return true;
@ -195,6 +196,7 @@ const kTests = [
{ description: "WidgetKeyboardEvent (keydown during composition)",
targetID: "input-text", eventType: "keydown",
dispatchEvent: function () {
SpecialPowers.setBoolPref("dom.keyboardevent.dispatch_during_composition", true);
document.getElementById(this.targetID).value = "";
document.getElementById(this.targetID).focus();
synthesizeCompositionChange({ "composition":
@ -206,9 +208,9 @@ const kTests = [
},
"caret": { "start": 1, "length": 0 }
});
synthesizeKey("VK_RETURN", { type: "keydown" });
synthesizeComposition({ type: "compositioncommitasis" });
synthesizeKey("VK_RETURN", { type: "keyup" });
synthesizeComposition({ type: "compositioncommitasis",
key: { key: "KEY_Enter", code: "Enter" } });
SpecialPowers.clearUserPref("dom.keyboardevent.dispatch_during_composition");
},
canRun: function () {
return true;

View File

@ -2938,10 +2938,10 @@ function runIsComposingTest()
// XXX These cases shouldn't occur in actual native key events because we
// don't dispatch key events while composition (bug 354358).
SpecialPowers.setBoolPref("dom.keyboardevent.dispatch_during_composition", true);
description = "events before dispatching compositionstart";
synthesizeKey("VK_LEFT", {});
synthesizeKey("a", { type: "keydown" });
description = "events after dispatching compositionchange";
synthesizeCompositionChange(
{ "composition":
@ -2951,23 +2951,25 @@ function runIsComposingTest()
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 1, "length": 0 }
"caret": { "start": 1, "length": 0 },
"key": { key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A },
});
synthesizeKey("a", { type: "keyup" });
// Although, firing keypress event during composition is a bug.
synthesizeKey("VK_INSERT", {});
description = "events for committing composition string";
synthesizeKey("VK_RETURN", { type: "keydown" });
synthesizeComposition({ type: "compositioncommitasis" });
synthesizeComposition({ type: "compositioncommitasis",
key: { key: "KEY_Enter", code: "Enter", type: "keydown" } });
// input event will be fired by synthesizing compositionend event.
// Then, its isComposing should be false.
description = "events after dispatching compositioncommitasis";
synthesizeKey("VK_RETURN", { type: "keyup" });
SpecialPowers.clearUserPref("dom.keyboardevent.dispatch_during_composition");
textarea.removeEventListener("keydown", eventHandler, true);
textarea.removeEventListener("keypress", eventHandler, true);
textarea.removeEventListener("keyup", eventHandler, true);