Bug 1245153 - Convert EventUtils.js to a module; r=automatedtester
authorAndreas Tolfsen <ato@mozilla.com>
Wed, 03 Feb 2016 18:47:08 +0000
changeset 321325 fb2e6ed35dec4c9857a62ba128a7777262379794
parent 321324 a95822fe264cb6e4f421efea97ade477a9da28b3
child 321326 e853ad1a013c28160fa7e84b758c8e842371ddd7
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersautomatedtester
bugs1245153
milestone47.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1245153 - Convert EventUtils.js to a module; r=automatedtester testing/marionette/sendkeys.js has been merged into the new testing/marionette/event.js module, together with testing/marionette/EventUtils.js. There is a lot of functionality still left in this module that we can probably remove, as it is not in use by Marionette. MozReview-Commit-ID: GrjNuK9VPjp
testing/marionette/EventUtils.js
testing/marionette/event.js
testing/marionette/sendkeys.js
rename from testing/marionette/EventUtils.js
rename to testing/marionette/event.js
--- a/testing/marionette/EventUtils.js
+++ b/testing/marionette/event.js
@@ -1,673 +1,954 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-/**
- * EventUtils provides some utility methods for creating and sending DOM events.
- * Current methods:
- *  sendMouseEvent
- *  sendChar
- *  sendString
- *  sendKey
- *  synthesizeMouse
- *  synthesizeMouseAtCenter
- *  synthesizeMouseScroll
- *  synthesizeKey
- *  synthesizeMouseExpectEvent
- *  synthesizeKeyExpectEvent
- *
- *  When adding methods to this file, please add a performance test for it.
- */
+// Provides functionality for creating and sending DOM events.
+
+"use strict";
+
+const {interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/Log.jsm");
+const logger = Log.repository.getLogger("Marionette");
+
+Cu.import("chrome://marionette/content/elements.js");
+Cu.import("chrome://marionette/content/error.js");
 
-/**
- * Send a mouse event to the node aTarget (aTarget can be an id, or an
- * actual node) . The "event" passed in to aEvent is just a JavaScript
- * object with the properties set that the real mouse event object should
- * have. This includes the type of the mouse event.
- * E.g. to send an click event to the node with id 'node' you might do this:
- *
- * sendMouseEvent({type:'click'}, 'node');
- */
-function getElement(id) {
-  return ((typeof(id) == "string") ?
-    document.getElementById(id) : id); 
-};   
+this.EXPORTED_SYMBOLS = ["event"];
 
-this.$ = this.getElement;
-const KeyEvent = Components.interfaces.nsIDOMKeyEvent;
+// must be synchronised with nsIDOMWindowUtils
+const COMPOSITION_ATTR_RAWINPUT = 0x02;
+const COMPOSITION_ATTR_SELECTEDRAWTEXT = 0x03;
+const COMPOSITION_ATTR_CONVERTEDTEXT = 0x04;
+const COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT = 0x05;
 
-function sendMouseEvent(aEvent, aTarget, aWindow) {
-  if (['click', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mouseout'].indexOf(aEvent.type) == -1) {
-    throw new Error("sendMouseEvent doesn't know about event type '" + aEvent.type + "'");
+// TODO(ato): Document!
+let seenEvent = false;
+
+function getDOMWindowUtils(win) {
+  if (!win) {
+    win = window;
   }
 
-  if (!aWindow) {
-    aWindow = window;
-  }
+  // this assumes we are operating in chrome space
+  return win.QueryInterface(Ci.nsIInterfaceRequestor)
+      .getInterface(Ci.nsIDOMWindowUtils);
+}
 
-  if (!(aTarget instanceof Element)) {
-    aTarget = aWindow.document.getElementById(aTarget);
-  }
-
-  var event = aWindow.document.createEvent('MouseEvent');
+this.event = {};
 
-  var typeArg          = aEvent.type;
-  var canBubbleArg     = true;
-  var cancelableArg    = true;
-  var viewArg          = aWindow;
-  var detailArg        = aEvent.detail        || (aEvent.type == 'click'     ||
-                                                  aEvent.type == 'mousedown' ||
-                                                  aEvent.type == 'mouseup' ? 1 :
-                                                  aEvent.type == 'dblclick'? 2 : 0);
-  var screenXArg       = aEvent.screenX       || 0;
-  var screenYArg       = aEvent.screenY       || 0;
-  var clientXArg       = aEvent.clientX       || 0;
-  var clientYArg       = aEvent.clientY       || 0;
-  var ctrlKeyArg       = aEvent.ctrlKey       || false;
-  var altKeyArg        = aEvent.altKey        || false;
-  var shiftKeyArg      = aEvent.shiftKey      || false;
-  var metaKeyArg       = aEvent.metaKey       || false;
-  var buttonArg        = aEvent.button        || 0;
-  var relatedTargetArg = aEvent.relatedTarget || null;
+event.MouseEvents = {
+  click: 0,
+  dblclick: 1,
+  mousedown: 2,
+  mouseup: 3,
+  mouseover: 4,
+  mouseout: 5,
+};
 
-  event.initMouseEvent(typeArg, canBubbleArg, cancelableArg, viewArg, detailArg,
-                       screenXArg, screenYArg, clientXArg, clientYArg,
-                       ctrlKeyArg, altKeyArg, shiftKeyArg, metaKeyArg,
-                       buttonArg, relatedTargetArg);
-
-  //removed: SpecialPowers.dispatchEvent(aWindow, aTarget, event);
-}
+event.Modifiers = {
+  shiftKey: 0,
+  ctrlKey: 1,
+  altKey: 2,
+  metaKey: 3,
+};
 
 /**
- * Send the char aChar to the focused element.  This method handles casing of
- * chars (sends the right charcode, and sends a shift key for uppercase chars).
- * No other modifiers are handled at this point.
+ * Sends a mouse event to given target.
  *
- * For now this method only works for English letters (lower and upper case)
- * and the digits 0-9.
- */
-function sendChar(aChar, aWindow) {
-  // DOM event charcodes match ASCII (JS charcodes) for a-zA-Z0-9.
-  var hasShift = (aChar == aChar.toUpperCase());
-  synthesizeKey(aChar, { shiftKey: hasShift }, aWindow);
-}
-
-/**
- * Send the string aStr to the focused element.
+ * @param {nsIDOMMouseEvent} mouseEvent
+ *     Event to send.
+ * @param {(Element|string)} target
+ *     Target of event.  Can either be an Element or the ID of an element.
+ * @param {Window=} window
+ *     Window object.  Defaults to the current window.
  *
- * For now this method only works for English letters (lower and upper case)
- * and the digits 0-9.
+ * @throws {TypeError}
+ *     If the event is unsupported.
  */
-function sendString(aStr, aWindow) {
-  for (var i = 0; i < aStr.length; ++i) {
-    sendChar(aStr.charAt(i), aWindow);
+event.sendMouseEvent = function(mouseEvent, target, window = undefined) {
+  if (event.MouseEvents.hasOwnProperty(mouseEvent.type)) {
+    throw new TypeError("Unsupported event type: " + mouseEvent.type);
+  }
+
+  if (!(target instanceof Element)) {
+    target = window.document.getElementById(target);
   }
-}
+
+  let ev = window.document.createEvent("MouseEvent");
+
+  let type = mouseEvent.type;
+  let view = window;
+
+  let detail = mouseEvent.detail;
+  if (!detail) {
+    if (mouseEvent.type in ["click", "mousedown", "mouseup"]) {
+      detail = 1;
+    } else if (mouseEvent.type == "dblclick") {
+      detail = 2;
+    } else {
+      detail = 0;
+    }
+  }
 
-/**
- * Send the non-character key aKey to the focused node.
- * The name of the key should be the part that comes after "DOM_VK_" in the
- *   KeyEvent constant name for this key.
- * No modifiers are handled at this point.
- */
-function sendKey(aKey, aWindow) {
-  var keyName = "VK_" + aKey.toUpperCase();
-  synthesizeKey(keyName, { shiftKey: false }, aWindow);
-}
+  let screenX = mouseEvent.screenX || 0;
+  let screenY = mouseEvent.screenY || 0;
+  let clientX = mouseEvent.clientX || 0;
+  let clientY = mouseEvent.clientY || 0;
+  let ctrlKey = mouseEvent.ctrlKey || false;
+  let altKey = mouseEvent.altKey || false;
+  let shiftKey = mouseEvent.shiftKey || false;
+  let metaKey = mouseEvent.metaKey || false;
+  let button = mouseEvent.button || 0;
+  let relatedTarget = mouseEvent.relatedTarget || null;
+
+  ev.initMouseEvent(
+      mouseEvent.type,
+      /* canBubble */ true,
+      /* cancelable */ true,
+      view,
+      detail,
+      screenX,
+      screenY,
+      clientX,
+      clientY,
+      ctrlKey,
+      altKey,
+      shiftKey,
+      metaKey,
+      button,
+      relatedTarget);
+};
 
 /**
- * Parse the key modifier flags from aEvent. Used to share code between
- * synthesizeMouse and synthesizeKey.
+ * Send character to the currently focused element.
+ *
+ * This function handles casing of characters (sends the right charcode,
+ * and sends a shift key for uppercase chars).  No other modifiers are
+ * handled at this point.
+ *
+ * For now this method only works for English letters (lower and upper
+ * case) and the digits 0-9.
  */
-function _parseModifiers(aEvent)
-{
-  const masks = Components.interfaces.nsIDOMNSEvent;
-  var mval = 0;
-  if (aEvent.shiftKey)
-    mval |= masks.SHIFT_MASK;
-  if (aEvent.ctrlKey)
-    mval |= masks.CONTROL_MASK;
-  if (aEvent.altKey)
-    mval |= masks.ALT_MASK;
-  if (aEvent.metaKey)
-    mval |= masks.META_MASK;
-  if (aEvent.accelKey)
-    mval |= (navigator.platform.indexOf("Mac") >= 0) ? masks.META_MASK :
-                                                       masks.CONTROL_MASK;
+event.sendChar = function(char, window = undefined) {
+  // DOM event charcodes match ASCII (JS charcodes) for a-zA-Z0-9
+  let hasShift = (char == char.toUpperCase());
+  event.synthesizeKey(char, {shiftKey: hasShift}, window);
+};
 
-  return mval;
-}
+/**
+ * Send string to the focused element.
+ *
+ * For now this method only works for English letters (lower and upper
+ * case) and the digits 0-9.
+ */
+event.sendString = function(string, window = undefined) {
+  for (let i = 0; i < string.length; ++i) {
+    event.sendChar(string.charAt(i), window);
+  }
+};
 
 /**
- * Synthesize a mouse event on a target. The actual client point is determined
- * by taking the aTarget's client box and offseting it by aOffsetX and
- * aOffsetY. This allows mouse clicks to be simulated by calling this method.
- *
- * aEvent is an object which may contain the properties:
- *   shiftKey, ctrlKey, altKey, metaKey, accessKey, clickCount, button, type
+ * Send the non-character key to the focused element.
  *
- * If the type is specified, an mouse event of that type is fired. Otherwise,
- * a mousedown followed by a mouse up is performed.
- *
- * aWindow is optional, and defaults to the current window object.
+ * The name of the key should be the part that comes after "DOM_VK_"
+ * in the nsIDOMKeyEvent constant name for this key.  No modifiers are
+ * handled at this point.
  */
-function synthesizeMouse(aTarget, aOffsetX, aOffsetY, aEvent, aWindow)
-{
-  var rect = aTarget.getBoundingClientRect();
-  synthesizeMouseAtPoint(rect.left + aOffsetX, rect.top + aOffsetY,
-			 aEvent, aWindow);
-}
+event.sendKey = function(key, window = undefined) {
+  let keyName = "VK_" + key.toUpperCase();
+  event.synthesizeKey(keyName, {shiftKey: false}, window);
+};
+
+// TODO(ato): Unexpose this when actions.Chain#emitMouseEvent
+// no longer emits its own events
+event.parseModifiers_ = function(event) {
+  let mval = 0;
+  if (event.shiftKey) {
+    mval |= Ci.nsIDOMNSEvent.SHIFT_MASK;
+  }
+  if (event.ctrlKey) {
+    mval |= Ci.nsIDOMNSEvent.CONTROL_MASK;
+  }
+  if (event.altKey) {
+    mval |= Ci.nsIDOMNSEvent.ALT_MASK;
+  }
+  if (event.metaKey) {
+    mval |= Ci.nsIDOMNSEvent.META_MASK;
+  }
+  if (event.accelKey) {
+    if (navigator.platform.indexOf("Mac") >= 0) {
+      mval |= Ci.nsIDOMNSEvent.META_MASK;
+    } else {
+      mval |= Ci.nsIDOMNSEvent.CONTROL_MASK;
+    }
+  }
+  return mval;
+};
+
+/**
+ * Synthesise a mouse event on a target.
+ *
+ * The actual client point is determined by taking the aTarget's client
+ * box and offseting it by offsetX and offsetY.  This allows mouse clicks
+ * to be simulated by calling this method.
+ *
+ * If the type is specified, an mouse event of that type is
+ * fired. Otherwise, a mousedown followed by a mouse up is performed.
+ *
+ * @param {Element} element
+ *     Element to click.
+ * @param {number} offsetX
+ *     Horizontal offset to click from the target's bounding box.
+ * @param {number} offsetY
+ *     Vertical offset to click from the target's bounding box.
+ * @param {Object.<string, ?>} opts
+ *     Object which may contain the properties "shiftKey", "ctrlKey",
+ *     "altKey", "metaKey", "accessKey", "clickCount", "button", and
+ *     "type".
+ * @param {Window=} window
+ *     Window object.  Defaults to the current window.
+ */
+event.synthesizeMouse = function(
+    element, offsetX, offsetY, opts, window = undefined) {
+  let rect = element.getBoundingClientRect();
+  event.synthesizeMouseAtPoint(
+      rect.left + offsetX, rect.top + offsetY, opts, window);
+};
 
 /*
- * Synthesize a mouse event at a particular point in aWindow.
+ * Synthesize a mouse event at a particular point in a window.
  *
- * aEvent is an object which may contain the properties:
- *   shiftKey, ctrlKey, altKey, metaKey, accessKey, clickCount, button, type
+ * If the type of the event is specified, a mouse event of that type is
+ * fired. Otherwise, a mousedown followed by a mouse up is performed.
  *
- * If the type is specified, an mouse event of that type is fired. Otherwise,
- * a mousedown followed by a mouse up is performed.
- *
- * aWindow is optional, and defaults to the current window object.
+ * @param {number} left
+ *     CSS pixels from the left document margin.
+ * @param {number} top
+ *     CSS pixels from the top document margin.
+ * @param {Object.<string, ?>} event
+ *     Object which may contain the properties "shiftKey", "ctrlKey",
+ *     "altKey", "metaKey", "accessKey", "clickCount", "button", and
+ *     "type".
+ * @param {Window=} window
+ *     Window object.  Defaults to the current window.
  */
-function synthesizeMouseAtPoint(left, top, aEvent, aWindow)
-{
-  var utils = _getDOMWindowUtils(aWindow);
+event.synthesizeMouseAtPoint = function(
+    left, top, opts, window = undefined) {
+
+  let domutils = getDOMWindowUtils(window);
+
+  let button = event.button || 0;
+  let clickCount = event.clickCount || 1;
+  let modifiers = event.parseModifiers_(event);
 
-  if (utils) {
-    var button = aEvent.button || 0;
-    var clickCount = aEvent.clickCount || 1;
-    var modifiers = _parseModifiers(aEvent);
+  if (("type" in event) && event.type) {
+    domutils.sendMouseEvent(
+        event.type, left, top, button, clickCount, modifiers);
+  } else {
+    domutils.sendMouseEvent(
+        "mousedown", left, top, button, clickCount, modifiers);
+    domutils.sendMouseEvent(
+        "mouseup", left, top, button, clickCount, modifiers);
+  }
+};
 
-    if (("type" in aEvent) && aEvent.type) {
-      utils.sendMouseEvent(aEvent.type, left, top, button, clickCount, modifiers);
-    }
-    else {
-      utils.sendMouseEvent("mousedown", left, top, button, clickCount, modifiers);
-      utils.sendMouseEvent("mouseup", left, top, button, clickCount, modifiers);
-    }
-  }
-}
-
-// Call synthesizeMouse with coordinates at the center of aTarget.
-function synthesizeMouseAtCenter(aTarget, aEvent, aWindow)
-{
-  var rect = aTarget.getBoundingClientRect();
-  synthesizeMouse(aTarget, rect.width / 2, rect.height / 2, aEvent,
-                  aWindow);
-}
+/**
+ * Call event.synthesizeMouse with coordinates at the centre of the
+ * target.
+ */
+event.synthesizeMouseAtCenter = function(element, event, window) {
+  let rect = element.getBoundingClientRect();
+  event.synthesizeMouse(
+      element,
+      rect.width / 2,
+      rect.height / 2,
+      event,
+      window);
+};
 
 /**
- * Synthesize a mouse scroll event on a target. The actual client point is determined
- * by taking the aTarget's client box and offseting it by aOffsetX and
- * aOffsetY.
+ * Synthesise a mouse scroll event on a target.
+ *
+ * The actual client point is determined by taking the target's client
+ * box and offseting it by |offsetX| and |offsetY|.
+ *
+ * If the |type| property is specified for the |event| argument, a mouse
+ * scroll event of that type is fired.  Otherwise, DOMMouseScroll is used.
  *
- * aEvent is an object which may contain the properties:
- *   shiftKey, ctrlKey, altKey, metaKey, accessKey, button, type, axis, delta, hasPixels
+ * If the |axis| is specified, it must be one of "horizontal" or
+ * "vertical". If not specified, "vertical" is used.
  *
- * If the type is specified, a mouse scroll event of that type is fired. Otherwise,
- * "DOMMouseScroll" is used.
+ * |delta| is the amount to scroll by (can be positive or negative).
+ * It must be specified.
  *
- * If the axis is specified, it must be one of "horizontal" or "vertical". If not specified,
- * "vertical" is used.
+ * |hasPixels| specifies whether kHasPixels should be set in the
+ * |scrollFlags|.
  *
- * 'delta' is the amount to scroll by (can be positive or negative). It must
- * be specified.
- *
- * 'hasPixels' specifies whether kHasPixels should be set in the scrollFlags.
+ * |isMomentum| specifies whether kIsMomentum should be set in the
+ * |scrollFlags|.
  *
- * 'isMomentum' specifies whether kIsMomentum should be set in the scrollFlags.
- *
- * aWindow is optional, and defaults to the current window object.
+ * @param {Element} target
+ * @param {number} offsetY
+ * @param {number} offsetY
+ * @param {Object.<string, ?>} event
+ *     Object which may contain the properties shiftKey, ctrlKey, altKey,
+ *     metaKey, accessKey, button, type, axis, delta, and hasPixels.
+ * @param {Window=} window
+ *     Window object.  Defaults to the current window.
  */
-function synthesizeMouseScroll(aTarget, aOffsetX, aOffsetY, aEvent, aWindow)
-{
-  var utils = _getDOMWindowUtils(aWindow);
+event.synthesizeMouseScroll = function(
+    target, offsetX, offsetY, ev, window = undefined) {
+
+  let domutils = getDOMWindowUtils(window);
 
-  if (utils) {
-    // See nsMouseScrollFlags in nsGUIEvent.h
-    const kIsVertical = 0x02;
-    const kIsHorizontal = 0x04;
-    const kHasPixels = 0x08;
-    const kIsMomentum = 0x40;
+  // see nsMouseScrollFlags in nsGUIEvent.h
+  const kIsVertical = 0x02;
+  const kIsHorizontal = 0x04;
+  const kHasPixels = 0x08;
+  const kIsMomentum = 0x40;
 
-    var button = aEvent.button || 0;
-    var modifiers = _parseModifiers(aEvent);
+  let button = ev.button || 0;
+  let modifiers = event.parseModifiers_(ev);
 
-    var rect = aTarget.getBoundingClientRect();
-
-    var left = rect.left;
-    var top = rect.top;
+  let rect = target.getBoundingClientRect();
+  let left = rect.left;
+  let top = rect.top;
 
-    var type = (("type" in aEvent) && aEvent.type) || "DOMMouseScroll";
-    var axis = aEvent.axis || "vertical";
-    var scrollFlags = (axis == "horizontal") ? kIsHorizontal : kIsVertical;
-    if (aEvent.hasPixels) {
-      scrollFlags |= kHasPixels;
-    }
-    if (aEvent.isMomentum) {
-      scrollFlags |= kIsMomentum;
-    }
-    utils.sendMouseScrollEvent(type, left + aOffsetX, top + aOffsetY, button,
-                               scrollFlags, aEvent.delta, modifiers);
+  let type = (("type" in ev) && ev.type) || "DOMMouseScroll";
+  let axis = ev.axis || "vertical";
+  let scrollFlags = (axis == "horizontal") ? kIsHorizontal : kIsVertical;
+  if (ev.hasPixels) {
+    scrollFlags |= kHasPixels;
+  }
+  if (ev.isMomentum) {
+    scrollFlags |= kIsMomentum;
   }
-}
 
-function _computeKeyCodeFromChar(aChar)
-{
-  if (aChar.length != 1) {
+  domutils.sendMouseScrollEvent(
+      type,
+      left + offsetX,
+      top + offsetY,
+      button,
+      scrollFlags,
+      ev.delta,
+      modifiers);
+};
+
+function computeKeyCodeFromChar_(char) {
+  if (char.length != 1) {
     return 0;
   }
-  const nsIDOMKeyEvent = Components.interfaces.nsIDOMKeyEvent;
-  if (aChar >= 'a' && aChar <= 'z') {
-    return nsIDOMKeyEvent.DOM_VK_A + aChar.charCodeAt(0) - 'a'.charCodeAt(0);
+
+  if (char >= "a" && char <= "z") {
+    return Ci.nsIDOMKeyEvent.DOM_VK_A + char.charCodeAt(0) - "a".charCodeAt(0);
   }
-  if (aChar >= 'A' && aChar <= 'Z') {
-    return nsIDOMKeyEvent.DOM_VK_A + aChar.charCodeAt(0) - 'A'.charCodeAt(0);
+  if (char >= "A" && char <= "Z") {
+    return Ci.nsIDOMKeyEvent.DOM_VK_A + char.charCodeAt(0) - "A".charCodeAt(0);
   }
-  if (aChar >= '0' && aChar <= '9') {
-    return nsIDOMKeyEvent.DOM_VK_0 + aChar.charCodeAt(0) - '0'.charCodeAt(0);
+  if (char >= "0" && char <= "9") {
+    return Ci.nsIDOMKeyEvent.DOM_VK_0 + char.charCodeAt(0) - "0".charCodeAt(0);
   }
+
   // returns US keyboard layout's keycode
-  switch (aChar) {
-    case '~':
-    case '`':
-      return nsIDOMKeyEvent.DOM_VK_BACK_QUOTE;
-    case '!':
-      return nsIDOMKeyEvent.DOM_VK_1;
-    case '@':
-      return nsIDOMKeyEvent.DOM_VK_2;
-    case '#':
-      return nsIDOMKeyEvent.DOM_VK_3;
-    case '$':
-      return nsIDOMKeyEvent.DOM_VK_4;
-    case '%':
-      return nsIDOMKeyEvent.DOM_VK_5;
-    case '^':
-      return nsIDOMKeyEvent.DOM_VK_6;
-    case '&':
-      return nsIDOMKeyEvent.DOM_VK_7;
-    case '*':
-      return nsIDOMKeyEvent.DOM_VK_8;
-    case '(':
-      return nsIDOMKeyEvent.DOM_VK_9;
-    case ')':
-      return nsIDOMKeyEvent.DOM_VK_0;
-    case '-':
-    case '_':
-      return nsIDOMKeyEvent.DOM_VK_SUBTRACT;
-    case '+':
-    case '=':
-      return nsIDOMKeyEvent.DOM_VK_EQUALS;
-    case '{':
-    case '[':
-      return nsIDOMKeyEvent.DOM_VK_OPEN_BRACKET;
-    case '}':
-    case ']':
-      return nsIDOMKeyEvent.DOM_VK_CLOSE_BRACKET;
-    case '|':
-    case '\\':
-      return nsIDOMKeyEvent.DOM_VK_BACK_SLASH;
-    case ':':
-    case ';':
-      return nsIDOMKeyEvent.DOM_VK_SEMICOLON;
-    case '\'':
-    case '"':
-      return nsIDOMKeyEvent.DOM_VK_QUOTE;
-    case '<':
-    case ',':
-      return nsIDOMKeyEvent.DOM_VK_COMMA;
-    case '>':
-    case '.':
-      return nsIDOMKeyEvent.DOM_VK_PERIOD;
-    case '?':
-    case '/':
-      return nsIDOMKeyEvent.DOM_VK_SLASH;
-    case '\n':
-      return nsIDOMKeyEvent.DOM_VK_RETURN;
+  switch (char) {
+    case "~":
+    case "`":
+      return Ci.nsIDOMKeyEvent.DOM_VK_BACK_QUOTE;
+
+    case "!":
+      return Ci.nsIDOMKeyEvent.DOM_VK_1;
+
+    case "@":
+      return Ci.nsIDOMKeyEvent.DOM_VK_2;
+
+    case "#":
+      return Ci.nsIDOMKeyEvent.DOM_VK_3;
+
+    case "$":
+      return Ci.nsIDOMKeyEvent.DOM_VK_4;
+
+    case "%":
+      return Ci.nsIDOMKeyEvent.DOM_VK_5;
+
+    case "^":
+      return Ci.nsIDOMKeyEvent.DOM_VK_6;
+
+    case "&":
+      return Ci.nsIDOMKeyEvent.DOM_VK_7;
+
+    case "*":
+      return Ci.nsIDOMKeyEvent.DOM_VK_8;
+
+    case "(":
+      return Ci.nsIDOMKeyEvent.DOM_VK_9;
+
+    case ")":
+      return Ci.nsIDOMKeyEvent.DOM_VK_0;
+
+    case "-":
+    case "_":
+      return Ci.nsIDOMKeyEvent.DOM_VK_SUBTRACT;
+
+    case "+":
+    case "=":
+      return Ci.nsIDOMKeyEvent.DOM_VK_EQUALS;
+
+    case "{":
+    case "[":
+      return Ci.nsIDOMKeyEvent.DOM_VK_OPEN_BRACKET;
+
+    case "}":
+    case "]":
+      return Ci.nsIDOMKeyEvent.DOM_VK_CLOSE_BRACKET;
+
+    case "|":
+    case "\\":
+      return Ci.nsIDOMKeyEvent.DOM_VK_BACK_SLASH;
+
+    case ":":
+    case ";":
+      return Ci.nsIDOMKeyEvent.DOM_VK_SEMICOLON;
+
+    case "'":
+    case "\"":
+      return Ci.nsIDOMKeyEvent.DOM_VK_QUOTE;
+
+    case "<":
+    case ",":
+      return Ci.nsIDOMKeyEvent.DOM_VK_COMMA;
+
+    case ">":
+    case ".":
+      return Ci.nsIDOMKeyEvent.DOM_VK_PERIOD;
+
+    case "?":
+    case "/":
+      return Ci.nsIDOMKeyEvent.DOM_VK_SLASH;
+
+    case "\n":
+      return Ci.nsIDOMKeyEvent.DOM_VK_RETURN;
+
     default:
       return 0;
   }
 }
 
 /**
- * isKeypressFiredKey() returns TRUE if the given key should cause keypress
- * event when widget handles the native key event.  Otherwise, FALSE.
+ * Returns true if the given key should cause keypress event when widget
+ * handles the native key event.  Otherwise, false.
  *
- * aDOMKeyCode should be one of consts of nsIDOMKeyEvent::DOM_VK_*, or a key
- * name begins with "VK_", or a character.
+ * The key code should be one of consts of nsIDOMKeyEvent.DOM_VK_*,
+ * or a key name begins with "VK_", or a character.
  */
-function isKeypressFiredKey(aDOMKeyCode)
-{
-  const KeyEvent = Components.interfaces.nsIDOMKeyEvent;
-  if (typeof(aDOMKeyCode) == "string") {
-    if (aDOMKeyCode.indexOf("VK_") == 0) {
-      aDOMKeyCode = KeyEvent["DOM_" + aDOMKeyCode];
-      if (!aDOMKeyCode) {
-        throw "Unknown key: " + aDOMKeyCode;
+event.isKeypressFiredKey = function(key) {
+  if (typeof key == "string") {
+    if (key.indexOf("VK_") === 0) {
+      key = Ci.nsIDOMKeyEvent["DOM_" + key];
+      if (!key) {
+        throw new TypeError("Unknown key: " + key);
       }
+
+    // if key generates a character, it must cause a keypress event
     } else {
-      // If the key generates a character, it must cause a keypress event.
       return true;
     }
   }
-  switch (aDOMKeyCode) {
-    case KeyEvent.DOM_VK_SHIFT:
-    case KeyEvent.DOM_VK_CONTROL:
-    case KeyEvent.DOM_VK_ALT:
-    case KeyEvent.DOM_VK_CAPS_LOCK:
-    case KeyEvent.DOM_VK_NUM_LOCK:
-    case KeyEvent.DOM_VK_SCROLL_LOCK:
-    case KeyEvent.DOM_VK_META:
+
+  switch (key) {
+    case Ci.nsIDOMKeyEvent.DOM_VK_SHIFT:
+    case Ci.nsIDOMKeyEvent.DOM_VK_CONTROL:
+    case Ci.nsIDOMKeyEvent.DOM_VK_ALT:
+    case Ci.nsIDOMKeyEvent.DOM_VK_CAPS_LOCK:
+    case Ci.nsIDOMKeyEvent.DOM_VK_NUM_LOCK:
+    case Ci.nsIDOMKeyEvent.DOM_VK_SCROLL_LOCK:
+    case Ci.nsIDOMKeyEvent.DOM_VK_META:
       return false;
+
     default:
       return true;
   }
+};
+
+/**
+ * Synthesise a key event.
+ *
+ * It is targeted at whatever would be targeted by an actual keypress
+ * by the user, typically the focused element.
+ *
+ * @param {string} key
+ *     Key to synthesise.  Should either be a character or a key code
+ *     starting with "VK_" such as VK_RETURN.
+ * @param {Object.<string, ?>} event
+ *     Object which may contain the properties shiftKey, ctrlKey, altKey,
+ *     metaKey, accessKey, type.  If the type is specified, a key event
+ *    of that type is fired.  Otherwise, a keydown, a keypress, and then a
+ *     keyup event are fired in sequence.
+ * @param {Window=} window
+ *     Window object.  Defaults to the current window.
+ *
+ * @throws {TypeError}
+ *     If unknown key.
+ */
+event.synthesizeKey = function(key, ev, window = undefined) {
+  let domutils = getDOMWindowUtils(window);
+
+  let keyCode = 0;
+  let charCode = 0;
+  if (key.indexOf("VK_") === 0) {
+    keyCode = Ci.nsIDOMKeyEvent["DOM_" + key];
+    if (!keyCode) {
+      throw new TypeError("Unknown key: " + key);
+    }
+  } else {
+    charCode = key.charCodeAt(0);
+    keyCode = computeKeyCodeFromChar_(key.charAt(0));
+  }
+
+  let modifiers = event.parseModifiers_(ev);
+
+  // send keydown + (optional) keypress + keyup events
+  if (!("type" in ev) || !ev.type) {
+    let keyDownDefaultHappened = domutils.sendKeyEvent(
+        "keydown", keyCode, 0, modifiers);
+    if (event.isKeypressFiredKey(keyCode)) {
+      domutils.sendKeyEvent(
+          "keypress",
+          charCode ? 0 : keyCode,
+          charCode,
+          modifiers,
+          !keyDownDefaultHappened);
+    }
+    domutils.sendKeyEvent("keyup", keyCode, 0, modifiers);
+
+  // send standalone keypress event
+  } else if (ev.type == "keypress") {
+    domutils.sendKeyEvent(
+        ev.type,
+        charCode ? 0 : keyCode,
+        charCode,
+        modifiers);
+
+  // send other standalone event than keypress
+  } else {
+    domutils.sendKeyEvent(ev.type, keyCode, 0, modifiers);
+  }
+};
+
+/**
+ * Indicate that an event with an original target and type is expected
+ * to be fired, or not expected to be fired.
+ */
+function expectEvent_(expectedTarget, expectedEvent, testName) {
+  if (!expectedTarget || !expectedEvent) {
+    return null;
+  }
+
+  seenEvent = false;
+
+  let type;
+  if (expectedEvent.charAt(0) == "!") {
+    type = expectedEvent.substring(1);
+  } else {
+    type = expectedEvent;
+  }
+
+  let handler = ev => {
+    let pass = (!seenEvent && ev.originalTarget == expectedTarget && ev.type == type);
+    is(pass, true, `${testName} ${type} event target ${seenEvent ? "twice" : ""}`);
+    seenEvent = true;
+  };
+
+  expectedTarget.addEventListener(type, handler, false);
+  return handler;
 }
 
 /**
- * Synthesize a key event. It is targeted at whatever would be targeted by an
- * actual keypress by the user, typically the focused element.
+ * Check if the event was fired or not. The provided event handler will
+ * be removed.
+ */
+function checkExpectedEvent_(
+    expectedTarget, expectedEvent, eventHandler, testName) {
+
+  if (eventHandler) {
+    let expectEvent = (expectedEvent.charAt(0) != "!");
+    let type = expectEvent;
+    if (!type) {
+      type = expectedEvent.substring(1);
+    }
+    expectedTarget.removeEventListener(type, eventHandler, false);
+
+    let desc = `${type} event`;
+    if (!expectEvent) {
+      desc += " not";
+    }
+    is(seenEvent, expectEvent, `${testName} ${desc} fired`);
+  }
+
+  seenEvent = false;
+}
+
+/**
+ * Similar to event.synthesizeMouse except that a test is performed to
+ * see if an event is fired at the right target as a result.
  *
- * aKey should be either a character or a keycode starting with VK_ such as
- * VK_RETURN.
+ * To test that an event is not fired, use an expected type preceded by
+ * an exclamation mark, such as "!select". This might be used to test that
+ * a click on a disabled element doesn't fire certain events for instance.
  *
- * aEvent is an object which may contain the properties:
- *   shiftKey, ctrlKey, altKey, metaKey, accessKey, type
+ * @param {Element} target
+ *     Synthesise the mouse event on this target.
+ * @param {number} offsetX
+ *     Horizontal offset from the target's bounding box.
+ * @param {number} offsetY
+ *     Vertical offset from the target's bounding box.
+ * @param {Object.<string, ?>} ev
+ *     Object which may contain the properties shiftKey, ctrlKey, altKey,
+ *     metaKey, accessKey, type.
+ * @param {Element} expectedTarget
+ *     Expected originalTarget of the event.
+ * @param {DOMEvent} expectedEvent
+ *     Expected type of the event, such as "select".
+ * @param {string} testName
+ *     Test name when outputing results.
+ * @param {Window=} window
+ *     Window object.  Defaults to the current window.
+ */
+event.synthesizeMouseExpectEvent = function(
+    target, offsetX, offsetY, ev, expectedTarget, expectedEvent,
+    testName, window = undefined) {
+
+  let eventHandler = expectEvent_(
+      expectedTarget,
+      expectedEvent,
+      testName);
+  event.synthesizeMouse(target, offsetX, offsetY, ev, window);
+  checkExpectedEvent_(
+      expectedTarget,
+      expectedEvent,
+      eventHandler,
+      testName);
+};
+
+/**
+ * Similar to synthesizeKey except that a test is performed to see if
+ * an event is fired at the right target as a result.
  *
- * If the type is specified, a key event of that type is fired. Otherwise,
- * a keydown, a keypress and then a keyup event are fired in sequence.
+ * @param {string} key
+ *     Key to synthesise.
+ * @param {Object.<string, ?>} ev
+ *     Object which may contain the properties shiftKey, ctrlKey, altKey,
+ *     metaKey, accessKey, type.
+ * @param {Element} expectedTarget
+ *     Expected originalTarget of the event.
+ * @param {DOMEvent} expectedEvent
+ *     Expected type of the event, such as "select".
+ * @param {string} testName
+ *     Test name when outputing results
+ * @param {Window=} window
+ *     Window object.  Defaults to the current window.
+ *
+ * To test that an event is not fired, use an expected type preceded by an
+ * exclamation mark, such as "!select".
  *
  * aWindow is optional, and defaults to the current window object.
  */
-function synthesizeKey(aKey, aEvent, aWindow)
-{
-  var utils = _getDOMWindowUtils(aWindow);
-  if (utils) {
-    var keyCode = 0, charCode = 0;
-    if (aKey.indexOf("VK_") == 0) {
-      keyCode = KeyEvent["DOM_" + aKey];
-      if (!keyCode) {
-        throw "Unknown key: " + aKey;
-      }
-    } else {
-      charCode = aKey.charCodeAt(0);
-      keyCode = _computeKeyCodeFromChar(aKey.charAt(0));
-    }
-
-    var modifiers = _parseModifiers(aEvent);
-
-    if (!("type" in aEvent) || !aEvent.type) {
-      // Send keydown + (optional) keypress + keyup events.
-      var keyDownDefaultHappened =
-          utils.sendKeyEvent("keydown", keyCode, 0, modifiers);
-      if (isKeypressFiredKey(keyCode)) {
-        utils.sendKeyEvent("keypress", charCode ? 0 : keyCode, charCode,
-                           modifiers, !keyDownDefaultHappened);
-      }
-      utils.sendKeyEvent("keyup", keyCode, 0, modifiers);
-    } else if (aEvent.type == "keypress") {
-      // Send standalone keypress event.
-      utils.sendKeyEvent(aEvent.type, charCode ? 0 : keyCode,
-                         charCode, modifiers);
-    } else {
-      // Send other standalone event than keypress.
-      utils.sendKeyEvent(aEvent.type, keyCode, 0, modifiers);
-    }
-  }
-}
-
-var _gSeenEvent = false;
-
-/**
- * Indicate that an event with an original target of aExpectedTarget and
- * a type of aExpectedEvent is expected to be fired, or not expected to
- * be fired.
- */
-function _expectEvent(aExpectedTarget, aExpectedEvent, aTestName)
-{
-  if (!aExpectedTarget || !aExpectedEvent)
-    return null;
-
-  _gSeenEvent = false;
-
-  var type = (aExpectedEvent.charAt(0) == "!") ?
-             aExpectedEvent.substring(1) : aExpectedEvent;
-  var eventHandler = function(event) {
-    var epassed = (!_gSeenEvent && event.originalTarget == aExpectedTarget &&
-                   event.type == type);
-    is(epassed, true, aTestName + " " + type + " event target " + (_gSeenEvent ? "twice" : ""));
-    _gSeenEvent = true;
-  };
-
-  aExpectedTarget.addEventListener(type, eventHandler, false);
-  return eventHandler;
-}
+event.synthesizeKeyExpectEvent = function(
+    key, ev, expectedTarget, expectedEvent, testName,
+    window = undefined) {
 
-/**
- * Check if the event was fired or not. The event handler aEventHandler
- * will be removed.
- */
-function _checkExpectedEvent(aExpectedTarget, aExpectedEvent, aEventHandler, aTestName)
-{
-  if (aEventHandler) {
-    var expectEvent = (aExpectedEvent.charAt(0) != "!");
-    var type = expectEvent ? aExpectedEvent : aExpectedEvent.substring(1);
-    aExpectedTarget.removeEventListener(type, aEventHandler, false);
-    var desc = type + " event";
-    if (!expectEvent)
-      desc += " not";
-    is(_gSeenEvent, expectEvent, aTestName + " " + desc + " fired");
-  }
-
-  _gSeenEvent = false;
-}
-
-/**
- * Similar to synthesizeMouse except that a test is performed to see if an
- * event is fired at the right target as a result.
- *
- * aExpectedTarget - the expected originalTarget of the event.
- * aExpectedEvent - the expected type of the event, such as 'select'.
- * aTestName - the test name when outputing results
- *
- * To test that an event is not fired, use an expected type preceded by an
- * exclamation mark, such as '!select'. This might be used to test that a
- * click on a disabled element doesn't fire certain events for instance.
- *
- * aWindow is optional, and defaults to the current window object.
- */
-function synthesizeMouseExpectEvent(aTarget, aOffsetX, aOffsetY, aEvent,
-                                    aExpectedTarget, aExpectedEvent, aTestName,
-                                    aWindow)
-{
-  var eventHandler = _expectEvent(aExpectedTarget, aExpectedEvent, aTestName);
-  synthesizeMouse(aTarget, aOffsetX, aOffsetY, aEvent, aWindow);
-  _checkExpectedEvent(aExpectedTarget, aExpectedEvent, eventHandler, aTestName);
-}
-
-/**
- * Similar to synthesizeKey except that a test is performed to see if an
- * event is fired at the right target as a result.
- *
- * aExpectedTarget - the expected originalTarget of the event.
- * aExpectedEvent - the expected type of the event, such as 'select'.
- * aTestName - the test name when outputing results
- *
- * To test that an event is not fired, use an expected type preceded by an
- * exclamation mark, such as '!select'.
- *
- * aWindow is optional, and defaults to the current window object.
- */
-function synthesizeKeyExpectEvent(key, aEvent, aExpectedTarget, aExpectedEvent,
-                                  aTestName, aWindow)
-{
-  var eventHandler = _expectEvent(aExpectedTarget, aExpectedEvent, aTestName);
-  synthesizeKey(key, aEvent, aWindow);
-  _checkExpectedEvent(aExpectedTarget, aExpectedEvent, eventHandler, aTestName);
-}
-
-function disableNonTestMouseEvents(aDisable)
-{
-  var domutils = _getDOMWindowUtils();
-  domutils.disableNonTestMouseEvents(aDisable);
-}
-
-function _getDOMWindowUtils(aWindow)
-{
-  if (!aWindow) {
-    aWindow = window;
-  }
-
-  //TODO: this is assuming we are in chrome space
-  return aWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
-                               getInterface(Components.interfaces.nsIDOMWindowUtils);
-}
-
-// Must be synchronized with nsIDOMWindowUtils.
-const COMPOSITION_ATTR_RAWINPUT              = 0x02;
-const COMPOSITION_ATTR_SELECTEDRAWTEXT       = 0x03;
-const COMPOSITION_ATTR_CONVERTEDTEXT         = 0x04;
-const COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT = 0x05;
+  let eventHandler = expectEvent_(
+      expectedTarget,
+      expectedEvent,
+      testName);
+  event.synthesizeKey(key, ev, window);
+  checkExpectedEvent_(
+      expectedTarget,
+      expectedEvent,
+      eventHandler,
+      testName);
+};
 
 /**
  * Synthesize a composition event.
  *
- * @param aEvent               The composition event information.  This must
- *                             have |type| member.  The value must be
- *                             "compositionstart", "compositionend" or
- *                             "compositionupdate".
- *                             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 would
- *                             be ignored if the event type were
- *                             "compositionstart".
- * @param aWindow              Optional (If null, current |window| will be used)
+ * @param {DOMEvent} ev
+ *     The composition event information.  This must have |type|
+ *     member.  The value must be "compositionstart", "compositionend" or
+ *     "compositionupdate".  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 would be ignored if the
+ *     event type were "compositionstart".
+ * @param {Window=} window
+ *     Window object.  Defaults to the current window.
  */
-function synthesizeComposition(aEvent, aWindow)
-{
-  var utils = _getDOMWindowUtils(aWindow);
-  if (!utils) {
-    return;
-  }
+event.synthesizeComposition = function(ev, window = undefined) {
+  let domutils = getDOMWindowUtils(window);
+  domutils.sendCompositionEvent(ev.type, ev.data || "", ev.locale || "");
+};
 
-  utils.sendCompositionEvent(aEvent.type, aEvent.data ? aEvent.data : "",
-                             aEvent.locale ? aEvent.locale : "");
-}
 /**
  * Synthesize a text event.
  *
- * @param aEvent   The text 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.
+ * The text 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
- *                   +-- composition
- *                   |     +-- string
- *                   |     +-- clauses[]
- *                   |           +-- length
- *                   |           +-- attr
- *                   +-- caret
- *                         +-- start
- *                         +-- length
+ *     ev
+ *      +-- composition
+ *      |     +-- string
+ *      |     +-- clauses[]
+ *      |           +-- length
+ *      |           +-- attr
+ *      +-- caret
+ *            +-- start
+ *            +-- length
  *
- *                 Set the composition string to |composition.string|.  Set its
- *                 clauses information to the |clauses| array.
+ * Set the composition string to |composition.string|.  Set its clauses
+ * information to the |clauses| array.
  *
- *                 When it's composing, set the each clauses' length to the
- *                 |composition.clauses[n].length|.  The sum of the all length
- *                 values must be same as the length of |composition.string|.
- *                 Set nsIDOMWindowUtils.COMPOSITION_ATTR_* to the
- *                 |composition.clauses[n].attr|.
+ * When it's composing, set the each clauses' length
+ * to the |composition.clauses[n].length|.  The sum
+ * of the all length values must be same as the length of
+ * |composition.string|. Set nsIDOMWindowUtils.COMPOSITION_ATTR_* to the
+ * |composition.clauses[n].attr|.
  *
- *                 When it's not composing, set 0 to the
- *                 |composition.clauses[0].length| and
- *                 |composition.clauses[0].attr|.
+ * When it's not composing, set 0 to the |composition.clauses[0].length|
+ * and |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.
+ * Set caret position to the |caret.start|. Its 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.
  *
- * @param aWindow  Optional (If null, current |window| will be used)
+ * @param {Object.<string, ?>} ev
+ *     The text event's information,
+ * @param {Window=} window
+ *     Window object.  Defaults to the current window.
  */
-function synthesizeText(aEvent, aWindow)
-{
-  var utils = _getDOMWindowUtils(aWindow);
-  if (!utils) {
+event.synthesizeText = function(ev, window = undefined) {
+  let domutils = getDOMWindowUtils(window);
+
+  if (!ev.composition ||
+      !ev.composition.clauses ||
+      !ev.composition.clauses[0]) {
     return;
   }
 
-  if (!aEvent.composition || !aEvent.composition.clauses ||
-      !aEvent.composition.clauses[0]) {
-    return;
-  }
-
-  var firstClauseLength = aEvent.composition.clauses[0].length;
-  var firstClauseAttr   = aEvent.composition.clauses[0].attr;
-  var secondClauseLength = 0;
-  var secondClauseAttr = 0;
-  var thirdClauseLength = 0;
-  var thirdClauseAttr = 0;
-  if (aEvent.composition.clauses[1]) {
-    secondClauseLength = aEvent.composition.clauses[1].length;
-    secondClauseAttr   = aEvent.composition.clauses[1].attr;
-    if (aEvent.composition.clauses[2]) {
-      thirdClauseLength = aEvent.composition.clauses[2].length;
-      thirdClauseAttr   = aEvent.composition.clauses[2].attr;
+  let firstClauseLength = ev.composition.clauses[0].length;
+  let firstClauseAttr   = ev.composition.clauses[0].attr;
+  let secondClauseLength = 0;
+  let secondClauseAttr = 0;
+  let thirdClauseLength = 0;
+  let thirdClauseAttr = 0;
+  if (ev.composition.clauses[1]) {
+    secondClauseLength = ev.composition.clauses[1].length;
+    secondClauseAttr   = ev.composition.clauses[1].attr;
+    if (event.composition.clauses[2]) {
+      thirdClauseLength = ev.composition.clauses[2].length;
+      thirdClauseAttr   = ev.composition.clauses[2].attr;
     }
   }
 
-  var caretStart = -1;
-  var caretLength = 0;
-  if (aEvent.caret) {
-    caretStart = aEvent.caret.start;
-    caretLength = aEvent.caret.length;
+  let caretStart = -1;
+  let caretLength = 0;
+  if (event.caret) {
+    caretStart = ev.caret.start;
+    caretLength = ev.caret.length;
   }
 
-  utils.sendTextEvent(aEvent.composition.string,
-                      firstClauseLength, firstClauseAttr,
-                      secondClauseLength, secondClauseAttr,
-                      thirdClauseLength, thirdClauseAttr,
-                      caretStart, caretLength);
-}
+  domutils.sendTextEvent(
+      ev.composition.string,
+      firstClauseLength,
+      firstClauseAttr,
+      secondClauseLength,
+      secondClauseAttr,
+      thirdClauseLength,
+      thirdClauseAttr,
+      caretStart,
+      caretLength);
+};
 
 /**
  * Synthesize a query selected text event.
  *
- * @param aWindow  Optional (If null, current |window| will be used)
- * @return         An nsIQueryContentEventResult object.  If this failed,
- *                 the result might be null.
+ * @param {Window=}
+ *     Window object.  Defaults to the current window.
+ *
+ * @return {(nsIQueryContentEventResult|null)}
+ *     Event's result, or null if it failed.
  */
-function synthesizeQuerySelectedText(aWindow)
-{
-  var utils = _getDOMWindowUtils(aWindow);
-  if (!utils) {
-    return null;
-  }
-
-  return utils.sendQueryContentEvent(utils.QUERY_SELECTED_TEXT, 0, 0, 0, 0);
-}
+event.synthesizeQuerySelectedText = function(window = undefined) {
+  let domutils = getDOMWindowUtils(window);
+  return domutils.sendQueryContentEvent(
+      domutils.QUERY_SELECTED_TEXT, 0, 0, 0, 0);
+};
 
 /**
  * Synthesize a selection set event.
  *
- * @param aOffset  The character offset.  0 means the first character in the
- *                 selection root.
- * @param aLength  The length of the text.  If the length is too long,
- *                 the extra length is ignored.
- * @param aReverse If true, the selection is from |aOffset + aLength| to
- *                 |aOffset|.  Otherwise, from |aOffset| to |aOffset + aLength|.
- * @param aWindow  Optional (If null, current |window| will be used)
+ * @param {number} offset
+ *     Character offset.  0 means the first character in the selection
+ *     root.
+ * @param {number} length
+ *     Length of the text.  If the length is too long, the extra length
+ *     is ignored.
+ * @param {boolean} reverse
+ *     If true, the selection is from |aOffset + aLength| to |aOffset|.
+ *     Otherwise, from |aOffset| to |aOffset + aLength|.
+ * @param {Window=} window
+ *     Window object.  Defaults to the current window.
+ *
  * @return         True, if succeeded.  Otherwise false.
  */
-function synthesizeSelectionSet(aOffset, aLength, aReverse, aWindow)
-{
-  var utils = _getDOMWindowUtils(aWindow);
-  if (!utils) {
-    return false;
+event.synthesizeSelectionSet = function(
+    offset, length, reverse, window = undefined) {
+  let domutils = getDOMWindowUtils(window);
+  return domutils.sendSelectionSetEvent(offset, length, reverse);
+};
+
+const KEYCODES_LOOKUP = {
+  "VK_SHIFT": "shiftKey",
+  "VK_CONTROL": "ctrlKey",
+  "VK_ALT": "altKey",
+  "VK_META": "metaKey",
+};
+
+const VIRTUAL_KEYCODE_LOOKUP = {
+  "\uE001": "VK_CANCEL",
+  "\uE002": "VK_HELP",
+  "\uE003": "VK_BACK_SPACE",
+  "\uE004": "VK_TAB",
+  "\uE005": "VK_CLEAR",
+  "\uE006": "VK_RETURN",
+  "\uE007": "VK_RETURN",
+  "\uE008": "VK_SHIFT",
+  "\uE009": "VK_CONTROL",
+  "\uE00A": "VK_ALT",
+  "\uE03D": "VK_META",
+  "\uE00B": "VK_PAUSE",
+  "\uE00C": "VK_ESCAPE",
+  "\uE00D": "VK_SPACE",  // printable
+  "\uE00E": "VK_PAGE_UP",
+  "\uE00F": "VK_PAGE_DOWN",
+  "\uE010": "VK_END",
+  "\uE011": "VK_HOME",
+  "\uE012": "VK_LEFT",
+  "\uE013": "VK_UP",
+  "\uE014": "VK_RIGHT",
+  "\uE015": "VK_DOWN",
+  "\uE016": "VK_INSERT",
+  "\uE017": "VK_DELETE",
+  "\uE018": "VK_SEMICOLON",
+  "\uE019": "VK_EQUALS",
+  "\uE01A": "VK_NUMPAD0",
+  "\uE01B": "VK_NUMPAD1",
+  "\uE01C": "VK_NUMPAD2",
+  "\uE01D": "VK_NUMPAD3",
+  "\uE01E": "VK_NUMPAD4",
+  "\uE01F": "VK_NUMPAD5",
+  "\uE020": "VK_NUMPAD6",
+  "\uE021": "VK_NUMPAD7",
+  "\uE022": "VK_NUMPAD8",
+  "\uE023": "VK_NUMPAD9",
+  "\uE024": "VK_MULTIPLY",
+  "\uE025": "VK_ADD",
+  "\uE026": "VK_SEPARATOR",
+  "\uE027": "VK_SUBTRACT",
+  "\uE028": "VK_DECIMAL",
+  "\uE029": "VK_DIVIDE",
+  "\uE031": "VK_F1",
+  "\uE032": "VK_F2",
+  "\uE033": "VK_F3",
+  "\uE034": "VK_F4",
+  "\uE035": "VK_F5",
+  "\uE036": "VK_F6",
+  "\uE037": "VK_F7",
+  "\uE038": "VK_F8",
+  "\uE039": "VK_F9",
+  "\uE03A": "VK_F10",
+  "\uE03B": "VK_F11",
+  "\uE03C": "VK_F12",
+};
+
+function getKeyCode(c) {
+  if (c in VIRTUAL_KEYCODE_LOOKUP) {
+    return VIRTUAL_KEYCODE_LOOKUP[c];
   }
-  return utils.sendSelectionSetEvent(aOffset, aLength, aReverse);
+  return c;
 }
+
+event.sendKeyDown = function(keyToSend, modifiers, document) {
+  modifiers.type = "keydown";
+  event.sendSingleKey(keyToSend, modifiers, document);
+  if (["VK_SHIFT", "VK_CONTROL", "VK_ALT", "VK_META"].indexOf(getKeyCode(keyToSend)) < 0) {
+    modifiers.type = "keypress";
+    event.sendSingleKey(keyToSend, modifiers, document);
+  }
+  delete modifiers.type;
+};
+
+event.sendKeyUp = function(keyToSend, modifiers, window = undefined) {
+  modifiers.type = "keyup";
+  event.sendSingleKey(keyToSend, modifiers, window);
+  delete modifiers.type;
+};
+
+event.sendSingleKey = function(keyToSend, modifiers, window = undefined) {
+  let keyCode = getKeyCode(keyToSend);
+  if (keyCode in KEYCODES_LOOKUP) {
+    let modName = KEYCODES_LOOKUP[keyCode];
+    modifiers[modName] = !modifiers[modName];
+  } else if (modifiers.shiftKey) {
+    keyCode = keyCode.toUpperCase();
+  }
+  event.synthesizeKey(keyCode, modifiers, window);
+};
+
+/**
+ * Focus element and, if a textual input field and no previous selection
+ * state exists, move the caret to the end of the input field.
+ *
+ * @param {Element} element
+ *     Element to focus.
+ */
+function focusElement(element) {
+  let t = element.type;
+  if (t && (t == "text" || t == "textarea")) {
+    if (element.selectionEnd == 0) {
+      let len = element.value.length;
+      element.setSelectionRange(len, len);
+    }
+  }
+  element.focus();
+}
+
+/**
+ * @param {Array.<string>} keySequence
+ * @param {Element} element
+ * @param {Object.<string, boolean>=} opts
+ * @param {Window=} window
+ */
+event.sendKeysToElement = function(
+    keySequence, element, opts = {}, window = undefined) {
+
+  if (opts.ignoreVisibility || elements.checkVisible(element, window)) {
+    focusElement(element);
+
+    // make Object.<modifier, false> map
+    let modifiers = Object.create(event.Modifiers);
+    for (let modifier in event.Modifiers) {
+      modifiers[modifier] = false;
+    }
+
+    let value = keySequence.join("");
+    for (let i = 0; i < value.length; i++) {
+      let c = value.charAt(i);
+      event.sendSingleKey(c, modifiers, window);
+    }
+
+  } else {
+    throw new ElementNotVisibleError("Element is not visible");
+  }
+};
deleted file mode 100644
--- a/testing/marionette/sendkeys.js
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- *  Copyright 2007-2009 WebDriver committers
- *  Copyright 2007-2009 Google Inc.
- *  Portions copyright 2012 Software Freedom Conservancy
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
-
-Cu.import("chrome://marionette/content/error.js");
-
-var loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
-    .getService(Ci.mozIJSSubScriptLoader);
-
-var utils = {};
-loader.loadSubScript("chrome://marionette/content/EventUtils.js", utils);
-loader.loadSubScript("chrome://marionette/content/ChromeUtils.js", utils);
-
-var keyModifierNames = {
-    "VK_SHIFT": 'shiftKey',
-    "VK_CONTROL": 'ctrlKey',
-    "VK_ALT": 'altKey',
-    "VK_META": 'metaKey'
-};
-
-var keyCodes = {
-  '\uE001': "VK_CANCEL",
-  '\uE002': "VK_HELP",
-  '\uE003': "VK_BACK_SPACE",
-  '\uE004': "VK_TAB",
-  '\uE005': "VK_CLEAR",
-  '\uE006': "VK_RETURN",
-  '\uE007': "VK_RETURN",
-  '\uE008': "VK_SHIFT",
-  '\uE009': "VK_CONTROL",
-  '\uE00A': "VK_ALT",
-  '\uE03D': "VK_META",
-  '\uE00B': "VK_PAUSE",
-  '\uE00C': "VK_ESCAPE",
-  '\uE00D': "VK_SPACE",  // printable
-  '\uE00E': "VK_PAGE_UP",
-  '\uE00F': "VK_PAGE_DOWN",
-  '\uE010': "VK_END",
-  '\uE011': "VK_HOME",
-  '\uE012': "VK_LEFT",
-  '\uE013': "VK_UP",
-  '\uE014': "VK_RIGHT",
-  '\uE015': "VK_DOWN",
-  '\uE016': "VK_INSERT",
-  '\uE017': "VK_DELETE",
-  '\uE018': "VK_SEMICOLON",
-  '\uE019': "VK_EQUALS",
-  '\uE01A': "VK_NUMPAD0",
-  '\uE01B': "VK_NUMPAD1",
-  '\uE01C': "VK_NUMPAD2",
-  '\uE01D': "VK_NUMPAD3",
-  '\uE01E': "VK_NUMPAD4",
-  '\uE01F': "VK_NUMPAD5",
-  '\uE020': "VK_NUMPAD6",
-  '\uE021': "VK_NUMPAD7",
-  '\uE022': "VK_NUMPAD8",
-  '\uE023': "VK_NUMPAD9",
-  '\uE024': "VK_MULTIPLY",
-  '\uE025': "VK_ADD",
-  '\uE026': "VK_SEPARATOR",
-  '\uE027': "VK_SUBTRACT",
-  '\uE028': "VK_DECIMAL",
-  '\uE029': "VK_DIVIDE",
-  '\uE031': "VK_F1",
-  '\uE032': "VK_F2",
-  '\uE033': "VK_F3",
-  '\uE034': "VK_F4",
-  '\uE035': "VK_F5",
-  '\uE036': "VK_F6",
-  '\uE037': "VK_F7",
-  '\uE038': "VK_F8",
-  '\uE039': "VK_F9",
-  '\uE03A': "VK_F10",
-  '\uE03B': "VK_F11",
-  '\uE03C': "VK_F12"
-};
-
-function getKeyCode (c) {
-  if (c in keyCodes) {
-    return keyCodes[c];
-  }
-  return c;
-};
-
-function sendKeyDown (keyToSend, modifiers, document) {
-  modifiers.type = "keydown";
-  sendSingleKey(keyToSend, modifiers, document);
-  if (["VK_SHIFT", "VK_CONTROL",
-       "VK_ALT", "VK_META"].indexOf(getKeyCode(keyToSend)) == -1) {
-    modifiers.type = "keypress";
-    sendSingleKey(keyToSend, modifiers, document);
-  }
-  delete modifiers.type;
-}
-
-function sendKeyUp (keyToSend, modifiers, document) {
-  modifiers.type = "keyup";
-  sendSingleKey(keyToSend, modifiers, document);
-  delete modifiers.type;
-}
-
-function sendSingleKey (keyToSend, modifiers, document) {
-  let keyCode = getKeyCode(keyToSend);
-  if (keyCode in keyModifierNames) {
-    let modName = keyModifierNames[keyCode];
-    modifiers[modName] = !modifiers[modName];
-  } else if (modifiers.shiftKey) {
-    keyCode = keyCode.toUpperCase();
-  }
-  utils.synthesizeKey(keyCode, modifiers, document);
-}
-
-/**
- * Focus element and, if a textual input field and no previous selection
- * state exists, move the caret to the end of the input field.
- *
- * @param {Element} el
- *     Element to focus.
- */
-function focusElement(el) {
-  let t = el.type;
-  if (t && (t == "text" || t == "textarea")) {
-    if (el.selectionEnd == 0) {
-      let len = el.value.length;
-      el.setSelectionRange(len, len);
-    }
-  }
-  el.focus();
-}
-
-function sendKeysToElement(document, element, keysToSend, ignoreVisibility) {
-  if (ignoreVisibility || checkVisible(element)) {
-    focusElement(element);
-
-    let modifiers = {
-      shiftKey: false,
-      ctrlKey: false,
-      altKey: false,
-      metaKey: false
-    };
-    let value = keysToSend.join("");
-    for (var i = 0; i < value.length; i++) {
-      var c = value.charAt(i);
-      sendSingleKey(c, modifiers, document);
-    }
-  } else {
-    throw new ElementNotVisibleError("Element is not visible");
-  }
-};