From d837b657fd3f4aaa8a25268247acb3b1173596c7 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Thu, 19 Feb 2015 15:50:20 +0900 Subject: [PATCH] Bug 1119609 part.13 EventUtils.synthesizeComposition() and synthesizeCompositionChange() should take KeyboardEvent for emulating composition state change caused by a key operation rs=smaug --- .../mochitest/tests/SimpleTest/EventUtils.js | 383 ++++++++++++++++-- .../file_autocomplete_with_composition.js | 92 +++-- widget/tests/test_assign_event_data.html | 14 +- .../window_composition_text_querycontent.xul | 12 +- 4 files changed, 413 insertions(+), 88 deletions(-) diff --git a/testing/mochitest/tests/SimpleTest/EventUtils.js b/testing/mochitest/tests/SimpleTest/EventUtils.js index 4a7d3c6e97d..9455b5b8d5d 100644 --- a/testing/mochitest/tests/SimpleTest/EventUtils.js +++ b/testing/mochitest/tests/SimpleTest/EventUtils.js @@ -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. diff --git a/toolkit/content/tests/chrome/file_autocomplete_with_composition.js b/toolkit/content/tests/chrome/file_autocomplete_with_composition.js index fe1127017d4..2c36add0d0f 100644 --- a/toolkit/content/tests/chrome/file_autocomplete_with_composition.js +++ b/toolkit/content/tests/chrome/file_autocomplete_with_composition.js @@ -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... diff --git a/widget/tests/test_assign_event_data.html b/widget/tests/test_assign_event_data.html index 0aab14cb50f..4d97fe5ec74 100644 --- a/widget/tests/test_assign_event_data.html +++ b/widget/tests/test_assign_event_data.html @@ -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; diff --git a/widget/tests/window_composition_text_querycontent.xul b/widget/tests/window_composition_text_querycontent.xul index dc10e20d609..c69ade332e6 100644 --- a/widget/tests/window_composition_text_querycontent.xul +++ b/widget/tests/window_composition_text_querycontent.xul @@ -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);