--- a/browser/base/content/test/about/browser_aboutHome_search_composing.js
+++ b/browser/base/content/test/about/browser_aboutHome_search_composing.js
@@ -16,20 +16,17 @@ add_task(async function() {
await p;
await ContentTask.spawn(browser, null, async function() {
// Start composition and type "x"
let input = content.document.querySelector(["#searchText", "#newtab-search-text"]);
input.focus();
});
- await BrowserTestUtils.synthesizeComposition({
- type: "compositionstart",
- data: ""
- }, browser);
+ // FYI: "compositionstart" will be dispatched automatically.
await BrowserTestUtils.synthesizeCompositionChange({
composition: {
string: "x",
clauses: [
{ length: 1, attr: Ci.nsITextInputProcessor.ATTR_RAW_CLAUSE }
]
},
caret: { start: 1, length: 0 }
--- a/dom/base/TextInputProcessor.cpp
+++ b/dom/base/TextInputProcessor.cpp
@@ -476,18 +476,19 @@ TextInputProcessor::IsValidStateForCompo
return NS_OK;
}
bool
TextInputProcessor::IsValidEventTypeForComposition(
const WidgetKeyboardEvent& aKeyboardEvent) const
{
- // The key event type of composition methods must be "" or "keydown".
- if (aKeyboardEvent.mMessage == eKeyDown) {
+ // The key event type of composition methods must be "", "keydown" or "keyup".
+ if (aKeyboardEvent.mMessage == eKeyDown ||
+ aKeyboardEvent.mMessage == eKeyUp) {
return true;
}
if (aKeyboardEvent.mMessage == eUnidentifiedEvent &&
aKeyboardEvent.mSpecifiedEventType &&
nsDependentAtomString(
aKeyboardEvent.mSpecifiedEventType).EqualsLiteral("on")) {
return true;
}
@@ -506,16 +507,22 @@ TextInputProcessor::MaybeDispatchKeydown
result.mCanContinue = false;
return result;
}
if (!aKeyboardEvent) {
return result;
}
+ // If the mMessage is eKeyUp, the caller doesn't want TIP to dispatch
+ // eKeyDown event.
+ if (aKeyboardEvent->mMessage == eKeyUp) {
+ return result;
+ }
+
// Modifier keys are not allowed because managing modifier state in this
// method makes this messy.
if (NS_WARN_IF(aKeyboardEvent->IsModifierKeyEvent())) {
result.mResult = NS_ERROR_INVALID_ARG;
result.mCanContinue = false;
return result;
}
@@ -540,17 +547,17 @@ TextInputProcessor::MaybeDispatchKeyupFo
{
EventDispatcherResult result;
if (!aKeyboardEvent) {
return result;
}
// If the mMessage is eKeyDown, the caller doesn't want TIP to dispatch
- // keyup event.
+ // eKeyUp event.
if (aKeyboardEvent->mMessage == eKeyDown) {
return result;
}
// If the widget has been destroyed, we can do nothing here.
result.mResult = IsValidStateForComposition();
if (NS_FAILED(result.mResult)) {
result.mCanContinue = false;
@@ -1121,16 +1128,22 @@ TextInputProcessor::KeydownInternal(cons
if (aKeyFlags & KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT) {
return NS_OK;
}
} else if (NS_WARN_IF(aKeyFlags & KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT)) {
return NS_ERROR_INVALID_ARG;
}
keyEvent.mModifiers = GetActiveModifiers();
+ if (!aAllowToDispatchKeypress &&
+ !(aKeyFlags & KEY_DONT_MARK_KEYDOWN_AS_PROCESSED)) {
+ keyEvent.mKeyCode = NS_VK_PROCESSKEY;
+ keyEvent.mKeyNameIndex = KEY_NAME_INDEX_Process;
+ }
+
RefPtr<TextEventDispatcher> kungFuDeathGrip(mDispatcher);
rv = IsValidStateForComposition();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsEventStatus status = aConsumedFlags ? nsEventStatus_eConsumeNoDefault :
nsEventStatus_eIgnore;
@@ -1201,16 +1214,21 @@ TextInputProcessor::KeyupInternal(const
if (aKeyFlags & KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT) {
return NS_OK;
}
} else if (NS_WARN_IF(aKeyFlags & KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT)) {
return NS_ERROR_INVALID_ARG;
}
keyEvent.mModifiers = GetActiveModifiers();
+ if (aKeyFlags & KEY_MARK_KEYUP_AS_PROCESSED) {
+ keyEvent.mKeyCode = NS_VK_PROCESSKEY;
+ keyEvent.mKeyNameIndex = KEY_NAME_INDEX_Process;
+ }
+
RefPtr<TextEventDispatcher> kungFuDeathGrip(mDispatcher);
rv = IsValidStateForComposition();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsEventStatus status = aDoDefault ? nsEventStatus_eIgnore :
nsEventStatus_eConsumeNoDefault;
--- a/dom/interfaces/base/nsITextInputProcessor.idl
+++ b/dom/interfaces/base/nsITextInputProcessor.idl
@@ -300,16 +300,20 @@ interface nsITextInputProcessor : nsISup
* compositionstart event hasn't been dispatched yet. If this is called
* when compositionstart has already been dispatched, this throws an
* exception.
*
* @param aKeyboardEvent Key event which causes starting composition.
* If its type value is "keydown", this method
* dispatches only keydown event first. Otherwise,
* dispatches keydown first and keyup at last.
+ * key value and keyCode values of keydown event
+ * are set to "Process" and DOM_VK_PROCESSKEY
+ * automatically. You can prevent this behavior
+ * with KEY_DONT_MARK_KEYDOWN_AS_PROCESSED.
* @param aKeyFlags See KEY_* constants.
* @return Returns true if composition starts normally.
* Otherwise, returns false because it might be
* canceled by the web application.
*/
[optional_argc]
boolean startComposition([optional] in nsIDOMEvent aKeyboardEvent,
[optional] in unsigned long aKeyFlags);
@@ -388,16 +392,20 @@ interface nsITextInputProcessor : nsISup
* Note that if sum of lengths of appended clauses are not same as composition
* string or caret offset is larger than the composition string length, this
* throws an exception.
*
* @param aKeyboardEvent Key event which causes the composition string.
* If its type value is "keydown", this method
* dispatches only keydown event first. Otherwise,
* dispatches keydown first and keyup at last.
+ * key value and keyCode values of keydown event
+ * are set to "Process" and DOM_VK_PROCESSKEY
+ * automatically. You can prevent this behavior
+ * with KEY_DONT_MARK_KEYDOWN_AS_PROCESSED.
* @param aKeyFlags See KEY_* constants.
* @return Returns true if there is a composition already or
* starting composition automatically.
* Otherwise, i.e., if it cannot start composition
* automatically, e.g., canceled by web apps, returns
* false.
*/
[optional_argc]
@@ -408,32 +416,40 @@ interface nsITextInputProcessor : nsISup
/**
* commitComposition() will commit composition with the last composition
* string. If there is no composition, this will throw an exception.
*
* @param aKeyboardEvent Key event which causes the commit composition.
* If its type value is "keydown", this method
* dispatches only keydown event first. Otherwise,
* dispatches keydown first and keyup at last.
+ * key value and keyCode values of keydown event
+ * are set to "Process" and DOM_VK_PROCESSKEY
+ * automatically. You can prevent this behavior
+ * with KEY_DONT_MARK_KEYDOWN_AS_PROCESSED.
* @param aKeyFlags See KEY_* constants.
*/
[optional_argc]
void commitComposition([optional] in nsIDOMEvent aKeyboardEvent,
[optional] in unsigned long aKeyFlags);
/**
* commitCompositionWith() will commit composition with the specific string.
* If there is no composition, this will start composition and commit it
* with the specified string.
*
* @param aCommitString The string to be committed.
* @param aKeyboardEvent Key event which causes the commit composition.
* If its type value is "keydown", this method
* dispatches only keydown event first. Otherwise,
* dispatches keydown first and keyup at last.
+ * key value and keyCode values of keydown event
+ * are set to "Process" and DOM_VK_PROCESSKEY
+ * automatically. You can prevent this behavior
+ * with KEY_DONT_MARK_KEYDOWN_AS_PROCESSED.
* @param aKeyFlags See KEY_* constants.
* @return Returns true if there is a composition already or
* starting composition automatically.
* Otherwise, i.e., if it cannot start composition
* automatically, e.g., canceled by web apps, returns
* false.
*/
[optional_argc]
@@ -449,16 +465,20 @@ interface nsITextInputProcessor : nsISup
*
* Note that if you tries to cancel composition when there is no composition,
* this throws an exception.
*
* @param aKeyboardEvent Key event which causes the canceling composition.
* If its type value is "keydown", this method
* dispatches only keydown event first. Otherwise,
* dispatches keydown first and keyup at last.
+ * key value and keyCode values of keydown event
+ * are set to "Process" and DOM_VK_PROCESSKEY
+ * automatically. You can prevent this behavior
+ * with KEY_DONT_MARK_KEYDOWN_AS_PROCESSED.
* @param aKeyFlags See KEY_* constants.
*/
[optional_argc]
void cancelComposition([optional] in nsIDOMEvent aKeyboardEvent,
[optional] in unsigned long aKeyFlags);
// Specifying KEY_DEFAULT_PREVENTED can dispatch key events whose
// defaultPrevented are true. Note that if this is specified, keypress event
@@ -483,16 +503,22 @@ interface nsITextInputProcessor : nsISup
// 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;
// If KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT is specified when the key event is
// a modifier key's, keydown() and keyup() only modifies its modifier state
// without dispatching key events. This is useful for testing odd behavior
// or emulating legacy API behavior.
const unsigned long KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT = 0x00000020;
+ // If KEY_DONT_MARK_KEYDOWN_AS_PROCESSED is specified, key value and keyCode
+ // value of keydown event are not changed to "Process" and DOM_VK_PROCESSKEY.
+ const unsigned long KEY_DONT_MARK_KEYDOWN_AS_PROCESSED = 0x00000040;
+ // If KEY_MARK_KEYUP_AS_PROCESSED is specified, key value and keyCode value
+ // of keyup event are changed to "Process" and DOM_VK_PROCESSKEY.
+ const unsigned long KEY_MARK_KEYUP_AS_PROCESSED = 0x00000080;
// These values can be used to do bitwise operation with the return value of
// the keydown() method.
const unsigned long KEYEVENT_NOT_CONSUMED = 0x00000000;
const unsigned long KEYDOWN_IS_CONSUMED = 0x00000001;
const unsigned long KEYPRESS_IS_CONSUMED = 0x00000002;
/**
--- a/dom/plugins/test/mochitest/test_windowless_ime.html
+++ b/dom/plugins/test/mochitest/test_windowless_ime.html
@@ -10,17 +10,17 @@ https://bugzilla.mozilla.org/show_bug.cg
<script type="application/javascript" src="plugin-utils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script class="testbody" type="text/javascript">
function runTests() {
var plugin = document.getElementById("plugin1");
plugin.focus();
- synthesizeComposition({ type: "compositionstart", data: "" });
+ // FYI: "compositionstart" will be dispatched automatically.
let data = "composition";
synthesizeCompositionChange({
composition: {
string: data,
clauses: [
{ length: data.length, attr: COMPOSITION_ATTR_RAW_CLAUSE }
]
},
--- a/editor/libeditor/tests/test_bug1109465.html
+++ b/editor/libeditor/tests/test_bug1109465.html
@@ -31,18 +31,18 @@ SimpleTest.waitForFocus(function() {
sendString("foo");
synthesizeKey("KEY_Enter");
sendString("bar");
synthesizeKey("KEY_ArrowUp");
is(t.selectionStart, 3, "Correct start of selection");
is(t.selectionEnd, 3, "Correct end of selection");
// Compose an IME string
- synthesizeComposition({ type: "compositionstart" });
var composingString = "\u306B";
+ // FYI: "compositionstart" will be dispatched automatically.
synthesizeCompositionChange(
{ "composition":
{ "string": composingString,
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
--- a/editor/libeditor/tests/test_bug1230473.html
+++ b/editor/libeditor/tests/test_bug1230473.html
@@ -51,67 +51,67 @@ SimpleTest.waitForFocus(()=>{
}
clear();
// Committing at compositionstart
aEditor.focus();
aEditor.addEventListener("compositionstart", committer, true);
synthesizeCompositionChange({ composition: { string: "a", clauses: [{length: 1, attr: COMPOSITION_ATTR_RAW_CLAUSE }] },
- caret: { start: 1, length: 0 }});
+ caret: { start: 1, length: 0 }, key: { key: "a" }});
aEditor.removeEventListener("compositionstart", committer, true);
ok(!isComposing(), "composition in " + aEditor.id + " should be committed by compositionstart event handler");
is(value(), "", "composition in " + aEditor.id + " shouldn't insert any text since it's committed at compositionstart");
clear();
// Committing at first compositionupdate
aEditor.focus();
aEditor.addEventListener("compositionupdate", committer, true);
synthesizeCompositionChange({ composition: { string: "a", clauses: [{length: 1, attr: COMPOSITION_ATTR_RAW_CLAUSE }] },
- caret: { start: 1, length: 0 }});
+ caret: { start: 1, length: 0 }, key: { key: "a" }});
aEditor.removeEventListener("compositionupdate", committer, true);
ok(!isComposing(), "composition in " + aEditor.id + " should be committed by compositionupdate event handler");
is(value(), "", "composition in " + aEditor.id + " shouldn't have inserted any text since it's committed at first compositionupdate");
clear();
// Committing at first text (eCompositionChange)
aEditor.focus();
aEditor.addEventListener("text", committer, true);
synthesizeCompositionChange({ composition: { string: "a", clauses: [{length: 1, attr: COMPOSITION_ATTR_RAW_CLAUSE }] },
- caret: { start: 1, length: 0 }});
+ caret: { start: 1, length: 0 }, key: { key: "a" }});
aEditor.removeEventListener("text", committer, true);
ok(!isComposing(), "composition in " + aEditor.id + " should be committed by text event handler");
is(value(), "", "composition in " + aEditor.id + " should have inserted any text since it's committed at first text");
clear();
// Committing at second compositionupdate
aEditor.focus();
- synthesizeComposition({ type: "compositionstart" });
+ // FYI: "compositionstart" will be dispatched automatically.
synthesizeCompositionChange({ composition: { string: "a", clauses: [{length: 1, attr: COMPOSITION_ATTR_RAW_CLAUSE }] },
- caret: { start: 1, length: 0 }});
+ caret: { start: 1, length: 0 }, key: { key: "a" }});
ok(isComposing(), "composition should be in " + aEditor.id + " before dispatching second compositionupdate");
is(value(), "a", "composition in " + aEditor.id + " should be 'a' before dispatching second compositionupdate");
aEditor.addEventListener("compositionupdate", committer, true);
synthesizeCompositionChange({ composition: { string: "ab", clauses: [{length: 2, attr: COMPOSITION_ATTR_RAW_CLAUSE }] },
- caret: { start: 2, length: 0 }});
+ caret: { start: 2, length: 0 }, key: { key: "b" }});
aEditor.removeEventListener("compositionupdate", committer, true);
ok(!isComposing(), "composition in " + aEditor.id + " should be committed by compositionupdate event handler");
todo_is(value(), "a", "composition in " + aEditor.id + " shouldn't have been modified since it's committed at second compositionupdate");
clear();
// Committing at second text (eCompositionChange)
aEditor.focus();
- synthesizeComposition({ type: "compositionstart" });
+ // FYI: "compositionstart" will be dispatched automatically.
synthesizeCompositionChange({ composition: { string: "a", clauses: [{length: 1, attr: COMPOSITION_ATTR_RAW_CLAUSE }] },
- caret: { start: 1, length: 0 }});
+ caret: { start: 1, length: 0 }, key: { key: "a" }});
ok(isComposing(), "composition should be in " + aEditor.id + " before dispatching second text");
is(value(), "a", "composition in " + aEditor.id + " should be 'a' before dispatching second text");
aEditor.addEventListener("text", committer, true);
synthesizeCompositionChange({ composition: { string: "ab", clauses: [{length: 2, attr: COMPOSITION_ATTR_RAW_CLAUSE }] },
- caret: { start: 2, length: 0 }});
+ caret: { start: 2, length: 0 }, key: { key: "b" }});
aEditor.removeEventListener("text", committer, true);
ok(!isComposing(), "composition in " + aEditor.id + " should be committed by text event handler");
todo_is(value(), "a", "composition in " + aEditor.id + " shouldn't have been modified since it's committed at second text");
clear();
}
runTest(document.getElementById("input"));
runTest(document.getElementById("textarea"));
runTest(document.getElementById("div"));
--- a/testing/mochitest/tests/Harness_sanity/test_sanityEventUtils.html
+++ b/testing/mochitest/tests/Harness_sanity/test_sanityEventUtils.html
@@ -27,32 +27,37 @@
<p>blah blah blah blah</p>
<p>blah blah blah blah</p>
<p>blah blah blah blah</p>
<p>blah blah blah blah</p>
</div>
<script class="testbody" type="text/javascript">
const kStrictKeyPressEvents =
SpecialPowers.getBoolPref("dom.keyboardevent.keypress.dispatch_non_printable_keys_only_system_group_in_content");
+const kStrictKeyDownKeyUpEvents =
+ SpecialPowers.getBoolPref("dom.keyboardevent.dispatch_during_composition");
info("\nProfile::EventUtilsLoadTime: " + (loadTime - start) + "\n");
function starttest() {
SimpleTest.waitForFocus(
function () {
SimpleTest.waitForExplicitFinish();
var startTime = new Date();
var check = false;
-
+ function doCheck() {
+ check = true;
+ }
+
/* test send* functions */
- $("testMouseEvent").addEventListener("click", function() { check=true; });
+ $("testMouseEvent").addEventListener("click", doCheck, {once: true});
sendMouseEvent({type:'click'}, "testMouseEvent");
is(check, true, 'sendMouseEvent should dispatch click event');
check = false;
- $("testKeyEvent").addEventListener("keypress", function() { check = true; }, {once: true});
+ $("testKeyEvent").addEventListener("keypress", doCheck, {once: true});
$("testKeyEvent").focus();
sendChar("x");
is($("testKeyEvent").value, "x", "sendChar should work");
is(check, true, "sendChar should dispatch keyPress");
$("testKeyEvent").value = "";
$("testStrEvent").focus();
sendString("string");
@@ -105,75 +110,131 @@ function starttest() {
* that we can successfully call it to avoid having setTimeout vary the runtime metric.
* Testing of this method is currently done here:
* toolkit/content/tests/chrome/test_mousescroll.xul
*/
synthesizeWheel($("scrollB"), 5, 5, {'deltaY': 10.0, deltaMode: WheelEvent.DOM_DELTA_LINE});
/* test synthesizeKey* */
check = false;
- $("testKeyEvent").addEventListener("keypress", function() { check = true; });
+ $("testKeyEvent").addEventListener("keypress", doCheck, {once:true});
$("testKeyEvent").focus();
sendString("a");
is($("testKeyEvent").value, "a", "synthesizeKey should work");
is(check, true, "synthesizeKey should dispatch keyPress");
$("testKeyEvent").value = "";
check = false;
+ $("testKeyEvent").addEventListener("keypress", doCheck, {once:true});
synthesizeKeyExpectEvent("a", {}, $("testKeyEvent"), "keypress");
is($("testKeyEvent").value, "a", "synthesizeKey should work");
is(check, true, "synthesizeKey should dispatch keyPress");
$("testKeyEvent").value = "";
/* test synthesizeComposition */
+ var description = "";
+ var keydownEvent = null;
+ var keyupEvent = null;
+ function onKeyDown(aEvent) {
+ ok(!keydownEvent, description + "keydown should be fired only once" + (keydownEvent ? keydownEvent.key : "") + ", " + (keyupEvent ? keyupEvent.key : ""));
+ keydownEvent = aEvent;
+ }
+ function onKeyUp(aEvent) {
+ ok(!keyupEvent, description + "keyup should be fired only once");
+ keyupEvent = aEvent;
+ }
+ function resetKeyDownAndKeyUp(aDescription) {
+ description = aDescription + ": ";
+ keydownEvent = null;
+ keyupEvent = null;
+ check = false;
+ }
+ function checkKeyDownAndKeyUp(aKeyDown, aKeyUp) {
+ if (aKeyDown && (!aKeyDown.inComposition || kStrictKeyDownKeyUpEvents)) {
+ is(keydownEvent.keyCode, aKeyDown.keyCode,
+ description + "keydown event should be dispatched (checking keyCode)");
+ is(keydownEvent.key, aKeyDown.key,
+ description + "keydown event should be dispatched (checking key)");
+ } else {
+ is(keydownEvent, null,
+ description + "keydown event shouldn't be fired");
+ }
+ if (aKeyUp && (!aKeyUp.inComposition || kStrictKeyDownKeyUpEvents)) {
+ is(keyupEvent.keyCode, aKeyUp.keyCode,
+ description + "keyup event should be dispatched (checking keyCode)");
+ is(keyupEvent.key, aKeyUp.key,
+ description + "keyup event should be dispatched (checking key)");
+ } else {
+ is(keyupEvent, null,
+ description + "keyup event shouldn't be fired");
+ }
+ }
+ $("textBoxB").addEventListener("keydown", onKeyDown);
+ $("textBoxB").addEventListener("keyup", onKeyUp);
+
$("textBoxB").focus();
- check = false;
- window.addEventListener("compositionstart", function() { check = true; });
- synthesizeComposition({ type: "compositionstart" });
- is(check, true, 'synthesizeComposition() should dispatch compositionstart');
-
- check = false;
- window.addEventListener("compositionupdate", function() { check = true; });
- synthesizeComposition({ type: "compositionupdate", data: "a" });
- is(check, false, 'synthesizeComposition() should not dispatch compositionupdate without error');
- check = false;
- window.addEventListener("text", function() { check = true; });
+ // If key event is not specified, fake keydown and keyup events which are
+ // marked as "processed by IME" should be fired.
+ resetKeyDownAndKeyUp("synthesizing eCompositionStart without specifying keyboard event");
+ window.addEventListener("compositionstart", doCheck, {once: true});
+ synthesizeComposition({type: "compositionstart"});
+ ok(check, description + "synthesizeComposition() should dispatch compositionstart");
+ checkKeyDownAndKeyUp({inComposition: false, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"},
+ {inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"});
+
+ resetKeyDownAndKeyUp("trying to synthesize eCompositionUpdate directly without specifying keyboard event");
+ window.addEventListener("compositionupdate", doCheck, {once: true});
+ synthesizeComposition({type: "compositionupdate", data: "a"});
+ ok(!check, description + "synthesizeComposition() should not dispatch compositionupdate without error");
+ checkKeyDownAndKeyUp(null, null);
+
+ resetKeyDownAndKeyUp("synthesizing eCompositionChange without specifying keyboard event");
+ window.addEventListener("text", doCheck, {once: true});
synthesizeCompositionChange(
{ "composition":
{ "string": "a",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 1, "length": 0 }
}
);
- is(check, true, "synthesizeCompositionChange should cause dispatching a DOM text event");
+ ok(check, description + "synthesizeCompositionChange should cause dispatching a DOM text event");
+ checkKeyDownAndKeyUp({inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"},
+ {inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"});
+ resetKeyDownAndKeyUp("synthesizing eCompositionChange for removing clauses without specifying keyboard event");
synthesizeCompositionChange(
{ "composition":
{ "string": "a",
"clauses":
[
{ "length": 0, "attr": 0 }
]
},
"caret": { "start": 1, "length": 0 }
}
);
+ checkKeyDownAndKeyUp({inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"},
+ {inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"});
- check = false;
- window.addEventListener("compositionend", function() { check = true; });
- synthesizeComposition({ type: "compositionend", data: "a" });
- is(check, false, 'synthesizeComposition() should not dispatch compositionend');
+ resetKeyDownAndKeyUp("trying to synthesize eCompositionEnd directly without specifying keyboard event");
+ window.addEventListener("compositionend", doCheck, {once: true});
+ synthesizeComposition({type: "compositionend", data: "a"});
+ ok(!check, description + "synthesizeComposition() should not dispatch compositionend");
+ checkKeyDownAndKeyUp(null, null);
- synthesizeComposition({ type: "compositioncommit", data: "a" });
- is(check, true, 'synthesizeComposition() should dispatch compositionend');
+ resetKeyDownAndKeyUp("synthesizing eCompositionCommit without specifying keyboard event");
+ synthesizeComposition({type: "compositioncommit", data: "a"});
+ ok(check, description + "synthesizeComposition() should dispatch compositionend");
+ checkKeyDownAndKeyUp({inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"},
+ {inComposition: false, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"});
var querySelectedText = synthesizeQuerySelectedText();
ok(querySelectedText, "query selected text event result is null");
ok(querySelectedText.succeeded, "query selected text event failed");
is(querySelectedText.offset, 1,
"query selected text event returns wrong offset");
is(querySelectedText.text, "",
"query selected text event returns wrong selected text");
@@ -183,15 +244,211 @@ function starttest() {
ok(querySelectedText, "query selected text event result is null");
ok(querySelectedText.succeeded, "query selected text event failed");
is(querySelectedText.offset, 0,
"query selected text event returns wrong offset");
is(querySelectedText.text, "",
"query selected text event returns wrong selected text");
var endTime = new Date();
info("\nProfile::EventUtilsRunTime: " + (endTime-startTime) + "\n");
+
+ // In most cases, automated tests shouldn't try to synthesize
+ // compositionstart manually. Let's check if synthesizeCompositionChange()
+ // dispatches compositionstart automatically.
+ resetKeyDownAndKeyUp("synthesizing eCompositionChange without specifying keyboard event when there is no composition");
+ window.addEventListener("compositionstart", doCheck, {once: true});
+ synthesizeCompositionChange(
+ { "composition":
+ { "string": "a",
+ "clauses":
+ [
+ { "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
+ ]
+ },
+ "caret": { "start": 1, "length": 0 }
+ }
+ );
+ ok(check, description + "synthesizeCompositionChange should dispatch \"compositionstart\" automatically if there is no composition");
+ checkKeyDownAndKeyUp({inComposition: false, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"},
+ {inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"});
+
+ resetKeyDownAndKeyUp("synthesizing eCompositionCommitAsIs without specifying keyboard event");
+ synthesizeComposition({type: "compositioncommitasis"});
+ checkKeyDownAndKeyUp({inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"},
+ {inComposition: false, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"});
+
+ // If key event is specified, keydown event which is marked as "processed
+ // by IME" should be fired and keyup event which is NOT marked as so
+ // should be fired too.
+ resetKeyDownAndKeyUp("synthesizing eCompositionStart with specifying keyboard event");
+ synthesizeComposition({type: "compositionstart", key: {key: "a"}});
+ checkKeyDownAndKeyUp({inComposition: false, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"},
+ {inComposition: true, keyCode: KeyboardEvent.DOM_VK_A, key: "a"});
+
+ resetKeyDownAndKeyUp("synthesizing eCompositionChange with specifying keyboard event");
+ synthesizeCompositionChange(
+ {"composition":
+ {"string": "b", "clauses": [
+ {"length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE}
+ ]},
+ "caret": {"start": 1, "length": 0},
+ "key": {key: "b"},
+ }
+ );
+ checkKeyDownAndKeyUp({inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"},
+ {inComposition: true, keyCode: KeyboardEvent.DOM_VK_B, key: "b"});
+
+ resetKeyDownAndKeyUp("synthesizing eCompositionCommit with specifying keyboard event");
+ synthesizeComposition({type: "compositioncommit", data: "c", key: {key: "KEY_Enter"}});
+ checkKeyDownAndKeyUp({inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"},
+ {inComposition: false, keyCode: KeyboardEvent.DOM_VK_RETURN, key: "Enter"});
+
+ // keyup shouldn't be dispatched automatically if type is specified as keydown
+ resetKeyDownAndKeyUp("synthesizing eCompositionStart with specifying keyboard event whose type is keydown");
+ synthesizeComposition({type: "compositionstart", key: {key: "a", type: "keydown"}});
+ checkKeyDownAndKeyUp({inComposition: false, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"},
+ null);
+
+ resetKeyDownAndKeyUp("synthesizing eCompositionChange with specifying keyboard event whose type is keydown");
+ synthesizeCompositionChange(
+ {"composition":
+ {"string": "b", "clauses": [
+ {"length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE}
+ ]},
+ "caret": {"start": 1, "length": 0},
+ "key": {key: "b", type: "keydown"},
+ }
+ );
+ checkKeyDownAndKeyUp({inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"},
+ null);
+
+ resetKeyDownAndKeyUp("synthesizing eCompositionCommit with specifying keyboard event whose type is keydown");
+ synthesizeComposition({type: "compositioncommit", data: "c", key: {key: "KEY_Enter", type: "keydown"}});
+ checkKeyDownAndKeyUp({inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"},
+ null);
+
+ // keydown shouldn't be dispatched automatically if type is specified as keyup
+ resetKeyDownAndKeyUp("synthesizing eCompositionStart with specifying keyboard event whose type is keyup");
+ synthesizeComposition({type: "compositionstart", key: {key: "a", type: "keyup"}});
+ checkKeyDownAndKeyUp(null,
+ {inComposition: true, keyCode: KeyboardEvent.DOM_VK_A, key: "a"});
+
+ resetKeyDownAndKeyUp("synthesizing eCompositionChange with specifying keyboard event whose type is keyup");
+ synthesizeCompositionChange(
+ {"composition":
+ {"string": "b", "clauses": [
+ {"length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE}
+ ]},
+ "caret": {"start": 1, "length": 0},
+ "key": {key: "b", type: "keyup"},
+ }
+ );
+ checkKeyDownAndKeyUp(null,
+ {inComposition: true, keyCode: KeyboardEvent.DOM_VK_B, key: "b"});
+
+ resetKeyDownAndKeyUp("synthesizing eCompositionCommit with specifying keyboard event whose type is keyup");
+ synthesizeComposition({type: "compositioncommit", data: "c", key: {key: "KEY_Enter", type: "keyup"}});
+ checkKeyDownAndKeyUp(null,
+ {inComposition: false, keyCode: KeyboardEvent.DOM_VK_RETURN, key: "Enter"});
+
+ // keydown event shouldn't be marked as "processed by IME" if doNotMarkKeydownAsProcessed is true
+ resetKeyDownAndKeyUp("synthesizing eCompositionStart with specifying keyboard event whose doNotMarkKeydownAsProcessed is true");
+ synthesizeComposition({type: "compositionstart", key: {key: "a", doNotMarkKeydownAsProcessed: true}});
+ checkKeyDownAndKeyUp({inComposition: false, keyCode: KeyboardEvent.DOM_VK_A, key: "a"},
+ {inComposition: true, keyCode: KeyboardEvent.DOM_VK_A, key: "a"});
+
+ resetKeyDownAndKeyUp("synthesizing eCompositionChange with specifying keyboard event whose doNotMarkKeydownAsProcessed is true");
+ synthesizeCompositionChange(
+ {"composition":
+ {"string": "b", "clauses": [
+ {"length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE}
+ ]},
+ "caret": {"start": 1, "length": 0},
+ "key": {key: "b", doNotMarkKeydownAsProcessed: true},
+ }
+ );
+ checkKeyDownAndKeyUp({inComposition: true, keyCode: KeyboardEvent.DOM_VK_B, key: "b"},
+ {inComposition: true, keyCode: KeyboardEvent.DOM_VK_B, key: "b"});
+
+ resetKeyDownAndKeyUp("synthesizing eCompositionCommit with specifying keyboard event whose doNotMarkKeydownAsProcessed is true");
+ synthesizeComposition({type: "compositioncommit", data: "c", key: {key: "KEY_Enter", doNotMarkKeydownAsProcessed: true}});
+ checkKeyDownAndKeyUp({inComposition: true, keyCode: KeyboardEvent.DOM_VK_RETURN, key: "Enter"},
+ {inComposition: false, keyCode: KeyboardEvent.DOM_VK_RETURN, key: "Enter"});
+
+ // keyup event should be marked as "processed by IME" if markKeyupAsProcessed is true
+ resetKeyDownAndKeyUp("synthesizing eCompositionStart with specifying keyboard event whose markKeyupAsProcessed is true");
+ synthesizeComposition({type: "compositionstart", key: {key: "a", markKeyupAsProcessed: true}});
+ checkKeyDownAndKeyUp({inComposition: false, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"},
+ {inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"});
+
+ resetKeyDownAndKeyUp("synthesizing eCompositionChange with specifying keyboard event whose markKeyupAsProcessed is true");
+ synthesizeCompositionChange(
+ {"composition":
+ {"string": "b", "clauses": [
+ {"length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE}
+ ]},
+ "caret": {"start": 1, "length": 0},
+ "key": {key: "b", markKeyupAsProcessed: true},
+ }
+ );
+ checkKeyDownAndKeyUp({inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"},
+ {inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"});
+
+ resetKeyDownAndKeyUp("synthesizing eCompositionCommit with specifying keyboard event whose markKeyupAsProcessed is true");
+ synthesizeComposition({type: "compositioncommit", data: "c", key: {key: "KEY_Enter", markKeyupAsProcessed: true}});
+ checkKeyDownAndKeyUp({inComposition: true, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"},
+ {inComposition: false, keyCode: KeyboardEvent.DOM_VK_PROCESSKEY, key: "Process"});
+
+ // If key event is explicitly declared with null, keyboard events shouldn't
+ // be fired for emulating text inputs without keyboard such as voice input or something.
+ resetKeyDownAndKeyUp("synthesizing eCompositionStart with specifying keyboard event as null");
+ synthesizeComposition({type: "compositionstart", key: null});
+ checkKeyDownAndKeyUp(null, null);
+
+ resetKeyDownAndKeyUp("synthesizing eCompositionChange with specifying keyboard event as null");
+ synthesizeCompositionChange(
+ {"composition":
+ {"string": "b", "clauses": [
+ {"length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE}
+ ]},
+ "caret": {"start": 1, "length": 0},
+ "key": null,
+ }
+ );
+ checkKeyDownAndKeyUp(null, null);
+
+ resetKeyDownAndKeyUp("synthesizing eCompositionCommit with specifying keyboard event as null");
+ synthesizeComposition({type: "compositioncommit", data: "c", key: null});
+ checkKeyDownAndKeyUp(null, null);
+
+ // If key event is explicitly declared with empty object, keyboard events
+ // shouldn't be fired for emulating text inputs without keyboard such as
+ // voice input or something.
+ resetKeyDownAndKeyUp("synthesizing eCompositionStart with specifying keyboard event as empty");
+ synthesizeComposition({type: "compositionstart", key: {}});
+ checkKeyDownAndKeyUp(null, null);
+
+ resetKeyDownAndKeyUp("synthesizing eCompositionChange with specifying keyboard event as empty");
+ synthesizeCompositionChange(
+ {"composition":
+ {"string": "b", "clauses": [
+ {"length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE}
+ ]},
+ "caret": {"start": 1, "length": 0},
+ "key": {},
+ }
+ );
+ checkKeyDownAndKeyUp(null, null);
+
+ resetKeyDownAndKeyUp("synthesizing eCompositionCommit with specifying keyboard event as empty");
+ synthesizeComposition({type: "compositioncommit", data: "c", key: {}});
+ checkKeyDownAndKeyUp(null, null);
+
+ $("textBoxB").removeEventListener("keydown", onKeyDown);
+ $("textBoxB").removeEventListener("keyup", onKeyUp);
+
SimpleTest.finish();
}
);
};
</script>
</body>
</html>
--- a/testing/mochitest/tests/SimpleTest/EventUtils.js
+++ b/testing/mochitest/tests/SimpleTest/EventUtils.js
@@ -1464,16 +1464,18 @@ function _guessKeyNameFromKeyCode(aKeyCo
case KeyboardEvent.DOM_VK_VOLUME_DOWN:
return "AudioVolumeDown";
case KeyboardEvent.DOM_VK_VOLUME_UP:
return "AudioVolumeUp";
case KeyboardEvent.DOM_VK_META:
return "Meta";
case KeyboardEvent.DOM_VK_ALTGR:
return "AltGraph";
+ case KeyboardEvent.DOM_VK_PROCESSKEY:
+ return "Process";
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";
@@ -1776,16 +1778,23 @@ function _createKeyboardEventDictionary(
}
var code = "code" in aKeyEvent ?
aKeyEvent.code :
_guessCodeFromKeyName(keyName, aKeyEvent.location, aWindow);
var locationIsDefined = "location" in aKeyEvent;
if (locationIsDefined && aKeyEvent.location === 0) {
result.flags |= _EU_Ci.nsITextInputProcessor.KEY_KEEP_KEY_LOCATION_STANDARD;
}
+ if (aKeyEvent.doNotMarkKeydownAsProcessed) {
+ result.flags |=
+ _EU_Ci.nsITextInputProcessor.KEY_DONT_MARK_KEYDOWN_AS_PROCESSED;
+ }
+ if (aKeyEvent.markKeyupAsProcessed) {
+ result.flags |= _EU_Ci.nsITextInputProcessor.KEY_MARK_KEYUP_AS_PROCESSED;
+ }
result.dictionary = {
key: keyName,
code: code,
location: locationIsDefined ? aKeyEvent.location : 0,
repeat: "repeat" in aKeyEvent ? aKeyEvent.repeat === true : false,
keyCode: keyCode,
};
return result;
@@ -1875,54 +1884,84 @@ function _emulateToInactivateModifiers(a
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.
+ * Synthesize a composition event and keydown event and keyup events unless
+ * you prevent to dispatch them explicitly (see aEvent.key's explanation).
+ *
+ * Note that you shouldn't call this with "compositionstart" unless you need to
+ * test compositionstart event which is NOT followed by compositionupdate
+ * event immediately. Typically, native IME starts composition with
+ * a pair of keydown and keyup event and dispatch compositionstart and
+ * compositionupdate (and non-standard text event) between them. So, in most
+ * cases, you should call synthesizeCompositionChange() directly.
+ * If you call this with compositionstart, keyup event will be fired
+ * immediately after compositionstart. In other words, you should use
+ * "compositionstart" only when you need to emulate IME which just starts
+ * composition with compositionstart event but does not send composing text to
+ * us until committing the composition. This is behavior of some Chinese IMEs.
*
* @param aEvent The composition event information. This must
* have |type| member. The value must be
* "compositionstart", "compositionend",
* "compositioncommitasis" or "compositioncommit".
+ *
* And also this may have |data| and |locale| which
* would be used for the value of each property of
* 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.
+ *
+ * If |key| is undefined, "keydown" and "keyup"
+ * events which are marked as "processed by IME"
+ * are dispatched. If |key| is not null, "keydown"
+ * and/or "keyup" events are dispatched (if the
+ * |key.type| is specified as "keydown", only
+ * "keydown" event is dispatched). Otherwise,
+ * i.e., if |key| is null, neither "keydown" nor
+ * "keyup" event is dispatched.
+ *
+ * If |key.doNotMarkKeydownAsProcessed| is not true,
+ * key value and keyCode value of "keydown" event
+ * will be set to "Process" and DOM_VK_PROCESSKEY.
+ * If |key.markKeyupAsProcessed| is true,
+ * key value and keyCode value of "keyup" event
+ * will be set to "Process" and DOM_VK_PROCESSKEY.
* @param aWindow Optional (If null, current |window| will be used)
* @param aCallback Optional (If non-null, use the callback for
* receiving notifications to IME)
*/
function synthesizeComposition(aEvent, aWindow = window, aCallback)
{
var TIP = _getTIP(aWindow, aCallback);
if (!TIP) {
return false;
}
var KeyboardEvent = _getKeyboardEvent(aWindow);
var modifiers = _emulateToActivateModifiers(TIP, aEvent.key, aWindow);
var ret = false;
- var keyEventDict =
- "key" in aEvent ?
- _createKeyboardEventDictionary(aEvent.key.key, aEvent.key, aWindow) :
- { dictionary: null, flags: 0 };
- var keyEvent =
- "key" in aEvent ?
- new KeyboardEvent(aEvent.type === "keydown" ? "keydown" : "",
- keyEventDict.dictionary) :
- null;
+ var keyEventDict = {dictionary: null, flags: 0};
+ var keyEvent = null;
+ if (aEvent.key && typeof aEvent.key.key === "string") {
+ keyEventDict =
+ _createKeyboardEventDictionary(aEvent.key.key, aEvent.key, aWindow);
+ keyEvent = new KeyboardEvent(aEvent.key.type === "keydown" ?
+ "keydown" :
+ aEvent.key.type === "keyup" ?
+ "keyup" : "",
+ keyEventDict.dictionary)
+ } else if (aEvent.key === undefined) {
+ keyEventDict = _createKeyboardEventDictionary("KEY_Process", {}, aWindow);
+ keyEvent = new KeyboardEvent("", keyEventDict.dictionary)
+ }
try {
switch (aEvent.type) {
case "compositionstart":
ret = TIP.startComposition(keyEvent, keyEventDict.flags);
break;
case "compositioncommitasis":
ret = TIP.commitComposition(keyEvent, keyEventDict.flags);
break;
@@ -1931,18 +1970,25 @@ function synthesizeComposition(aEvent, a
keyEventDict.flags);
break;
}
} finally {
_emulateToInactivateModifiers(TIP, modifiers, aWindow);
}
}
/**
- * Synthesize a compositionchange event which causes a DOM text event and
- * compositionupdate event if it's necessary.
+ * Synthesize eCompositionChange event which causes a DOM text event, may
+ * cause compositionupdate event, and causes keydown event and keyup event
+ * unless you prevent to dispatch them explicitly (see aEvent.key's
+ * explanation).
+ *
+ * Note that if you call this when there is no composition, compositionstart
+ * event will be fired automatically. This is better than you use
+ * synthesizeComposition("compositionstart") in most cases. See the
+ * explanation of syntehszeComposition().
*
* @param aEvent The compositionchange event's information, this has
* |composition| and |caret| members. |composition| has
* |string| and |clauses| members. |clauses| must be array
* object. Each object has |length| and |attr|. And |caret|
* has |start| and |length|. See the following tree image.
*
* aEvent
@@ -1970,20 +2016,28 @@ function synthesizeComposition(aEvent, a
* |composition.clauses[0].attr|.
*
* Set caret position to the |caret.start|. It's offset from
* the start of the composition string. Set caret length to
* |caret.length|. If it's larger than 0, it should be wide
* 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.
+ * If |key| is undefined, "keydown" and "keyup" events which
+ * are marked as "processed by IME" are dispatched. If |key|
+ * is not null, "keydown" and/or "keyup" events are dispatched
+ * (if the |key.type| is specified as "keydown", only "keydown"
+ * event is dispatched). Otherwise, i.e., if |key| is null,
+ * neither "keydown" nor "keyup" event is dispatched.
+ * If |key.doNotMarkKeydownAsProcessed| is not true, key value
+ * and keyCode value of "keydown" event will be set to
+ * "Process" and DOM_VK_PROCESSKEY.
+ * If |key.markKeyupAsProcessed| is true key value and keyCode
+ * value of "keyup" event will be set to "Process" and
+ * DOM_VK_PROCESSKEY.
*
* @param aWindow Optional (If null, current |window| will be used)
* @param aCallback Optional (If non-null, use the callback for receiving
* notifications to IME)
*/
function synthesizeCompositionChange(aEvent, aWindow = window, aCallback)
{
var TIP = _getTIP(aWindow, aCallback);
@@ -2020,25 +2074,30 @@ function synthesizeCompositionChange(aEv
}
if (aEvent.caret) {
TIP.setCaretInPendingComposition(aEvent.caret.start);
}
var modifiers = _emulateToActivateModifiers(TIP, aEvent.key, aWindow);
try {
- var keyEventDict =
- "key" in aEvent ?
- _createKeyboardEventDictionary(aEvent.key.key, aEvent.key, aWindow) :
- { dictionary: null, flags: 0 };
- var keyEvent =
- "key" in aEvent ?
- new KeyboardEvent(aEvent.type === "keydown" ? "keydown" : "",
- keyEventDict.dictionary) :
- null;
+ var keyEventDict = {dictionary: null, flags: 0};
+ var keyEvent = null;
+ if (aEvent.key && typeof aEvent.key.key === "string") {
+ keyEventDict =
+ _createKeyboardEventDictionary(aEvent.key.key, aEvent.key, aWindow);
+ keyEvent = new KeyboardEvent(aEvent.key.type === "keydown" ?
+ "keydown" :
+ aEvent.key.type === "keyup" ?
+ "keyup" : "",
+ keyEventDict.dictionary)
+ } else if (aEvent.key === undefined) {
+ keyEventDict = _createKeyboardEventDictionary("KEY_Process", {}, aWindow);
+ keyEvent = new KeyboardEvent("", keyEventDict.dictionary)
+ }
TIP.flushPendingComposition(keyEvent, keyEventDict.flags);
} finally {
_emulateToInactivateModifiers(TIP, modifiers, aWindow);
}
}
// Must be synchronized with nsIDOMWindowUtils.
const QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK = 0x0000;
--- a/toolkit/content/tests/chrome/file_autocomplete_with_composition.js
+++ b/toolkit/content/tests/chrome/file_autocomplete_with_composition.js
@@ -93,138 +93,135 @@ nsDoTestsForAutoCompleteWithComposition.
{ "composition":
{ "string": "M",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 1, "length": 0 },
- "key": { key: "M", code: "KeyM", keyCode: KeyboardEvent.DOM_VK_M,
- shiftKey: true },
+ "key": { key: "M" },
}, aWindow);
}, popup: false, value: "M", searchString: ""
},
{ description: "modifying composition string shouldn't open the popup",
completeDefaultIndex: false,
execute(aWindow) {
synthesizeCompositionChange(
{ "composition":
{ "string": "Mo",
"clauses":
[
{ "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 2, "length": 0 },
- "key": { key: "o", code: "KeyO", keyCode: KeyboardEvent.DOM_VK_O },
+ "key": { key: "o" },
}, aWindow);
}, popup: false, value: "Mo", searchString: ""
},
{ description: "compositionend should open the popup",
completeDefaultIndex: false,
execute(aWindow) {
- synthesizeComposition({ type: "compositioncommitasis",
- key: { key: "KEY_Enter", code: "Enter" } }, aWindow);
+ synthesizeComposition({ type: "compositioncommitasis", key: { key: "KEY_Enter" } }, aWindow);
}, popup: true, value: "Mo", searchString: "Mo"
},
// If composition starts when popup is shown, the compositionstart event
// should cause closing the popup.
{ description: "compositionstart should close the popup",
completeDefaultIndex: false,
execute(aWindow) {
synthesizeCompositionChange(
{ "composition":
{ "string": "z",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 1, "length": 0 },
- "key": { key: "z", code: "KeyZ", keyCode: KeyboardEvent.DOM_VK_Z },
+ "key": { key: "z" },
}, aWindow);
}, popup: false, value: "Moz", searchString: "Mo"
},
{ description: "modifying composition string shouldn't reopen the popup",
completeDefaultIndex: false,
execute(aWindow) {
synthesizeCompositionChange(
{ "composition":
{ "string": "zi",
"clauses":
[
{ "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 2, "length": 0 },
- "key": { key: "i", code: "KeyI", keyCode: KeyboardEvent.DOM_VK_I },
+ "key": { key: "i" },
}, aWindow);
}, popup: false, value: "Mozi", searchString: "Mo"
},
{ description: "compositionend should research the result and open the popup",
completeDefaultIndex: false,
execute(aWindow) {
- synthesizeComposition({ type: "compositioncommitasis",
- key: { key: "KEY_Enter", code: "Enter" } }, aWindow);
+ synthesizeComposition({ type: "compositioncommitasis", key: { key: "KEY_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(aWindow) {
synthesizeCompositionChange(
{ "composition":
{ "string": "l",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 1, "length": 0 },
- "key": { key: "l", code: "KeyL", keyCode: KeyboardEvent.DOM_VK_L },
+ "key": { key: "l" },
}, aWindow);
}, popup: false, value: "Mozil", searchString: "Mozi"
},
{ description: "modifying composition string shouldn't reopen the popup",
completeDefaultIndex: false,
execute(aWindow) {
synthesizeCompositionChange(
{ "composition":
{ "string": "ll",
"clauses":
[
{ "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 2, "length": 0 },
- "key": { key: "l", code: "KeyL", keyCode: KeyboardEvent.DOM_VK_L },
+ "key": { key: "l" },
}, aWindow);
}, popup: false, value: "Mozill", searchString: "Mozi"
},
{ description: "modifying composition string to empty string shouldn't reopen the popup",
completeDefaultIndex: false,
execute(aWindow) {
synthesizeCompositionChange(
{ "composition":
{ "string": "",
"clauses":
[
{ "length": 0, "attr": 0 }
]
},
- "caret": { "start": 0, "length": 0 }
+ "caret": { "start": 0, "length": 0 },
+ "key": { key: "KEY_Backspace" },
}, aWindow);
}, popup: false, value: "Mozi", searchString: "Mozi"
},
{ description: "cancled compositionend should reopen the popup",
completeDefaultIndex: false,
execute(aWindow) {
- synthesizeComposition({ type: "compositioncommit", data: "",
- key: { key: "KEY_Escape", code: "Escape" } }, aWindow);
+ synthesizeComposition({ type: "compositioncommit", data: "", key: { key: "KEY_Escape" } }, aWindow);
}, popup: true, value: "Mozi", searchString: "Mozi"
},
// But if composition replaces some characters and canceled, the search
// string should be the latest value.
{ description: "compositionstart with selected string should close the popup",
completeDefaultIndex: false,
execute(aWindow) {
synthesizeKey("VK_LEFT", { shiftKey: true }, aWindow);
@@ -233,193 +230,191 @@ nsDoTestsForAutoCompleteWithComposition.
{ "composition":
{ "string": "z",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 1, "length": 0 },
- "key": { key: "z", code: "KeyZ", keyCode: KeyboardEvent.DOM_VK_Z },
+ "key": { key: "z" },
}, aWindow);
}, popup: false, value: "Moz", searchString: "Mozi"
},
{ description: "modifying composition string shouldn't reopen the popup",
completeDefaultIndex: false,
execute(aWindow) {
synthesizeCompositionChange(
{ "composition":
{ "string": "zi",
"clauses":
[
{ "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 2, "length": 0 },
- "key": { key: "i", code: "KeyI", keyCode: KeyboardEvent.DOM_VK_I },
+ "key": { key: "i" },
}, aWindow);
}, popup: false, value: "Mozi", searchString: "Mozi"
},
{ description: "modifying composition string to empty string shouldn't reopen the popup",
completeDefaultIndex: false,
execute(aWindow) {
synthesizeCompositionChange(
{ "composition":
{ "string": "",
"clauses":
[
{ "length": 0, "attr": 0 }
]
},
- "caret": { "start": 0, "length": 0 }
+ "caret": { "start": 0, "length": 0 },
+ "key": { key: "KEY_Backspace" },
}, aWindow);
}, popup: false, value: "Mo", searchString: "Mozi"
},
{ description: "canceled compositionend should search the result with the latest value",
completeDefaultIndex: false,
execute(aWindow) {
- synthesizeComposition({ type: "compositioncommitasis",
- key: { key: "KEY_Escape", code: "Escape" } }, aWindow);
+ synthesizeComposition({ type: "compositioncommitasis", key: { key: "KEY_Escape" } }, aWindow);
}, popup: true, value: "Mo", searchString: "Mo"
},
// If all characters are removed, the popup should be closed.
{ description: "the value becomes empty by backspace, the popup should be closed",
completeDefaultIndex: false,
execute(aWindow) {
- synthesizeKey("VK_BACK_SPACE", {}, aWindow);
- synthesizeKey("VK_BACK_SPACE", {}, aWindow);
+ synthesizeKey("KEY_Backspace", {}, aWindow);
+ synthesizeKey("KEY_Backspace", {}, aWindow);
}, popup: false, value: "", searchString: ""
},
// composition which is canceled shouldn't cause opening the popup.
{ description: "compositionstart shouldn't open the popup",
completeDefaultIndex: false,
execute(aWindow) {
synthesizeCompositionChange(
{ "composition":
{ "string": "M",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 1, "length": 0 },
- "key": { key: "m", code: "KeyM", keyCode: KeyboardEvent.DOM_VK_M,
- shiftKey: true },
+ "key": { key: "M" },
}, aWindow);
}, popup: false, value: "M", searchString: ""
},
{ description: "modifying composition string shouldn't open the popup",
completeDefaultIndex: false,
execute(aWindow) {
synthesizeCompositionChange(
{ "composition":
{ "string": "Mo",
"clauses":
[
{ "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 2, "length": 0 },
- "key": { key: "o", code: "KeyO", keyCode: KeyboardEvent.DOM_VK_O },
+ "key": { key: "o" },
}, aWindow);
}, popup: false, value: "Mo", searchString: ""
},
{ description: "modifying composition string to empty string shouldn't open the popup",
completeDefaultIndex: false,
execute(aWindow) {
synthesizeCompositionChange(
{ "composition":
{ "string": "",
"clauses":
[
{ "length": 0, "attr": 0 }
]
},
- "caret": { "start": 0, "length": 0 }
+ "caret": { "start": 0, "length": 0 },
+ "key": { key: "KEY_Backspace" },
}, aWindow);
}, popup: false, value: "", searchString: ""
},
{ description: "canceled compositionend shouldn't open the popup if it was closed",
completeDefaultIndex: false,
execute(aWindow) {
- synthesizeComposition({ type: "compositioncommitasis",
- key: { key: "KEY_Escape", code: "Escape" } }, aWindow);
+ synthesizeComposition({ type: "compositioncommitasis", key: { key: "KEY_Escape" } }, aWindow);
}, popup: false, value: "", searchString: ""
},
// Down key should open the popup even if the editor is empty.
{ description: "DOWN key should open the popup even if the value is empty",
completeDefaultIndex: false,
execute(aWindow) {
- synthesizeKey("VK_DOWN", {}, aWindow);
+ synthesizeKey("KEY_ArrowDown", {}, aWindow);
}, popup: true, value: "", searchString: ""
},
// If popup is open at starting composition, the popup should be reopened
// after composition anyway.
{ description: "compositionstart shouldn't open the popup",
completeDefaultIndex: false,
execute(aWindow) {
synthesizeCompositionChange(
{ "composition":
{ "string": "M",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 1, "length": 0 },
- "key": { key: "M", code: "KeyM", keyCode: KeyboardEvent.DOM_VK_M,
- shiftKey: true },
+ "key": { key: "M" },
}, aWindow);
}, popup: false, value: "M", searchString: ""
},
{ description: "modifying composition string shouldn't open the popup",
completeDefaultIndex: false,
execute(aWindow) {
synthesizeCompositionChange(
{ "composition":
{ "string": "Mo",
"clauses":
[
{ "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 2, "length": 0 },
- "key": { key: "o", code: "KeyO", keyCode: KeyboardEvent.DOM_VK_O },
+ "key": { key: "o" },
}, aWindow);
}, popup: false, value: "Mo", searchString: ""
},
{ description: "modifying composition string to empty string shouldn't open the popup",
completeDefaultIndex: false,
execute(aWindow) {
synthesizeCompositionChange(
{ "composition":
{ "string": "",
"clauses":
[
{ "length": 0, "attr": 0 }
]
},
- "caret": { "start": 0, "length": 0 }
+ "caret": { "start": 0, "length": 0 },
+ "key": { key: "KEY_Backspace" },
}, aWindow);
}, popup: false, value: "", searchString: ""
},
{ description: "canceled compositionend should open the popup if it was opened",
completeDefaultIndex: false,
execute(aWindow) {
- synthesizeComposition({ type: "compositioncommitasis",
- key: { key: "KEY_Escape", code: "Escape" } }, aWindow);
+ synthesizeComposition({ type: "compositioncommitasis", key: { key: "KEY_Escape" } }, aWindow);
}, popup: true, value: "", searchString: ""
},
// Type normally, and hit escape, the popup should be closed.
{ description: "ESCAPE should close the popup after typing something",
completeDefaultIndex: false,
execute(aWindow) {
- synthesizeKey("M", { shiftKey: true }, aWindow);
- synthesizeKey("o", { shiftKey: true }, aWindow);
- synthesizeKey("VK_ESCAPE", {}, aWindow);
+ synthesizeKey("M", {}, aWindow);
+ synthesizeKey("o", {}, aWindow);
+ synthesizeKey("KEY_Escape", {}, aWindow);
}, popup: false, value: "Mo", searchString: "Mo"
},
// Even if the popup is closed, composition which is canceled should open
// the popup if the value isn't empty.
// XXX This might not be good behavior, but anyway, this is minor issue...
{ description: "compositionstart shouldn't open the popup",
completeDefaultIndex: false,
execute(aWindow) {
@@ -427,113 +422,111 @@ nsDoTestsForAutoCompleteWithComposition.
{ "composition":
{ "string": "z",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 1, "length": 0 },
- "key": { key: "z", code: "KeyZ", keyCode: KeyboardEvent.DOM_VK_Z },
+ "key": { key: "z" },
}, aWindow);
}, popup: false, value: "Moz", searchString: "Mo"
},
{ description: "modifying composition string shouldn't open the popup",
completeDefaultIndex: false,
execute(aWindow) {
synthesizeCompositionChange(
{ "composition":
{ "string": "zi",
"clauses":
[
{ "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 2, "length": 0 },
- "key": { key: "i", code: "KeyI", keyCode: KeyboardEvent.DOM_VK_I },
+ "key": { key: "i", },
}, aWindow);
}, popup: false, value: "Mozi", searchString: "Mo"
},
{ description: "modifying composition string to empty string shouldn't open the popup",
completeDefaultIndex: false,
execute(aWindow) {
synthesizeCompositionChange(
{ "composition":
{ "string": "",
"clauses":
[
{ "length": 0, "attr": 0 }
]
},
- "caret": { "start": 0, "length": 0 }
+ "caret": { "start": 0, "length": 0 },
+ "key": { key: "KEY_Backspace" },
}, aWindow);
}, popup: false, value: "Mo", searchString: "Mo"
},
{ description: "canceled compositionend shouldn't open the popup if the popup was closed",
completeDefaultIndex: false,
execute(aWindow) {
- synthesizeComposition({ type: "compositioncommitasis",
- key: { key: "KEY_Escape", code: "Escape" } }, aWindow);
+ synthesizeComposition({ type: "compositioncommitasis", key: { key: "KEY_Escape" } }, aWindow);
}, popup: true, value: "Mo", searchString: "Mo"
},
// House keeping...
{ description: "house keeping for next tests",
completeDefaultIndex: false,
execute(aWindow) {
- synthesizeKey("VK_BACK_SPACE", {}, aWindow);
- synthesizeKey("VK_BACK_SPACE", {}, aWindow);
+ synthesizeKey("KEY_Backspace", {}, aWindow);
+ synthesizeKey("KEY_Backspace", {}, aWindow);
}, popup: false, value: "", searchString: ""
},
// Testing for nsIAutoCompleteInput.completeDefaultIndex being true.
{ description: "compositionstart shouldn't open the popup (completeDefaultIndex is true)",
completeDefaultIndex: true,
execute(aWindow) {
synthesizeCompositionChange(
{ "composition":
{ "string": "M",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 1, "length": 0 },
- "key": { key: "M", code: "KeyM", keyCode: KeyboardEvent.DOM_VK_M,
- shiftKey: true },
+ "key": { key: "M" },
}, aWindow);
}, popup: false, value: "M", searchString: ""
},
{ description: "modifying composition string shouldn't open the popup (completeDefaultIndex is true)",
completeDefaultIndex: true,
execute(aWindow) {
synthesizeCompositionChange(
{ "composition":
{ "string": "Mo",
"clauses":
[
{ "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 2, "length": 0 },
- "key": { key: "o", code: "KeyO", keyCode: KeyboardEvent.DOM_VK_O },
+ "key": { key: "o" },
}, aWindow);
}, popup: false, value: "Mo", searchString: ""
},
{ description: "compositionend should open the popup (completeDefaultIndex is true)",
completeDefaultIndex: true,
execute(aWindow) {
- synthesizeComposition({ type: "compositioncommitasis",
- key: { key: "KEY_Enter", code: "Enter" } }, aWindow);
+ synthesizeComposition({ type: "compositioncommitasis", key: { key: "KEY_Enter" } }, aWindow);
}, popup: true, value: "Mozilla", searchString: "Mo"
},
// House keeping...
{ description: "house keeping for next tests",
completeDefaultIndex: false,
execute(aWindow) {
- synthesizeKey("VK_BACK_SPACE", {}, aWindow);
- synthesizeKey("VK_BACK_SPACE", {}, aWindow);
- synthesizeKey("VK_BACK_SPACE", {}, aWindow);
- synthesizeKey("VK_BACK_SPACE", {}, aWindow);
- synthesizeKey("VK_BACK_SPACE", {}, aWindow);
- synthesizeKey("VK_BACK_SPACE", {}, aWindow);
+ synthesizeKey("KEY_Backspace", {}, aWindow);
+ synthesizeKey("KEY_Backspace", {}, aWindow);
+ synthesizeKey("KEY_Backspace", {}, aWindow);
+ synthesizeKey("KEY_Backspace", {}, aWindow);
+ synthesizeKey("KEY_Backspace", {}, aWindow);
+ synthesizeKey("KEY_Backspace", {}, aWindow);
}, popup: false, value: "", searchString: ""
}
]
};
--- a/widget/WidgetEventImpl.cpp
+++ b/widget/WidgetEventImpl.cpp
@@ -1433,16 +1433,18 @@ WidgetKeyboardEvent::ComputeKeyCodeFromK
case KEY_NAME_INDEX_AudioVolumeDown:
return dom::KeyboardEventBinding::DOM_VK_VOLUME_DOWN;
case KEY_NAME_INDEX_AudioVolumeUp:
return dom::KeyboardEventBinding::DOM_VK_VOLUME_UP;
case KEY_NAME_INDEX_Meta:
return dom::KeyboardEventBinding::DOM_VK_META;
case KEY_NAME_INDEX_AltGraph:
return dom::KeyboardEventBinding::DOM_VK_ALTGR;
+ case KEY_NAME_INDEX_Process:
+ return dom::KeyboardEventBinding::DOM_VK_PROCESSKEY;
case KEY_NAME_INDEX_Attn:
return dom::KeyboardEventBinding::DOM_VK_ATTN;
case KEY_NAME_INDEX_CrSel:
return dom::KeyboardEventBinding::DOM_VK_CRSEL;
case KEY_NAME_INDEX_ExSel:
return dom::KeyboardEventBinding::DOM_VK_EXSEL;
case KEY_NAME_INDEX_EraseEof:
return dom::KeyboardEventBinding::DOM_VK_EREOF;
--- a/widget/tests/test_assign_event_data.html
+++ b/widget/tests/test_assign_event_data.html
@@ -238,19 +238,19 @@ const kTests = [
synthesizeCompositionChange({ "composition":
{ "string": "\u306D",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
"caret": { "start": 1, "length": 0 },
- "key": { key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A },
+ "key": { key: "a" },
});
- synthesizeComposition({ type: "compositioncommitasis" });
+ synthesizeComposition({ type: "compositioncommitasis", key: {} });
setAndObserveCompositionPref(null, runNextTest);
});
return true;
},
canRun: function () {
return true;
},
todoMismatch: [ ],
@@ -263,20 +263,21 @@ const kTests = [
document.getElementById(this.targetID).focus();
synthesizeCompositionChange({ "composition":
{ "string": "\u306D",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": {},
});
synthesizeComposition({ type: "compositioncommitasis",
- key: { key: "KEY_Enter", code: "Enter" } });
+ key: { key: "KEY_Enter" } });
setAndObserveCompositionPref(null, runNextTest);
});
return true;
},
canRun: function () {
return true;
},
todoMismatch: [ ],
@@ -328,29 +329,29 @@ const kTests = [
},
todoMismatch: [],
},
{ description: "WidgetTextEvent (text)",
targetID: "input-text", eventType: "text",
dispatchEvent: function () {
document.getElementById(this.targetID).value = "";
document.getElementById(this.targetID).focus();
- synthesizeComposition({ type: "compositioncommit", data: "\u306D" });
+ synthesizeComposition({ type: "compositioncommit", data: "\u306D", key: { key: "," } });
},
canRun: function () {
return true;
},
todoMismatch: [ ],
},
{ description: "WidgetCompositionEvent (compositionupdate)",
targetID: "input-text", eventType: "compositionupdate",
dispatchEvent: function () {
document.getElementById(this.targetID).value = "";
document.getElementById(this.targetID).focus();
- synthesizeComposition({ type: "compositioncommit", data: "\u30E9\u30FC\u30E1\u30F3" });
+ synthesizeComposition({ type: "compositioncommit", data: "\u30E9\u30FC\u30E1\u30F3", key: { key: "KEY_Enter" } });
},
canRun: function () {
return true;
},
todoMismatch: [ ],
},
{ description: "InternalEditorInputEvent (input at key input)",
targetID: "input-text", eventType: "input",
@@ -374,28 +375,29 @@ const kTests = [
document.getElementById(this.targetID).focus();
synthesizeCompositionChange({ "composition":
{ "string": "\u30E9\u30FC\u30E1\u30F3",
"clauses":
[
{ "length": 4, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 4, "length": 0 }
+ "caret": { "start": 4, "length": 0 },
+ "key": { key: "y" },
});
},
canRun: function () {
return true;
},
todoMismatch: [ ],
},
{ description: "InternalEditorInputEvent (input at committing)",
targetID: "input-text", eventType: "input",
dispatchEvent: function () {
- synthesizeComposition({ type: "compositioncommitasis" });
+ synthesizeComposition({ type: "compositioncommitasis", key: { key: "KEY_Enter" } });
},
canRun: function () {
return true;
},
todoMismatch: [ ],
},
{ description: "WidgetMouseScrollEvent (DOMMouseScroll, vertical)",
targetID: "input-text", eventType: "DOMMouseScroll",
--- a/widget/tests/window_composition_text_querycontent.xul
+++ b/widget/tests/window_composition_text_querycontent.xul
@@ -314,174 +314,187 @@ function runUndoRedoTest()
synthesizeCompositionChange(
{ "composition":
{ "string": "\u306D",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "," },
});
synthesizeCompositionChange(
{ "composition":
{ "string": "\u306D\u3053",
"clauses":
[
{ "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 2, "length": 0 }
+ "caret": { "start": 2, "length": 0 },
+ "key": { key: "b" },
});
// convert
synthesizeCompositionChange(
{ "composition":
{ "string": "\u732B",
"clauses":
[
{ "length": 1,
"attr": COMPOSITION_ATTR_SELECTED_CLAUSE }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: " " },
});
// commit
- synthesizeComposition({ type: "compositioncommitasis" });
+ synthesizeComposition({ type: "compositioncommitasis", key: { key: "KEY_Enter" } });
// input raw characters
synthesizeCompositionChange(
{ "composition":
{ "string": "\u307E",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "j" },
});
// cancel the composition
- synthesizeComposition({ type: "compositioncommit", data: "" });
+ synthesizeComposition({ type: "compositioncommit", data: "", key: { key: "KEY_Escape" } });
// input raw characters
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3080",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "]" },
});
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3080\u3059",
"clauses":
[
{ "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 2, "length": 0 }
+ "caret": { "start": 2, "length": 0 },
+ "key": { key: "r" },
});
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3080\u3059\u3081",
"clauses":
[
{ "length": 3, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 3, "length": 0 }
+ "caret": { "start": 3, "length": 0 },
+ "key": { key: "/" },
});
// convert
synthesizeCompositionChange(
{ "composition":
{ "string": "\u5A18",
"clauses":
[
{ "length": 1,
"attr": COMPOSITION_ATTR_SELECTED_CLAUSE }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: " " },
});
// commit
- synthesizeComposition({ type: "compositioncommitasis" });
+ synthesizeComposition({ type: "compositioncommitasis", key: { key: "KEY_Enter" } });
sendString(" meant");
synthesizeKey("KEY_Backspace");
synthesizeKey("s \"cat-girl\". She is a ");
// input raw characters
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3088",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "9" },
});
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3088\u3046",
"clauses":
[
{ "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 2, "length": 0 }
+ "caret": { "start": 2, "length": 0 },
+ "key": { key: "4" },
});
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3088\u3046\u304b",
"clauses":
[
{ "length": 3, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 3, "length": 0 }
+ "caret": { "start": 3, "length": 0 },
+ "key": { key: "t" },
});
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3088\u3046\u304b\u3044",
"clauses":
[
{ "length": 4, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 4, "length": 0 }
+ "caret": { "start": 4, "length": 0 },
+ "key": { key: "e" },
});
// convert
synthesizeCompositionChange(
{ "composition":
{ "string": "\u5996\u602a",
"clauses":
[
{ "length": 2, "attr": COMPOSITION_ATTR_SELECTED_CLAUSE }
]
},
- "caret": { "start": 2, "length": 0 }
+ "caret": { "start": 2, "length": 0 },
+ "key": { key: " " },
});
// commit
- synthesizeComposition({ type: "compositioncommitasis" });
+ synthesizeComposition({ type: "compositioncommitasis", key: { key: "Enter" } });
synthesizeKey("KEY_Backspace", {repeat: 12});
var i = 0;
if (!checkContent("\u732B\u5A18 means \"cat-girl\".",
"runUndoRedoTest", "#" + ++i) ||
!checkSelection(20, "", "runUndoRedoTest", "#" + i)) {
return;
@@ -659,22 +672,23 @@ function runCompositionCommitAsIsTest()
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3042",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "a" },
});
is(textarea.value, "\u3042", "runCompositionCommitAsIsTest: textarea doesn't have composition string #1");
clearResult();
- synthesizeComposition({ type: "compositioncommitasis" });
+ synthesizeComposition({ type: "compositioncommitasis", key: { key: "Enter" } });
is(result.compositionupdate, false, "runCompositionCommitAsIsTest: compositionupdate shouldn't be fired after dispatching compositioncommitasis #1");
is(result.compositionend, true, "runCompositionCommitAsIsTest: compositionend should be fired after dispatching compositioncommitasis #1");
is(result.text, true, "runCompositionCommitAsIsTest: text should be fired after dispatching compositioncommitasis because it's dispatched when there is composing string #1");
is(result.input, true, "runCompositionCommitAsIsTest: input should be fired after dispatching compositioncommitasis #1");
is(textarea.value, "\u3042", "runCompositionCommitAsIsTest: textarea doesn't have committed string #1");
// compositioncommitasis with committed string.
@@ -682,33 +696,35 @@ function runCompositionCommitAsIsTest()
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3042",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "a" },
});
is(textarea.value, "\u3042", "runCompositionCommitAsIsTest: textarea doesn't have composition string #2");
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3042",
"clauses":
[
{ "length": 0, "attr": 0 }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "KEY_Enter", type: "keydown" },
});
is(textarea.value, "\u3042", "runCompositionCommitAsIsTest: textarea doesn't have committed string #2");
clearResult();
- synthesizeComposition({ type: "compositioncommitasis" });
+ synthesizeComposition({ type: "compositioncommitasis", key: { key: "KEY_Enter", type: "keyup" } });
is(result.compositionupdate, false, "runCompositionCommitAsIsTest: compositionupdate shouldn't be fired after dispatching compositioncommitasis #2");
is(result.compositionend, true, "runCompositionCommitAsIsTest: compositionend should be fired after dispatching compositioncommitasis #2");
is(result.text, false, "runCompositionCommitAsIsTest: text shouldn't be fired after dispatching compositioncommitasis because it's dispatched when there is already committed string #2");
is(result.input, true, "runCompositionCommitAsIsTest: input should be fired after dispatching compositioncommitasis #2");
is(textarea.value, "\u3042", "runCompositionCommitAsIsTest: textarea doesn't have committed string #2");
// compositioncommitasis with committed string.
@@ -716,33 +732,35 @@ function runCompositionCommitAsIsTest()
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3042",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "a" },
});
is(textarea.value, "\u3042", "runCompositionCommitAsIsTest: textarea doesn't have composition string #3");
synthesizeCompositionChange(
{ "composition":
{ "string": "",
"clauses":
[
{ "length": 0, "attr": 0 }
]
},
- "caret": { "start": 0, "length": 0 }
+ "caret": { "start": 0, "length": 0 },
+ "key": { key: "KEY_Escape", type: "keydown" },
});
is(textarea.value, "", "runCompositionCommitAsIsTest: textarea has non-empty composition string #3");
clearResult();
- synthesizeComposition({ type: "compositioncommitasis" });
+ synthesizeComposition({ type: "compositioncommitasis", key: { key: "KEY_Escape", type: "keyup" } });
is(result.compositionupdate, false, "runCompositionCommitAsIsTest: compositionupdate shouldn't be fired after dispatching compositioncommitasis #3");
is(result.compositionend, true, "runCompositionCommitAsIsTest: compositionend should be fired after dispatching compositioncommitasis #3");
is(result.text, false, "runCompositionCommitAsIsTest: text shouldn't be fired after dispatching compositioncommitasis because it's dispatched when there is empty composition string #3");
is(result.input, true, "runCompositionCommitAsIsTest: input should be fired after dispatching compositioncommitasis #3");
is(textarea.value, "", "runCompositionCommitAsIsTest: textarea doesn't have committed string #3");
textarea.removeEventListener("compositionupdate", handler, true);
@@ -776,22 +794,23 @@ function runCompositionCommitTest()
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3042",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "a", type: "keydown" },
});
is(textarea.value, "\u3042", "runCompositionCommitTest: textarea doesn't have composition string #1");
clearResult();
- synthesizeComposition({ type: "compositioncommit", data: "\u3043" });
+ synthesizeComposition({ type: "compositioncommit", data: "\u3043", key: { key: "a", type: "keyup" } });
is(result.compositionupdate, true, "runCompositionCommitTest: compositionupdate should be fired after dispatching compositioncommit #1");
is(result.compositionend, true, "runCompositionCommitTest: compositionend should be fired after dispatching compositioncommit #1");
is(result.text, true, "runCompositionCommitTest: text should be fired after dispatching compositioncommit because it's dispatched when there is compoing string #1");
is(result.input, true, "runCompositionCommitTest: input should be fired after dispatching compositioncommit #1");
is(textarea.value, "\u3043", "runCompositionCommitTest: textarea doesn't have committed string #1");
// compositioncommit with different committed string when there is already committed string
@@ -799,33 +818,35 @@ function runCompositionCommitTest()
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3042",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "a" },
});
is(textarea.value, "\u3042", "runCompositionCommitTest: textarea doesn't have composition string #2");
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3042",
"clauses":
[
{ "length": 0, "attr": 0 }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "KEY_Enter", type: "keydown" },
});
is(textarea.value, "\u3042", "runCompositionCommitTest: textarea doesn't have committed string #2");
clearResult();
- synthesizeComposition({ type: "compositioncommit", data: "\u3043" });
+ synthesizeComposition({ type: "compositioncommit", data: "\u3043", key: { key: "KEY_Enter", type: "keyup" } });
is(result.compositionupdate, true, "runCompositionCommitTest: compositionupdate should be fired after dispatching compositioncommit #2");
is(result.compositionend, true, "runCompositionCommitTest: compositionend should be fired after dispatching compositioncommit #2");
is(result.text, true, "runCompositionCommitTest: text should be fired after dispatching compositioncommit #2");
is(result.input, true, "runCompositionCommitTest: input should be fired after dispatching compositioncommit #2");
is(textarea.value, "\u3043", "runCompositionCommitTest: textarea doesn't have committed string #2");
// compositioncommit with empty composition string.
@@ -833,33 +854,35 @@ function runCompositionCommitTest()
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3042",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "a" },
});
is(textarea.value, "\u3042", "runCompositionCommitTest: textarea doesn't have composition string #3");
synthesizeCompositionChange(
{ "composition":
{ "string": "",
"clauses":
[
{ "length": 0, "attr": 0 }
]
},
- "caret": { "start": 0, "length": 0 }
+ "caret": { "start": 0, "length": 0 },
+ "key": { key: "KEY_Enter", type: "keydown" },
});
is(textarea.value, "", "runCompositionCommitTest: textarea has non-empty composition string #3");
clearResult();
- synthesizeComposition({ type: "compositioncommit", data: "\u3043" });
+ synthesizeComposition({ type: "compositioncommit", data: "\u3043", key: { key: "KEY_Enter", type: "keyup" } });
is(result.compositionupdate, true, "runCompositionCommitTest: compositionupdate should be fired after dispatching compositioncommit #3");
is(result.compositionend, true, "runCompositionCommitTest: compositionend should be fired after dispatching compositioncommit #3");
is(result.text, true, "runCompositionCommitTest: text should be fired after dispatching compositioncommit #3");
is(result.input, true, "runCompositionCommitTest: input should be fired after dispatching compositioncommit #3");
is(textarea.value, "\u3043", "runCompositionCommitTest: textarea doesn't have committed string #3");
// compositioncommit with non-empty composition string.
@@ -867,34 +890,35 @@ function runCompositionCommitTest()
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3042",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "a" },
});
is(textarea.value, "\u3042", "runCompositionCommitTest: textarea doesn't have composition string #4");
clearResult();
- synthesizeComposition({ type: "compositioncommit", data: "" });
+ synthesizeComposition({ type: "compositioncommit", data: "", key: { key: "KEY_Enter" } });
is(result.compositionupdate, true, "runCompositionCommitTest: compositionupdate should be fired after dispatching compositioncommit #4");
is(result.compositionend, true, "runCompositionCommitTest: compositionend should be fired after dispatching compositioncommit #4");
is(result.text, true, "runCompositionCommitTest: text should be fired after dispatching compositioncommit #4");
is(result.input, true, "runCompositionCommitTest: input should be fired after dispatching compositioncommit #4");
is(textarea.value, "", "runCompositionCommitTest: textarea should be empty #4");
// compositioncommit immediately without compositionstart
textarea.value = "";
clearResult();
- synthesizeComposition({ type: "compositioncommit", data: "\u3042" });
+ synthesizeComposition({ type: "compositioncommit", data: "\u3042", key: { key: "a" } });
is(result.compositionupdate, true, "runCompositionCommitTest: compositionupdate should be fired after dispatching compositioncommit #5");
is(result.compositionend, true, "runCompositionCommitTest: compositionend should be fired after dispatching compositioncommit #5");
is(result.text, true, "runCompositionCommitTest: text should be fired after dispatching compositioncommit #5");
is(result.input, true, "runCompositionCommitTest: input should be fired after dispatching compositioncommit #5");
is(textarea.value, "\u3042", "runCompositionCommitTest: textarea should be empty #5");
// compositioncommit with same composition string.
@@ -902,22 +926,23 @@ function runCompositionCommitTest()
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3042",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "a" },
});
is(textarea.value, "\u3042", "runCompositionCommitTest: textarea doesn't have composition string #5");
clearResult();
- synthesizeComposition({ type: "compositioncommit", data: "\u3042" });
+ synthesizeComposition({ type: "compositioncommit", data: "\u3042", key: { key: "KEY_Enter" } });
is(result.compositionupdate, false, "runCompositionCommitTest: compositionupdate shouldn't be fired after dispatching compositioncommit #5");
is(result.compositionend, true, "runCompositionCommitTest: compositionend should be fired after dispatching compositioncommit #5");
is(result.text, true, "runCompositionCommitTest: text should be fired after dispatching compositioncommit because there was composition string #5");
is(result.input, true, "runCompositionCommitTest: input should be fired after dispatching compositioncommit #5");
is(textarea.value, "\u3042", "runCompositionCommitTest: textarea should have committed string #5");
// compositioncommit with same composition string when there is committed string
@@ -925,34 +950,36 @@ function runCompositionCommitTest()
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3042",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "a" },
});
is(textarea.value, "\u3042", "runCompositionCommitTest: textarea doesn't have composition string #6");
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3042",
"clauses":
[
{ "length": 0, "attr": 0 }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "KEY_Enter", type: "keydown" },
});
is(textarea.value, "\u3042", "runCompositionCommitTest: textarea doesn't have composition string #6");
clearResult();
- synthesizeComposition({ type: "compositioncommit", data: "\u3042" });
+ synthesizeComposition({ type: "compositioncommit", data: "\u3042", key: { key: "KEY_Enter", type: "keyup" } });
is(result.compositionupdate, false, "runCompositionCommitTest: compositionupdate shouldn't be fired after dispatching compositioncommit #6");
is(result.compositionend, true, "runCompositionCommitTest: compositionend should be fired after dispatching compositioncommit #6");
is(result.text, false, "runCompositionCommitTest: text shouldn't be fired after dispatching compositioncommit because there was already committed string #6");
is(result.input, true, "runCompositionCommitTest: input should be fired after dispatching compositioncommit #6");
is(textarea.value, "\u3042", "runCompositionCommitTest: textarea should have committed string #6");
textarea.removeEventListener("compositionupdate", handler, true);
@@ -978,17 +1005,18 @@ function runCompositionTest()
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3089",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "o" },
});
if (!checkContent("\u3089", "runCompositionTest", "#1-1") ||
!checkSelection(1, "", "runCompositionTest", "#1-1")) {
return;
}
caretRect = synthesizeQueryCaretRect(1);
@@ -1002,17 +1030,18 @@ function runCompositionTest()
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3089\u30FC",
"clauses":
[
{ "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 2, "length": 0 }
+ "caret": { "start": 2, "length": 0 },
+ "key": { key: "\\", code: "IntlYen", keyCode: KeyboardEvent.DOM_VK_BACKSLASH },
});
if (!checkContent("\u3089\u30FC", "runCompositionTest", "#1-2") ||
!checkSelection(2, "", "runCompositionTest", "#1-2")) {
return;
}
caretRect = synthesizeQueryCaretRect(2);
@@ -1035,17 +1064,18 @@ function runCompositionTest()
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3089\u30FC\u3081",
"clauses":
[
{ "length": 3, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 3, "length": 0 }
+ "caret": { "start": 3, "length": 0 },
+ "key": { key: "/" },
});
if (!checkContent("\u3089\u30FC\u3081", "runCompositionTest", "#1-3") ||
!checkSelection(3, "", "runCompositionTest", "#1-3")) {
return;
}
caretRect = synthesizeQueryCaretRect(3);
@@ -1068,17 +1098,18 @@ function runCompositionTest()
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3089\u30FC\u3081",
"clauses":
[
{ "length": 3, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 2, "length": 0 }
+ "caret": { "start": 2, "length": 0 },
+ "key": { key: "KEY_ArrowLeft" },
});
if (!checkContent("\u3089\u30FC\u3081", "runCompositionTest", "#1-3-1") ||
!checkSelection(2, "", "runCompositionTest", "#1-3-1")) {
return;
}
@@ -1102,17 +1133,18 @@ function runCompositionTest()
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3089\u30FC\u3081",
"clauses":
[
{ "length": 3, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "KEY_ArrowLeft" },
});
if (!checkContent("\u3089\u30FC\u3081", "runCompositionTest", "#1-3-2") ||
!checkSelection(1, "", "runCompositionTest", "#1-3-2")) {
return;
}
@@ -1135,17 +1167,18 @@ function runCompositionTest()
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3089\u30FC\u3081\u3093",
"clauses":
[
{ "length": 4, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 4, "length": 0 }
+ "caret": { "start": 4, "length": 0 },
+ "key": { key: "y" },
});
if (!checkContent("\u3089\u30FC\u3081\u3093", "runCompositionTest", "#1-4") ||
!checkSelection(4, "", "runCompositionTest", "#1-4")) {
return;
}
@@ -1153,98 +1186,104 @@ function runCompositionTest()
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3089\u30FC\u3081",
"clauses":
[
{ "length": 3, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 3, "length": 0 }
+ "caret": { "start": 3, "length": 0 },
+ "key": { key: "KEY_Backspace" },
});
if (!checkContent("\u3089\u30FC\u3081", "runCompositionTest", "#1-5") ||
!checkSelection(3, "", "runCompositionTest", "#1-5")) {
return;
}
// re-input
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3089\u30FC\u3081\u3093",
"clauses":
[
{ "length": 4, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 4, "length": 0 }
+ "caret": { "start": 4, "length": 0 },
+ "key": { key: "y" },
});
if (!checkContent("\u3089\u30FC\u3081\u3093", "runCompositionTest", "#1-6") ||
!checkSelection(4, "", "runCompositionTest", "#1-6")) {
return;
}
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3089\u30FC\u3081\u3093\u3055",
"clauses":
[
{ "length": 5, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 5, "length": 0 }
+ "caret": { "start": 5, "length": 0 },
+ "key": { key: "x" },
});
if (!checkContent("\u3089\u30FC\u3081\u3093\u3055", "runCompositionTest", "#1-7") ||
!checkSelection(5, "", "runCompositionTest", "#1-7")) {
return;
}
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3089\u30FC\u3081\u3093\u3055\u3044",
"clauses":
[
{ "length": 6, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 6, "length": 0 }
+ "caret": { "start": 6, "length": 0 },
+ "key": { key: "e" },
});
if (!checkContent("\u3089\u30FC\u3081\u3093\u3055\u3044", "runCompositionTest", "#1-8") ||
!checkSelection(6, "", "runCompositionTest", "#1-8")) {
return;
}
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3089\u30FC\u3081\u3093\u3055\u3044\u3053",
"clauses":
[
{ "length": 7, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 7, "length": 0 }
+ "caret": { "start": 7, "length": 0 },
+ "key": { key: "b" },
});
if (!checkContent("\u3089\u30FC\u3081\u3093\u3055\u3044\u3053", "runCompositionTest", "#1-8") ||
!checkSelection(7, "", "runCompositionTest", "#1-8")) {
return;
}
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3089\u30FC\u3081\u3093\u3055\u3044\u3053\u3046",
"clauses":
[
{ "length": 8, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 8, "length": 0 }
+ "caret": { "start": 8, "length": 0 },
+ "key": { key: "4" },
});
if (!checkContent("\u3089\u30FC\u3081\u3093\u3055\u3044\u3053\u3046",
"runCompositionTest", "#1-9") ||
!checkSelection(8, "", "runCompositionTest", "#1-9")) {
return;
}
@@ -1255,17 +1294,18 @@ function runCompositionTest()
"clauses":
[
{ "length": 4,
"attr": COMPOSITION_ATTR_SELECTED_CLAUSE },
{ "length": 2,
"attr": COMPOSITION_ATTR_CONVERTED_CLAUSE }
]
},
- "caret": { "start": 4, "length": 0 }
+ "caret": { "start": 4, "length": 0 },
+ "key": { key: " " },
});
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8",
"runCompositionTest", "#1-10") ||
!checkSelection(4, "", "runCompositionTest", "#1-10")) {
return;
}
@@ -1276,17 +1316,18 @@ function runCompositionTest()
"clauses":
[
{ "length": 4,
"attr": COMPOSITION_ATTR_CONVERTED_CLAUSE },
{ "length": 2,
"attr": COMPOSITION_ATTR_SELECTED_CLAUSE }
]
},
- "caret": { "start": 6, "length": 0 }
+ "caret": { "start": 6, "length": 0 },
+ "key": { key: "KEY_ArrowLeft", shiftKey: true },
});
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8",
"runCompositionTest", "#1-11") ||
!checkSelection(6, "", "runCompositionTest", "#1-11")) {
return;
}
@@ -1297,17 +1338,18 @@ function runCompositionTest()
"clauses":
[
{ "length": 5,
"attr": COMPOSITION_ATTR_SELECTED_CLAUSE },
{ "length": 3,
"attr": COMPOSITION_ATTR_CONVERTED_CLAUSE }
]
},
- "caret": { "start": 5, "length": 0 }
+ "caret": { "start": 5, "length": 0 },
+ "key": { key: "KEY_ArrowRight" },
});
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046",
"runCompositionTest", "#1-12") ||
!checkSelection(5, "", "runCompositionTest", "#1-12")) {
return;
}
@@ -1347,78 +1389,82 @@ function runCompositionTest()
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3057",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "d" },
});
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046\u3057",
"runCompositionTest", "#2-1") ||
!checkSelection(8 + 1, "", "runCompositionTest", "#2-1")) {
return;
}
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3058",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "r" },
});
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046\u3058",
"runCompositionTest", "#2-2") ||
!checkSelection(8 + 1, "", "runCompositionTest", "#2-2")) {
return;
}
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3058\u3087",
"clauses":
[
{ "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 2, "length": 0 }
+ "caret": { "start": 2, "length": 0 },
+ "key": { key: ")", code: "Digit9", keyCode: KeyboardEvent.DOM_VK_9, shiftKey: true },
});
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046\u3058\u3087",
"runCompositionTest", "#2-3") ||
!checkSelection(8 + 2, "", "runCompositionTest", "#2-3")) {
return;
}
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3058\u3087\u3046",
"clauses":
[
{ "length": 3, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 3, "length": 0 }
+ "caret": { "start": 3, "length": 0 },
+ "key": { key: "4" },
});
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046\u3058\u3087\u3046",
"runCompositionTest", "#2-4") ||
!checkSelection(8 + 3, "", "runCompositionTest", "#2-4")) {
return;
}
// commit the composition string
- synthesizeComposition({ type: "compositioncommitasis" });
+ synthesizeComposition({ type: "compositioncommitasis", key: { key: "KEY_Enter" } });
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046\u3058\u3087\u3046",
"runCompositionTest", "#2-4") ||
!checkSelection(8 + 3, "", "runCompositionTest", "#2-4")) {
return;
}
// set selection
@@ -1433,17 +1479,18 @@ function runCompositionTest()
synthesizeCompositionChange(
{ "composition":
{ "string": "\u304A",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "6" },
});
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u304A",
"runCompositionTest", "#3-2") ||
!checkSelection(4 + 1, "", "runCompositionTest", "#3-2")) {
return;
}
@@ -1451,17 +1498,18 @@ function runCompositionTest()
synthesizeCompositionChange(
{ "composition":
{ "string": "",
"clauses":
[
{ "length": 0, "attr": 0 }
]
},
- "caret": { "start": 0, "length": 0 }
+ "caret": { "start": 0, "length": 0 },
+ "key": { key: "KEY_Backspace" },
});
if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
"runCompositionTest", "#3-3") ||
!checkSelection(4, "", "runCompositionTest", "#3-3")) {
return;
}
@@ -1469,27 +1517,28 @@ function runCompositionTest()
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3046",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "4" },
});
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3046",
"runCompositionTest", "#3-4") ||
!checkSelection(4 + 1, "", "runCompositionTest", "#3-4")) {
return;
}
// cancel the composition
- synthesizeComposition({ type: "compositioncommit", data: "" });
+ synthesizeComposition({ type: "compositioncommit", data: "", key: { key: "KEY_Escape" } });
if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
"runCompositionTest", "#3-5") ||
!checkSelection(4, "", "runCompositionTest", "#3-5")) {
return;
}
// bug 271815, some Chinese IMEs for Linux make empty composition string
@@ -1498,68 +1547,71 @@ function runCompositionTest()
synthesizeCompositionChange(
{ "composition":
{ "string": "",
"clauses":
[
{ "length": 0, "attr": 0 }
]
},
- "caret": { "start": 0, "length": 0 }
+ "caret": { "start": 0, "length": 0 },
+ "key": { key: "a" },
});
if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
"runCompositionTest", "#4-1") ||
!checkSelection(4, "", "runCompositionTest", "#4-1")) {
return;
}
synthesizeCompositionChange(
{ "composition":
{ "string": "",
"clauses":
[
{ "length": 0, "attr": 0 }
]
},
- "caret": { "start": 0, "length": 0 }
+ "caret": { "start": 0, "length": 0 },
+ "key": { key: "b" },
});
if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
"runCompositionTest", "#4-2") ||
!checkSelection(4, "", "runCompositionTest", "#4-2")) {
return;
}
- synthesizeComposition({ type: "compositioncommit", data: "\u6700" });
+ synthesizeComposition({ type: "compositioncommit", data: "\u6700", key: { key: "KEY_Enter" } });
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700",
"runCompositionTest", "#4-3") ||
!checkSelection(5, "", "runCompositionTest", "#4-3")) {
return;
}
// testing the canceling case
synthesizeCompositionChange(
{ "composition":
{ "string": "",
"clauses":
[
{ "length": 0, "attr": 0 }
]
},
- "caret": { "start": 0, "length": 0 }
+ "caret": { "start": 0, "length": 0 },
+ "key": { key: "a" },
});
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700",
"runCompositionTest", "#4-5") ||
!checkSelection(5, "", "runCompositionTest", "#4-5")) {
return;
}
- synthesizeComposition({ type: "compositioncommitasis" });
+ synthesizeComposition({ type: "compositioncommitasis", key: { key: "KEY_Escape" } });
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700",
"runCompositionTest", "#4-6") ||
!checkSelection(5, "", "runCompositionTest", "#4-6")) {
return;
}
// testing whether the empty composition string deletes selected string.
@@ -1568,26 +1620,27 @@ function runCompositionTest()
synthesizeCompositionChange(
{ "composition":
{ "string": "",
"clauses":
[
{ "length": 0, "attr": 0 }
]
},
- "caret": { "start": 0, "length": 0 }
+ "caret": { "start": 0, "length": 0 },
+ "key": { key: "a" },
});
if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
"runCompositionTest", "#4-8") ||
!checkSelection(4, "", "runCompositionTest", "#4-8")) {
return;
}
- synthesizeComposition({ type: "compositioncommit", data: "\u9AD8" });
+ synthesizeComposition({ type: "compositioncommit", data: "\u9AD8", key: { key: "KEY_Enter" } });
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u9AD8",
"runCompositionTest", "#4-9") ||
!checkSelection(5, "", "runCompositionTest", "#4-9")) {
return;
}
synthesizeKey("KEY_Backspace");
if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
@@ -1601,85 +1654,87 @@ function runCompositionTest()
synthesizeCompositionChange(
{ "composition":
{ "string": "\u6700",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "a" },
});
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700",
"runCompositionTest", "#5-1") ||
!checkSelection(4 + 1, "", "runCompositionTest", "#5-1")) {
return;
}
synthesizeCompositionChange(
{ "composition":
{ "string": "",
"clauses":
[
{ "length": 0, "attr": 0 }
]
},
- "caret": { "start": 0, "length": 0 }
+ "caret": { "start": 0, "length": 0 },
+ "key": { key: "KEY_Backspace", type: "keydown" },
});
if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
"runCompositionTest", "#5-2") ||
!checkSelection(4, "", "runCompositionTest", "#5-2")) {
return;
}
- synthesizeComposition({ type: "compositioncommitasis" });
+ synthesizeComposition({ type: "compositioncommitasis", key: { key: "KEY_Backspace", type: "keyup" } });
if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
"runCompositionTest", "#5-3") ||
!checkSelection(4, "", "runCompositionTest", "#5-3")) {
return;
}
// Undo tests for the testcases for bug 23558 and bug 271815
- synthesizeKey("Z", { accelKey: true });
+ synthesizeKey("z", { accelKey: true });
// XXX this is unexpected behavior, see bug 258291
if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
"runCompositionTest", "#6-1") ||
!checkSelection(4, "", "runCompositionTest", "#6-1")) {
return;
}
- synthesizeKey("Z", { accelKey: true });
+ synthesizeKey("z", { accelKey: true });
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u9AD8",
"runCompositionTest", "#6-2") ||
!checkSelection(5, "", "runCompositionTest", "#6-2")) {
return;
}
- synthesizeKey("Z", { accelKey: true });
+ synthesizeKey("z", { accelKey: true });
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700",
"runCompositionTest", "#6-3") ||
!checkSelection(4, "\u6700", "runCompositionTest", "#6-3")) {
return;
}
- synthesizeKey("Z", { accelKey: true });
+ synthesizeKey("z", { accelKey: true });
// XXX this is unexpected behavior, see bug 258291
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700",
"runCompositionTest", "#6-4") ||
!checkSelection(5, "", "runCompositionTest", "#6-4")) {
return;
}
- synthesizeKey("Z", { accelKey: true });
+ synthesizeKey("z", { accelKey: true });
if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
"runCompositionTest", "#6-5") ||
!checkSelection(4, "", "runCompositionTest", "#6-5")) {
return;
}
}
@@ -1772,17 +1827,18 @@ function runCompositionEventTest()
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3089",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "o" },
});
is(windowEventCounts["compositionstart"], 1,
kDescription + "compositionstart hasn't been handled by window #1");
is(windowEventData["compositionstart"], "",
kDescription + "data of compositionstart isn't empty (window) #1");
is(windowEventLocale["compositionstart"], "",
kDescription + "locale of compositionstart isn't empty (window) #1");
@@ -1823,17 +1879,18 @@ function runCompositionEventTest()
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3089\u30FC",
"clauses":
[
{ "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 2, "length": 0 }
+ "caret": { "start": 2, "length": 0 },
+ "key": { key: "\\", code: "IntlYen", keyCode: KeyboardEvent.DOM_VK_BACKSLASH },
});
is(windowEventCounts["compositionstart"], 1,
kDescription + "compositionstart has been handled more than once by window #2");
is(inputEventCounts["compositionstart"], 1,
kDescription + "compositionstart has been handled more than once by input #2");
is(windowEventCounts["compositionupdate"], 2,
@@ -1859,17 +1916,17 @@ function runCompositionEventTest()
is(windowEventData["input"], "\u3089\u30FC",
kDescription + "value of input element wasn't modified (window) #2");
is(inputEventCounts["input"], 2,
kDescription + "input hasn't been handled by input #2");
is(inputEventData["input"], "\u3089\u30FC",
kDescription + "value of input element wasn't modified (input) #2");
// text event shouldn't cause composition update, e.g., at committing.
- synthesizeComposition({ type: "compositioncommitasis" });
+ synthesizeComposition({ type: "compositioncommitasis", key: { key: "KEY_Enter" } });
is(windowEventCounts["compositionstart"], 1,
kDescription + "compositionstart has been handled more than once by window #3");
is(inputEventCounts["compositionstart"], 1,
kDescription + "compositionstart has been handled more than once by input #3");
is(windowEventCounts["compositionupdate"], 2,
kDescription + "compositionupdate has been fired unexpectedly on window #3");
@@ -1906,20 +1963,21 @@ function runCompositionEventTest()
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3089",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "o" },
});
- synthesizeComposition({ type: "compositioncommitasis" });
+ synthesizeComposition({ type: "compositioncommitasis", key: { key: "KEY_Enter" } });
is(windowEventCounts["compositionstart"], 1,
kDescription + "compositionstart hasn't been handled by window #4");
is(windowEventData["compositionstart"], "\u30FC",
kDescription + "data of compositionstart is empty (window) #4");
is(windowEventLocale["compositionstart"], "",
kDescription + "locale of compositionstart isn't empty (window) #4");
is(inputEventCounts["compositionstart"], 1,
@@ -1963,27 +2021,28 @@ function runCompositionEventTest()
kDescription + "input hasn't been handled by input #4");
is(inputEventData["input"], "\u3089\u3089",
kDescription + "value of input element wasn't modified (input) #4");
// preventDefault() should effect nothing.
preventDefault = true;
initResults();
- synthesizeKey("A", { accelKey: true }); // Select All
+ synthesizeKey("a", { accelKey: true }); // Select All
synthesizeCompositionChange(
{ "composition":
{ "string": "\u306D",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "," },
});
synthesizeComposition({ type: "compositioncommitasis" });
is(windowEventCounts["compositionstart"], 1,
kDescription + "compositionstart hasn't been handled by window #5");
is(windowEventData["compositionstart"], "\u3089\u3089",
kDescription + "data of compositionstart is empty (window) #5");
@@ -2032,30 +2091,31 @@ function runCompositionEventTest()
kDescription + "value of input element wasn't modified (input) #5");
prevnetDefault = false;
// stopPropagation() should effect nothing (except event count)
stopPropagation = true;
initResults();
- synthesizeKey("A", { accelKey: true }); // Select All
+ synthesizeKey("a", { accelKey: true }); // Select All
synthesizeCompositionChange(
{ "composition":
{ "string": "\u306E",
"clauses":
[
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
]
},
- "caret": { "start": 1, "length": 0 }
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "\\", code: "IntlRo", keyCode: KeyboardEvent.DOM_VK_BACKSLASH },
});
- synthesizeComposition({ type: "compositioncommitasis" });
+ synthesizeComposition({ type: "compositioncommitasis", key: { key: "KEY_Enter" } });
is(windowEventCounts["compositionstart"], 1,
kDescription + "compositionstart hasn't been handled by window #6");
is(windowEventData["compositionstart"], "\u306D",
kDescription + "data of compositionstart is empty #6");
is(windowEventLocale["compositionstart"], "",
kDescription + "locale of compositionstart isn't empty #6");
is(inputEventCounts["compositionstart"], 0,
@@ -2089,17 +2149,17 @@ function runCompositionEventTest()
kDescription + "value of input element wasn't modified (input) #6");
stopPropagation = false;
// create event and dispatch it.
initResults();
input.value = "value of input";
- synthesizeKey("A", { accelKey: true }); // Select All
+ synthesizeKey("a", { accelKey: true }); // Select All
var compositionstart = document.createEvent("CompositionEvent");
compositionstart.initCompositionEvent("compositionstart",
true, true, document.defaultView,
"start data", "start locale");
is(compositionstart.type, "compositionstart",
kDescription + "type doesn't match #7");
is(compositionstart.data, "start data",