Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 /**
6 * EventUtils provides some utility methods for creating and sending DOM events.
7 * Current methods:
8 * sendMouseEvent
9 * sendChar
10 * sendString
11 * sendKey
12 * synthesizeMouse
13 * synthesizeMouseAtCenter
14 * synthesizeMouseScroll
15 * synthesizeKey
16 * synthesizeMouseExpectEvent
17 * synthesizeKeyExpectEvent
18 *
19 * When adding methods to this file, please add a performance test for it.
20 */
22 /**
23 * Send a mouse event to the node aTarget (aTarget can be an id, or an
24 * actual node) . The "event" passed in to aEvent is just a JavaScript
25 * object with the properties set that the real mouse event object should
26 * have. This includes the type of the mouse event.
27 * E.g. to send an click event to the node with id 'node' you might do this:
28 *
29 * sendMouseEvent({type:'click'}, 'node');
30 */
31 function getElement(id) {
32 return ((typeof(id) == "string") ?
33 document.getElementById(id) : id);
34 };
36 this.$ = this.getElement;
37 const KeyEvent = Components.interfaces.nsIDOMKeyEvent;
39 function sendMouseEvent(aEvent, aTarget, aWindow) {
40 if (['click', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mouseout'].indexOf(aEvent.type) == -1) {
41 throw new Error("sendMouseEvent doesn't know about event type '" + aEvent.type + "'");
42 }
44 if (!aWindow) {
45 aWindow = window;
46 }
48 if (!(aTarget instanceof Element)) {
49 aTarget = aWindow.document.getElementById(aTarget);
50 }
52 var event = aWindow.document.createEvent('MouseEvent');
54 var typeArg = aEvent.type;
55 var canBubbleArg = true;
56 var cancelableArg = true;
57 var viewArg = aWindow;
58 var detailArg = aEvent.detail || (aEvent.type == 'click' ||
59 aEvent.type == 'mousedown' ||
60 aEvent.type == 'mouseup' ? 1 :
61 aEvent.type == 'dblclick'? 2 : 0);
62 var screenXArg = aEvent.screenX || 0;
63 var screenYArg = aEvent.screenY || 0;
64 var clientXArg = aEvent.clientX || 0;
65 var clientYArg = aEvent.clientY || 0;
66 var ctrlKeyArg = aEvent.ctrlKey || false;
67 var altKeyArg = aEvent.altKey || false;
68 var shiftKeyArg = aEvent.shiftKey || false;
69 var metaKeyArg = aEvent.metaKey || false;
70 var buttonArg = aEvent.button || 0;
71 var relatedTargetArg = aEvent.relatedTarget || null;
73 event.initMouseEvent(typeArg, canBubbleArg, cancelableArg, viewArg, detailArg,
74 screenXArg, screenYArg, clientXArg, clientYArg,
75 ctrlKeyArg, altKeyArg, shiftKeyArg, metaKeyArg,
76 buttonArg, relatedTargetArg);
78 //removed: SpecialPowers.dispatchEvent(aWindow, aTarget, event);
79 }
81 /**
82 * Send the char aChar to the focused element. This method handles casing of
83 * chars (sends the right charcode, and sends a shift key for uppercase chars).
84 * No other modifiers are handled at this point.
85 *
86 * For now this method only works for English letters (lower and upper case)
87 * and the digits 0-9.
88 */
89 function sendChar(aChar, aWindow) {
90 // DOM event charcodes match ASCII (JS charcodes) for a-zA-Z0-9.
91 var hasShift = (aChar == aChar.toUpperCase());
92 synthesizeKey(aChar, { shiftKey: hasShift }, aWindow);
93 }
95 /**
96 * Send the string aStr to the focused element.
97 *
98 * For now this method only works for English letters (lower and upper case)
99 * and the digits 0-9.
100 */
101 function sendString(aStr, aWindow) {
102 for (var i = 0; i < aStr.length; ++i) {
103 sendChar(aStr.charAt(i), aWindow);
104 }
105 }
107 /**
108 * Send the non-character key aKey to the focused node.
109 * The name of the key should be the part that comes after "DOM_VK_" in the
110 * KeyEvent constant name for this key.
111 * No modifiers are handled at this point.
112 */
113 function sendKey(aKey, aWindow) {
114 var keyName = "VK_" + aKey.toUpperCase();
115 synthesizeKey(keyName, { shiftKey: false }, aWindow);
116 }
118 /**
119 * Parse the key modifier flags from aEvent. Used to share code between
120 * synthesizeMouse and synthesizeKey.
121 */
122 function _parseModifiers(aEvent)
123 {
124 const masks = Components.interfaces.nsIDOMNSEvent;
125 var mval = 0;
126 if (aEvent.shiftKey)
127 mval |= masks.SHIFT_MASK;
128 if (aEvent.ctrlKey)
129 mval |= masks.CONTROL_MASK;
130 if (aEvent.altKey)
131 mval |= masks.ALT_MASK;
132 if (aEvent.metaKey)
133 mval |= masks.META_MASK;
134 if (aEvent.accelKey)
135 mval |= (navigator.platform.indexOf("Mac") >= 0) ? masks.META_MASK :
136 masks.CONTROL_MASK;
138 return mval;
139 }
141 /**
142 * Synthesize a mouse event on a target. The actual client point is determined
143 * by taking the aTarget's client box and offseting it by aOffsetX and
144 * aOffsetY. This allows mouse clicks to be simulated by calling this method.
145 *
146 * aEvent is an object which may contain the properties:
147 * shiftKey, ctrlKey, altKey, metaKey, accessKey, clickCount, button, type
148 *
149 * If the type is specified, an mouse event of that type is fired. Otherwise,
150 * a mousedown followed by a mouse up is performed.
151 *
152 * aWindow is optional, and defaults to the current window object.
153 */
154 function synthesizeMouse(aTarget, aOffsetX, aOffsetY, aEvent, aWindow)
155 {
156 var rect = aTarget.getBoundingClientRect();
157 synthesizeMouseAtPoint(rect.left + aOffsetX, rect.top + aOffsetY,
158 aEvent, aWindow);
159 }
161 /*
162 * Synthesize a mouse event at a particular point in aWindow.
163 *
164 * aEvent is an object which may contain the properties:
165 * shiftKey, ctrlKey, altKey, metaKey, accessKey, clickCount, button, type
166 *
167 * If the type is specified, an mouse event of that type is fired. Otherwise,
168 * a mousedown followed by a mouse up is performed.
169 *
170 * aWindow is optional, and defaults to the current window object.
171 */
172 function synthesizeMouseAtPoint(left, top, aEvent, aWindow)
173 {
174 var utils = _getDOMWindowUtils(aWindow);
176 if (utils) {
177 var button = aEvent.button || 0;
178 var clickCount = aEvent.clickCount || 1;
179 var modifiers = _parseModifiers(aEvent);
181 if (("type" in aEvent) && aEvent.type) {
182 utils.sendMouseEvent(aEvent.type, left, top, button, clickCount, modifiers);
183 }
184 else {
185 utils.sendMouseEvent("mousedown", left, top, button, clickCount, modifiers);
186 utils.sendMouseEvent("mouseup", left, top, button, clickCount, modifiers);
187 }
188 }
189 }
191 // Call synthesizeMouse with coordinates at the center of aTarget.
192 function synthesizeMouseAtCenter(aTarget, aEvent, aWindow)
193 {
194 var rect = aTarget.getBoundingClientRect();
195 synthesizeMouse(aTarget, rect.width / 2, rect.height / 2, aEvent,
196 aWindow);
197 }
199 /**
200 * Synthesize a mouse scroll event on a target. The actual client point is determined
201 * by taking the aTarget's client box and offseting it by aOffsetX and
202 * aOffsetY.
203 *
204 * aEvent is an object which may contain the properties:
205 * shiftKey, ctrlKey, altKey, metaKey, accessKey, button, type, axis, delta, hasPixels
206 *
207 * If the type is specified, a mouse scroll event of that type is fired. Otherwise,
208 * "DOMMouseScroll" is used.
209 *
210 * If the axis is specified, it must be one of "horizontal" or "vertical". If not specified,
211 * "vertical" is used.
212 *
213 * 'delta' is the amount to scroll by (can be positive or negative). It must
214 * be specified.
215 *
216 * 'hasPixels' specifies whether kHasPixels should be set in the scrollFlags.
217 *
218 * 'isMomentum' specifies whether kIsMomentum should be set in the scrollFlags.
219 *
220 * aWindow is optional, and defaults to the current window object.
221 */
222 function synthesizeMouseScroll(aTarget, aOffsetX, aOffsetY, aEvent, aWindow)
223 {
224 var utils = _getDOMWindowUtils(aWindow);
226 if (utils) {
227 // See nsMouseScrollFlags in nsGUIEvent.h
228 const kIsVertical = 0x02;
229 const kIsHorizontal = 0x04;
230 const kHasPixels = 0x08;
231 const kIsMomentum = 0x40;
233 var button = aEvent.button || 0;
234 var modifiers = _parseModifiers(aEvent);
236 var rect = aTarget.getBoundingClientRect();
238 var left = rect.left;
239 var top = rect.top;
241 var type = (("type" in aEvent) && aEvent.type) || "DOMMouseScroll";
242 var axis = aEvent.axis || "vertical";
243 var scrollFlags = (axis == "horizontal") ? kIsHorizontal : kIsVertical;
244 if (aEvent.hasPixels) {
245 scrollFlags |= kHasPixels;
246 }
247 if (aEvent.isMomentum) {
248 scrollFlags |= kIsMomentum;
249 }
250 utils.sendMouseScrollEvent(type, left + aOffsetX, top + aOffsetY, button,
251 scrollFlags, aEvent.delta, modifiers);
252 }
253 }
255 function _computeKeyCodeFromChar(aChar)
256 {
257 if (aChar.length != 1) {
258 return 0;
259 }
260 const nsIDOMKeyEvent = Components.interfaces.nsIDOMKeyEvent;
261 if (aChar >= 'a' && aChar <= 'z') {
262 return nsIDOMKeyEvent.DOM_VK_A + aChar.charCodeAt(0) - 'a'.charCodeAt(0);
263 }
264 if (aChar >= 'A' && aChar <= 'Z') {
265 return nsIDOMKeyEvent.DOM_VK_A + aChar.charCodeAt(0) - 'A'.charCodeAt(0);
266 }
267 if (aChar >= '0' && aChar <= '9') {
268 return nsIDOMKeyEvent.DOM_VK_0 + aChar.charCodeAt(0) - '0'.charCodeAt(0);
269 }
270 // returns US keyboard layout's keycode
271 switch (aChar) {
272 case '~':
273 case '`':
274 return nsIDOMKeyEvent.DOM_VK_BACK_QUOTE;
275 case '!':
276 return nsIDOMKeyEvent.DOM_VK_1;
277 case '@':
278 return nsIDOMKeyEvent.DOM_VK_2;
279 case '#':
280 return nsIDOMKeyEvent.DOM_VK_3;
281 case '$':
282 return nsIDOMKeyEvent.DOM_VK_4;
283 case '%':
284 return nsIDOMKeyEvent.DOM_VK_5;
285 case '^':
286 return nsIDOMKeyEvent.DOM_VK_6;
287 case '&':
288 return nsIDOMKeyEvent.DOM_VK_7;
289 case '*':
290 return nsIDOMKeyEvent.DOM_VK_8;
291 case '(':
292 return nsIDOMKeyEvent.DOM_VK_9;
293 case ')':
294 return nsIDOMKeyEvent.DOM_VK_0;
295 case '-':
296 case '_':
297 return nsIDOMKeyEvent.DOM_VK_SUBTRACT;
298 case '+':
299 case '=':
300 return nsIDOMKeyEvent.DOM_VK_EQUALS;
301 case '{':
302 case '[':
303 return nsIDOMKeyEvent.DOM_VK_OPEN_BRACKET;
304 case '}':
305 case ']':
306 return nsIDOMKeyEvent.DOM_VK_CLOSE_BRACKET;
307 case '|':
308 case '\\':
309 return nsIDOMKeyEvent.DOM_VK_BACK_SLASH;
310 case ':':
311 case ';':
312 return nsIDOMKeyEvent.DOM_VK_SEMICOLON;
313 case '\'':
314 case '"':
315 return nsIDOMKeyEvent.DOM_VK_QUOTE;
316 case '<':
317 case ',':
318 return nsIDOMKeyEvent.DOM_VK_COMMA;
319 case '>':
320 case '.':
321 return nsIDOMKeyEvent.DOM_VK_PERIOD;
322 case '?':
323 case '/':
324 return nsIDOMKeyEvent.DOM_VK_SLASH;
325 case '\n':
326 return nsIDOMKeyEvent.DOM_VK_RETURN;
327 default:
328 return 0;
329 }
330 }
332 /**
333 * isKeypressFiredKey() returns TRUE if the given key should cause keypress
334 * event when widget handles the native key event. Otherwise, FALSE.
335 *
336 * aDOMKeyCode should be one of consts of nsIDOMKeyEvent::DOM_VK_*, or a key
337 * name begins with "VK_", or a character.
338 */
339 function isKeypressFiredKey(aDOMKeyCode)
340 {
341 const KeyEvent = Components.interfaces.nsIDOMKeyEvent;
342 if (typeof(aDOMKeyCode) == "string") {
343 if (aDOMKeyCode.indexOf("VK_") == 0) {
344 aDOMKeyCode = KeyEvent["DOM_" + aDOMKeyCode];
345 if (!aDOMKeyCode) {
346 throw "Unknown key: " + aDOMKeyCode;
347 }
348 } else {
349 // If the key generates a character, it must cause a keypress event.
350 return true;
351 }
352 }
353 switch (aDOMKeyCode) {
354 case KeyEvent.DOM_VK_SHIFT:
355 case KeyEvent.DOM_VK_CONTROL:
356 case KeyEvent.DOM_VK_ALT:
357 case KeyEvent.DOM_VK_CAPS_LOCK:
358 case KeyEvent.DOM_VK_NUM_LOCK:
359 case KeyEvent.DOM_VK_SCROLL_LOCK:
360 case KeyEvent.DOM_VK_META:
361 return false;
362 default:
363 return true;
364 }
365 }
367 /**
368 * Synthesize a key event. It is targeted at whatever would be targeted by an
369 * actual keypress by the user, typically the focused element.
370 *
371 * aKey should be either a character or a keycode starting with VK_ such as
372 * VK_RETURN.
373 *
374 * aEvent is an object which may contain the properties:
375 * shiftKey, ctrlKey, altKey, metaKey, accessKey, type
376 *
377 * If the type is specified, a key event of that type is fired. Otherwise,
378 * a keydown, a keypress and then a keyup event are fired in sequence.
379 *
380 * aWindow is optional, and defaults to the current window object.
381 */
382 function synthesizeKey(aKey, aEvent, aWindow)
383 {
384 var utils = _getDOMWindowUtils(aWindow);
385 if (utils) {
386 var keyCode = 0, charCode = 0;
387 if (aKey.indexOf("VK_") == 0) {
388 keyCode = KeyEvent["DOM_" + aKey];
389 if (!keyCode) {
390 throw "Unknown key: " + aKey;
391 }
392 } else {
393 charCode = aKey.charCodeAt(0);
394 keyCode = _computeKeyCodeFromChar(aKey.charAt(0));
395 }
397 var modifiers = _parseModifiers(aEvent);
399 if (!("type" in aEvent) || !aEvent.type) {
400 // Send keydown + (optional) keypress + keyup events.
401 var keyDownDefaultHappened =
402 utils.sendKeyEvent("keydown", keyCode, 0, modifiers);
403 if (isKeypressFiredKey(keyCode)) {
404 utils.sendKeyEvent("keypress", charCode ? 0 : keyCode, charCode,
405 modifiers, !keyDownDefaultHappened);
406 }
407 utils.sendKeyEvent("keyup", keyCode, 0, modifiers);
408 } else if (aEvent.type == "keypress") {
409 // Send standalone keypress event.
410 utils.sendKeyEvent(aEvent.type, charCode ? 0 : keyCode,
411 charCode, modifiers);
412 } else {
413 // Send other standalone event than keypress.
414 utils.sendKeyEvent(aEvent.type, keyCode, 0, modifiers);
415 }
416 }
417 }
419 var _gSeenEvent = false;
421 /**
422 * Indicate that an event with an original target of aExpectedTarget and
423 * a type of aExpectedEvent is expected to be fired, or not expected to
424 * be fired.
425 */
426 function _expectEvent(aExpectedTarget, aExpectedEvent, aTestName)
427 {
428 if (!aExpectedTarget || !aExpectedEvent)
429 return null;
431 _gSeenEvent = false;
433 var type = (aExpectedEvent.charAt(0) == "!") ?
434 aExpectedEvent.substring(1) : aExpectedEvent;
435 var eventHandler = function(event) {
436 var epassed = (!_gSeenEvent && event.originalTarget == aExpectedTarget &&
437 event.type == type);
438 is(epassed, true, aTestName + " " + type + " event target " + (_gSeenEvent ? "twice" : ""));
439 _gSeenEvent = true;
440 };
442 aExpectedTarget.addEventListener(type, eventHandler, false);
443 return eventHandler;
444 }
446 /**
447 * Check if the event was fired or not. The event handler aEventHandler
448 * will be removed.
449 */
450 function _checkExpectedEvent(aExpectedTarget, aExpectedEvent, aEventHandler, aTestName)
451 {
452 if (aEventHandler) {
453 var expectEvent = (aExpectedEvent.charAt(0) != "!");
454 var type = expectEvent ? aExpectedEvent : aExpectedEvent.substring(1);
455 aExpectedTarget.removeEventListener(type, aEventHandler, false);
456 var desc = type + " event";
457 if (!expectEvent)
458 desc += " not";
459 is(_gSeenEvent, expectEvent, aTestName + " " + desc + " fired");
460 }
462 _gSeenEvent = false;
463 }
465 /**
466 * Similar to synthesizeMouse except that a test is performed to see if an
467 * event is fired at the right target as a result.
468 *
469 * aExpectedTarget - the expected originalTarget of the event.
470 * aExpectedEvent - the expected type of the event, such as 'select'.
471 * aTestName - the test name when outputing results
472 *
473 * To test that an event is not fired, use an expected type preceded by an
474 * exclamation mark, such as '!select'. This might be used to test that a
475 * click on a disabled element doesn't fire certain events for instance.
476 *
477 * aWindow is optional, and defaults to the current window object.
478 */
479 function synthesizeMouseExpectEvent(aTarget, aOffsetX, aOffsetY, aEvent,
480 aExpectedTarget, aExpectedEvent, aTestName,
481 aWindow)
482 {
483 var eventHandler = _expectEvent(aExpectedTarget, aExpectedEvent, aTestName);
484 synthesizeMouse(aTarget, aOffsetX, aOffsetY, aEvent, aWindow);
485 _checkExpectedEvent(aExpectedTarget, aExpectedEvent, eventHandler, aTestName);
486 }
488 /**
489 * Similar to synthesizeKey except that a test is performed to see if an
490 * event is fired at the right target as a result.
491 *
492 * aExpectedTarget - the expected originalTarget of the event.
493 * aExpectedEvent - the expected type of the event, such as 'select'.
494 * aTestName - the test name when outputing results
495 *
496 * To test that an event is not fired, use an expected type preceded by an
497 * exclamation mark, such as '!select'.
498 *
499 * aWindow is optional, and defaults to the current window object.
500 */
501 function synthesizeKeyExpectEvent(key, aEvent, aExpectedTarget, aExpectedEvent,
502 aTestName, aWindow)
503 {
504 var eventHandler = _expectEvent(aExpectedTarget, aExpectedEvent, aTestName);
505 synthesizeKey(key, aEvent, aWindow);
506 _checkExpectedEvent(aExpectedTarget, aExpectedEvent, eventHandler, aTestName);
507 }
509 function disableNonTestMouseEvents(aDisable)
510 {
511 var domutils = _getDOMWindowUtils();
512 domutils.disableNonTestMouseEvents(aDisable);
513 }
515 function _getDOMWindowUtils(aWindow)
516 {
517 if (!aWindow) {
518 aWindow = window;
519 }
521 //TODO: this is assuming we are in chrome space
522 return aWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
523 getInterface(Components.interfaces.nsIDOMWindowUtils);
524 }
526 // Must be synchronized with nsIDOMWindowUtils.
527 const COMPOSITION_ATTR_RAWINPUT = 0x02;
528 const COMPOSITION_ATTR_SELECTEDRAWTEXT = 0x03;
529 const COMPOSITION_ATTR_CONVERTEDTEXT = 0x04;
530 const COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT = 0x05;
532 /**
533 * Synthesize a composition event.
534 *
535 * @param aEvent The composition event information. This must
536 * have |type| member. The value must be
537 * "compositionstart", "compositionend" or
538 * "compositionupdate".
539 * And also this may have |data| and |locale| which
540 * would be used for the value of each property of
541 * the composition event. Note that the data would
542 * be ignored if the event type were
543 * "compositionstart".
544 * @param aWindow Optional (If null, current |window| will be used)
545 */
546 function synthesizeComposition(aEvent, aWindow)
547 {
548 var utils = _getDOMWindowUtils(aWindow);
549 if (!utils) {
550 return;
551 }
553 utils.sendCompositionEvent(aEvent.type, aEvent.data ? aEvent.data : "",
554 aEvent.locale ? aEvent.locale : "");
555 }
556 /**
557 * Synthesize a text event.
558 *
559 * @param aEvent The text event's information, this has |composition|
560 * and |caret| members. |composition| has |string| and
561 * |clauses| members. |clauses| must be array object. Each
562 * object has |length| and |attr|. And |caret| has |start| and
563 * |length|. See the following tree image.
564 *
565 * aEvent
566 * +-- composition
567 * | +-- string
568 * | +-- clauses[]
569 * | +-- length
570 * | +-- attr
571 * +-- caret
572 * +-- start
573 * +-- length
574 *
575 * Set the composition string to |composition.string|. Set its
576 * clauses information to the |clauses| array.
577 *
578 * When it's composing, set the each clauses' length to the
579 * |composition.clauses[n].length|. The sum of the all length
580 * values must be same as the length of |composition.string|.
581 * Set nsIDOMWindowUtils.COMPOSITION_ATTR_* to the
582 * |composition.clauses[n].attr|.
583 *
584 * When it's not composing, set 0 to the
585 * |composition.clauses[0].length| and
586 * |composition.clauses[0].attr|.
587 *
588 * Set caret position to the |caret.start|. It's offset from
589 * the start of the composition string. Set caret length to
590 * |caret.length|. If it's larger than 0, it should be wide
591 * caret. However, current nsEditor doesn't support wide
592 * caret, therefore, you should always set 0 now.
593 *
594 * @param aWindow Optional (If null, current |window| will be used)
595 */
596 function synthesizeText(aEvent, aWindow)
597 {
598 var utils = _getDOMWindowUtils(aWindow);
599 if (!utils) {
600 return;
601 }
603 if (!aEvent.composition || !aEvent.composition.clauses ||
604 !aEvent.composition.clauses[0]) {
605 return;
606 }
608 var firstClauseLength = aEvent.composition.clauses[0].length;
609 var firstClauseAttr = aEvent.composition.clauses[0].attr;
610 var secondClauseLength = 0;
611 var secondClauseAttr = 0;
612 var thirdClauseLength = 0;
613 var thirdClauseAttr = 0;
614 if (aEvent.composition.clauses[1]) {
615 secondClauseLength = aEvent.composition.clauses[1].length;
616 secondClauseAttr = aEvent.composition.clauses[1].attr;
617 if (aEvent.composition.clauses[2]) {
618 thirdClauseLength = aEvent.composition.clauses[2].length;
619 thirdClauseAttr = aEvent.composition.clauses[2].attr;
620 }
621 }
623 var caretStart = -1;
624 var caretLength = 0;
625 if (aEvent.caret) {
626 caretStart = aEvent.caret.start;
627 caretLength = aEvent.caret.length;
628 }
630 utils.sendTextEvent(aEvent.composition.string,
631 firstClauseLength, firstClauseAttr,
632 secondClauseLength, secondClauseAttr,
633 thirdClauseLength, thirdClauseAttr,
634 caretStart, caretLength);
635 }
637 /**
638 * Synthesize a query selected text event.
639 *
640 * @param aWindow Optional (If null, current |window| will be used)
641 * @return An nsIQueryContentEventResult object. If this failed,
642 * the result might be null.
643 */
644 function synthesizeQuerySelectedText(aWindow)
645 {
646 var utils = _getDOMWindowUtils(aWindow);
647 if (!utils) {
648 return null;
649 }
651 return utils.sendQueryContentEvent(utils.QUERY_SELECTED_TEXT, 0, 0, 0, 0);
652 }
654 /**
655 * Synthesize a selection set event.
656 *
657 * @param aOffset The character offset. 0 means the first character in the
658 * selection root.
659 * @param aLength The length of the text. If the length is too long,
660 * the extra length is ignored.
661 * @param aReverse If true, the selection is from |aOffset + aLength| to
662 * |aOffset|. Otherwise, from |aOffset| to |aOffset + aLength|.
663 * @param aWindow Optional (If null, current |window| will be used)
664 * @return True, if succeeded. Otherwise false.
665 */
666 function synthesizeSelectionSet(aOffset, aLength, aReverse, aWindow)
667 {
668 var utils = _getDOMWindowUtils(aWindow);
669 if (!utils) {
670 return false;
671 }
672 return utils.sendSelectionSetEvent(aOffset, aLength, aReverse);
673 }