Bug 1439500 - Make devtools/client/shared/widgets handle non-printable keys and key combinations with keydown event r?jryans draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Tue, 20 Feb 2018 18:57:35 +0900
changeset 759626 edab8e07bd4f94fc1b9a6d3fbeadd9b01aaaac9f
parent 759603 7208b6a7b11c3ed8c87a7f17c9c30a8f9583e791
push id100412
push usermasayuki@d-toybox.com
push dateMon, 26 Feb 2018 06:12:31 +0000
reviewersjryans
bugs1439500
milestone60.0a1
Bug 1439500 - Make devtools/client/shared/widgets handle non-printable keys and key combinations with keydown event r?jryans We'll stop dispatching keypress event for non-printable keys and key combinations at least in web content. This means that widget of devtools/client cannot be tested with loading them into tabs with mochitest browser chrome. Fortunately, they are cleanly independent from other module's keypress event listeners. So, we can make they use keydown event to handle non-printable keys and key combinations. MozReview-Commit-ID: 6fNSsGi9VbQ
devtools/client/shared/test/browser_treeWidget_keyboard_interaction.js
devtools/client/shared/widgets/AbstractTreeItem.jsm
devtools/client/shared/widgets/BreadcrumbsWidget.jsm
devtools/client/shared/widgets/FastListWidget.js
devtools/client/shared/widgets/FilterWidget.js
devtools/client/shared/widgets/FlameGraph.js
devtools/client/shared/widgets/SideMenuWidget.jsm
devtools/client/shared/widgets/TableWidget.js
devtools/client/shared/widgets/TreeWidget.js
devtools/client/shared/widgets/VariablesView.jsm
devtools/client/shared/widgets/tooltip/SwatchBasedEditorTooltip.js
devtools/client/shared/widgets/tooltip/Tooltip.js
devtools/client/shared/widgets/view-helpers.js
--- a/devtools/client/shared/test/browser_treeWidget_keyboard_interaction.js
+++ b/devtools/client/shared/test/browser_treeWidget_keyboard_interaction.js
@@ -6,19 +6,16 @@
 
 // Tests that keyboard interaction works fine with the tree widget
 
 const TEST_URI = "data:text/html;charset=utf-8,<head>" +
   "<link rel='stylesheet' type='text/css' href='chrome://devtools/skin/widg" +
   "ets.css'></head><body><div></div><span></span></body>";
 const {TreeWidget} = require("devtools/client/shared/widgets/TreeWidget");
 
-const kStrictKeyPressEvents = SpecialPowers.getBoolPref(
-  "dom.keyboardevent.keypress.dispatch_non_printable_keys_only_system_group_in_content");
-
 add_task(async function () {
   await addTab("about:blank");
   let [host, win, doc] = await createHost("bottom", TEST_URI);
 
   let tree = new TreeWidget(doc.querySelector("div"), {
     defaultType: "store"
   });
 
@@ -141,18 +138,17 @@ async function testKeyboardInteraction(t
   EventUtils.synthesizeKey("KEY_ArrowDown", {}, win);
   [name, data, attachment] = await event.promise;
   is(data.length, 2, "Correct level item was selected after fourth down keypress");
   is(data[0], "level1", "Correct parent level");
   is(data[1], "level2-1", "Correct second level");
 
   // pressing left to check expand collapse feature.
   // This does not emit any event, so listening for keypress
-  const eventToListen = kStrictKeyPressEvents ? "keydown" : "keypress";
-  tree.root.children.addEventListener(eventToListen, () => {
+  tree.root.children.addEventListener("keydown", () => {
     // executeSoon so that other listeners on the same method are executed first
     executeSoon(() => event.resolve(null));
   }, {once: true});
   info("Pressing left key to collapse the item");
   event = defer();
   node = tree._selectedLabel;
   ok(node.hasAttribute("expanded"), "Item is expanded before left keypress");
   EventUtils.synthesizeKey("KEY_ArrowLeft", {}, win);
@@ -184,47 +180,47 @@ async function testKeyboardInteraction(t
   EventUtils.synthesizeKey("KEY_ArrowDown", {}, win);
   [name, data, attachment] = await event.promise;
   is(data.length, 2, "Correct level item was selected after fifth down keypress");
   is(data[0], "level1", "Correct parent level");
   is(data[1], "level2-1", "Correct second level");
 
   // collapsing the item to check expand feature.
 
-  tree.root.children.addEventListener(eventToListen, () => {
+  tree.root.children.addEventListener("keydown", () => {
     executeSoon(() => event.resolve(null));
   }, {once: true});
   info("Pressing left key to collapse the item");
   event = defer();
   node = tree._selectedLabel;
   ok(node.hasAttribute("expanded"), "Item is expanded before left keypress");
   EventUtils.synthesizeKey("KEY_ArrowLeft", {}, win);
   await event.promise;
   ok(!node.hasAttribute("expanded"), "Item is collapsed after left keypress");
 
   // pressing right should expand this now.
 
-  tree.root.children.addEventListener(eventToListen, () => {
+  tree.root.children.addEventListener("keydown", () => {
     executeSoon(() => event.resolve(null));
   }, {once: true});
   info("Pressing right key to expend the collapsed item");
   event = defer();
   node = tree._selectedLabel;
   ok(!node.hasAttribute("expanded"), "Item is collapsed before right keypress");
   EventUtils.synthesizeKey("KEY_ArrowRight", {}, win);
   await event.promise;
   ok(node.hasAttribute("expanded"), "Item is expanded after right keypress");
 
   // selecting last item node to test edge navigation case
 
   tree.selectedItem = ["level1.1", "level2", "level3"];
   node = tree._selectedLabel;
   // pressing down again should not change selection
   event = defer();
-  tree.root.children.addEventListener(eventToListen, () => {
+  tree.root.children.addEventListener("keydown", () => {
     executeSoon(() => event.resolve(null));
   }, {once: true});
   info("Pressing down key on last item of the tree");
   EventUtils.synthesizeKey("KEY_ArrowDown", {}, win);
   await event.promise;
 
   ok(tree.isSelected(["level1.1", "level2", "level3"]),
      "Last item is still selected after pressing down on last item of the tree");
--- a/devtools/client/shared/widgets/AbstractTreeItem.jsm
+++ b/devtools/client/shared/widgets/AbstractTreeItem.jsm
@@ -437,32 +437,32 @@ AbstractTreeItem.prototype = {
    */
   _constructTargetNode: function () {
     if (this._constructed) {
       return;
     }
     this._onArrowClick = this._onArrowClick.bind(this);
     this._onClick = this._onClick.bind(this);
     this._onDoubleClick = this._onDoubleClick.bind(this);
-    this._onKeyPress = this._onKeyPress.bind(this);
+    this._onKeyDown = this._onKeyDown.bind(this);
     this._onFocus = this._onFocus.bind(this);
     this._onBlur = this._onBlur.bind(this);
 
     let document = this.document;
 
     let arrowNode = this._arrowNode = document.createElement("hbox");
     arrowNode.className = "arrow theme-twisty";
     arrowNode.addEventListener("mousedown", this._onArrowClick);
 
     let targetNode = this._targetNode = this._displaySelf(document, arrowNode);
     targetNode.style.MozUserFocus = "normal";
 
     targetNode.addEventListener("mousedown", this._onClick);
     targetNode.addEventListener("dblclick", this._onDoubleClick);
-    targetNode.addEventListener("keypress", this._onKeyPress);
+    targetNode.addEventListener("keydown", this._onKeyDown);
     targetNode.addEventListener("focus", this._onFocus);
     targetNode.addEventListener("blur", this._onBlur);
 
     this._constructed = true;
   },
 
   /**
    * Gets the element displaying an item in the tree at the specified offset
@@ -574,19 +574,19 @@ AbstractTreeItem.prototype = {
     // click events.
     if (!e.target.classList.contains("arrow")) {
       this._onArrowClick(e);
     }
     this.focus();
   },
 
   /**
-   * Handler for the "keypress" event on the element displaying this tree item.
+   * Handler for the "keydown" event on the element displaying this tree item.
    */
-  _onKeyPress: function (e) {
+  _onKeyDown: function (e) {
     // Prevent scrolling when pressing navigation keys.
     ViewHelpers.preventScrolling(e);
 
     switch (e.keyCode) {
       case KeyCodes.DOM_VK_UP:
         this._focusPrevNode();
         return;
 
--- a/devtools/client/shared/widgets/BreadcrumbsWidget.jsm
+++ b/devtools/client/shared/widgets/BreadcrumbsWidget.jsm
@@ -31,17 +31,17 @@ this.BreadcrumbsWidget = function Breadc
 
   // Create an internal arrowscrollbox container.
   this._list = this.document.createElement("arrowscrollbox");
   this._list.className = "breadcrumbs-widget-container";
   this._list.setAttribute("flex", "1");
   this._list.setAttribute("orient", "horizontal");
   this._list.setAttribute("clicktoscroll", "true");
   this._list.setAttribute("smoothscroll", !!aOptions.smoothScroll);
-  this._list.addEventListener("keypress", e => this.emit("keyPress", e));
+  this._list.addEventListener("keydown", e => this.emit("keyDown", e));
   this._list.addEventListener("mousedown", e => this.emit("mousePress", e));
   this._parent.appendChild(this._list);
 
   // By default, hide the arrows. We let the arrowscrollbox show them
   // in case of overflow.
   this._list._scrollButtonUp.collapsed = true;
   this._list._scrollButtonDown.collapsed = true;
   this._list.addEventListener("underflow", this._onUnderflow.bind(this));
--- a/devtools/client/shared/widgets/FastListWidget.js
+++ b/devtools/client/shared/widgets/FastListWidget.js
@@ -27,17 +27,17 @@ const FastListWidget = module.exports = 
   this._templateElement = this.document.createElement("hbox");
 
   // Create an internal scrollbox container.
   this._list = this.document.createElement("scrollbox");
   this._list.className = "fast-list-widget-container theme-body";
   this._list.setAttribute("flex", "1");
   this._list.setAttribute("orient", "vertical");
   this._list.setAttribute("tabindex", "0");
-  this._list.addEventListener("keypress", e => this.emit("keyPress", e));
+  this._list.addEventListener("keydown", e => this.emit("keyDown", e));
   this._list.addEventListener("mousedown", e => this.emit("mousePress", e));
   this._parent.appendChild(this._list);
 
   this._orderedMenuElementsArray = [];
   this._itemsByElement = new Map();
 
   // This widget emits events that can be handled in a MenuContainer.
   EventEmitter.decorate(this);
--- a/devtools/client/shared/widgets/FilterWidget.js
+++ b/devtools/client/shared/widgets/FilterWidget.js
@@ -336,17 +336,17 @@ CSSFilterEditorWidget.prototype = {
 
     const filterEl = e.target.closest(".filter");
     const index = this._getFilterElementIndex(filterEl);
     const filter = this.filters[index];
 
     // Filters that have units are number-type filters. For them,
     // the value can be incremented/decremented simply.
     // For other types of filters (e.g. drop-shadow) we need to check
-    // if the keypress happened close to a number first.
+    // if the keydown happened close to a number first.
     if (filter.unit) {
       let startValue = parseFloat(e.target.value);
       let value = startValue + direction * multiplier;
 
       const [min, max] = this._definition(filter.name).range;
       if (value < min) {
         value = min;
       } else if (value > max) {
--- a/devtools/client/shared/widgets/FlameGraph.js
+++ b/devtools/client/shared/widgets/FlameGraph.js
@@ -180,27 +180,25 @@ function FlameGraph(parent, sharpness) {
     let fontFamily = FLAME_GRAPH_BLOCK_TEXT_FONT_FAMILY;
     this._ctx.font = fontSize + "px " + fontFamily;
     this._averageCharWidth = this._calcAverageCharWidth();
     this._overflowCharWidth = this._getTextWidth(this.overflowChar);
 
     this._onAnimationFrame = this._onAnimationFrame.bind(this);
     this._onKeyDown = this._onKeyDown.bind(this);
     this._onKeyUp = this._onKeyUp.bind(this);
-    this._onKeyPress = this._onKeyPress.bind(this);
     this._onMouseMove = this._onMouseMove.bind(this);
     this._onMouseDown = this._onMouseDown.bind(this);
     this._onMouseUp = this._onMouseUp.bind(this);
     this._onMouseWheel = this._onMouseWheel.bind(this);
     this._onResize = this._onResize.bind(this);
     this.refresh = this.refresh.bind(this);
 
     this._window.addEventListener("keydown", this._onKeyDown);
     this._window.addEventListener("keyup", this._onKeyUp);
-    this._window.addEventListener("keypress", this._onKeyPress);
     this._window.addEventListener("mousemove", this._onMouseMove);
     this._window.addEventListener("mousedown", this._onMouseDown);
     this._window.addEventListener("mouseup", this._onMouseUp);
     this._window.addEventListener("MozMousePixelScroll", this._onMouseWheel);
 
     let ownerWindow = this._parent.ownerDocument.defaultView;
     ownerWindow.addEventListener("resize", this._onResize);
 
@@ -234,17 +232,16 @@ FlameGraph.prototype = {
   /**
    * Destroys this graph.
    */
   destroy: Task.async(function* () {
     yield this.ready();
 
     this._window.removeEventListener("keydown", this._onKeyDown);
     this._window.removeEventListener("keyup", this._onKeyUp);
-    this._window.removeEventListener("keypress", this._onKeyPress);
     this._window.removeEventListener("mousemove", this._onMouseMove);
     this._window.removeEventListener("mousedown", this._onMouseDown);
     this._window.removeEventListener("mouseup", this._onMouseUp);
     this._window.removeEventListener("MozMousePixelScroll", this._onMouseWheel);
 
     let ownerWindow = this._parent.ownerDocument.defaultView;
     if (ownerWindow) {
       ownerWindow.removeEventListener("resize", this._onResize);
@@ -934,23 +931,16 @@ FlameGraph.prototype = {
     if (this._keysPressed[e.keyCode]) {
       this._keysPressed[e.keyCode] = false;
       this._userInputStack--;
       this._shouldRedraw = true;
     }
   },
 
   /**
-   * Listener for the "keypress" event on the graph's container.
-   */
-  _onKeyPress: function (e) {
-    ViewHelpers.preventScrolling(e);
-  },
-
-  /**
    * Listener for the "mousemove" event on the graph's container.
    */
   _onMouseMove: function (e) {
     let {mouseX, mouseY} = this._getRelativeEventCoordinates(e);
 
     let canvasWidth = this._width;
 
     let selection = this._selection;
--- a/devtools/client/shared/widgets/SideMenuWidget.jsm
+++ b/devtools/client/shared/widgets/SideMenuWidget.jsm
@@ -49,17 +49,17 @@ this.SideMenuWidget = function SideMenuW
   this._list.className = "side-menu-widget-container theme-sidebar";
   this._list.setAttribute("flex", "1");
   this._list.setAttribute("orient", "vertical");
   this._list.setAttribute("with-arrows", this._showArrows);
   this._list.setAttribute("with-item-checkboxes", this._showItemCheckboxes);
   this._list.setAttribute("with-group-checkboxes", this._showGroupCheckboxes);
   this._list.setAttribute("tabindex", "0");
   this._list.addEventListener("contextmenu", e => this._showContextMenu(e));
-  this._list.addEventListener("keypress", e => this.emit("keyPress", e));
+  this._list.addEventListener("keydown", e => this.emit("keyDown", e));
   this._list.addEventListener("mousedown", e => this.emit("mousePress", e));
   this._parent.appendChild(this._list);
 
   // Menu items can optionally be grouped.
   this._groupsByName = new Map(); // Can't use a WeakMap because keys are strings.
   this._orderedGroupElementsArray = [];
   this._orderedMenuElementsArray = [];
   this._itemsByElement = new Map();
--- a/devtools/client/shared/widgets/TableWidget.js
+++ b/devtools/client/shared/widgets/TableWidget.js
@@ -1755,17 +1755,17 @@ EditableFieldsEngine.prototype = {
    * @param  {EventTarget} target
    *         Calling event's target.
    */
   onTrigger: function ({target}) {
     this.edit(target);
   },
 
   /**
-   * Handle keypresses when in edit mode:
+   * Handle keydowns when in edit mode:
    *   - <escape> revert the value and close the textbox.
    *   - <return> apply the value and close the textbox.
    *   - <tab> Handled by the consumer's `onTab` callback.
    *   - <shift><tab> Handled by the consumer's `onTab` callback.
    *
    * @param  {Event} event
    *         The calling event.
    */
--- a/devtools/client/shared/widgets/TreeWidget.js
+++ b/devtools/client/shared/widgets/TreeWidget.js
@@ -130,17 +130,17 @@ TreeWidget.prototype = {
         let menu = this.document.getElementById(this.contextMenuId);
         menu.openPopupAtScreen(event.screenX, event.screenY, true);
       });
     }
 
     this._parent.appendChild(this.root.children);
 
     this.root.children.addEventListener("mousedown", e => this.onClick(e));
-    this.root.children.addEventListener("keypress", e => this.onKeypress(e));
+    this.root.children.addEventListener("keydown", e => this.onKeydown(e));
   },
 
   /**
    * Sets the text to be shown when no node is present in the tree
    */
   setPlaceholderText: function (text) {
     this.placeholder.textContent = text;
   },
@@ -336,20 +336,20 @@ TreeWidget.prototype = {
 
     if (this._selectedLabel != target) {
       let ids = target.parentNode.getAttribute("data-id");
       this.selectedItem = JSON.parse(ids);
     }
   },
 
   /**
-   * Keypress handler for this tree. Used to select next and previous visible
+   * Keydown handler for this tree. Used to select next and previous visible
    * items, as well as collapsing and expanding any item.
    */
-  onKeypress: function (event) {
+  onKeydown: function (event) {
     switch (event.keyCode) {
       case KeyCodes.DOM_VK_UP:
         this.selectPreviousItem();
         break;
 
       case KeyCodes.DOM_VK_DOWN:
         this.selectNextItem();
         break;
--- a/devtools/client/shared/widgets/VariablesView.jsm
+++ b/devtools/client/shared/widgets/VariablesView.jsm
@@ -76,24 +76,22 @@ this.VariablesView = function VariablesV
   this._currHierarchy = new Map();
 
   this._parent = aParentNode;
   this._parent.classList.add("variables-view-container");
   this._parent.classList.add("theme-body");
   this._appendEmptyNotice();
 
   this._onSearchboxInput = this._onSearchboxInput.bind(this);
-  this._onSearchboxKeyPress = this._onSearchboxKeyPress.bind(this);
-  this._onViewKeyPress = this._onViewKeyPress.bind(this);
+  this._onSearchboxKeyDown = this._onSearchboxKeyDown.bind(this);
   this._onViewKeyDown = this._onViewKeyDown.bind(this);
 
   // Create an internal scrollbox container.
   this._list = this.document.createElement("scrollbox");
   this._list.setAttribute("orient", "vertical");
-  this._list.addEventListener("keypress", this._onViewKeyPress);
   this._list.addEventListener("keydown", this._onViewKeyDown);
   this._parent.appendChild(this._list);
 
   for (let name in aFlags) {
     this[name] = aFlags[name];
   }
 
   EventEmitter.decorate(this);
@@ -187,19 +185,17 @@ VariablesView.prototype = {
    * @see VariablesView.empty
    * @see VariablesView.commitHierarchy
    */
   _emptySoon: function (aTimeout) {
     let prevList = this._list;
     let currList = this._list = this.document.createElement("scrollbox");
 
     this.window.setTimeout(() => {
-      prevList.removeEventListener("keypress", this._onViewKeyPress);
       prevList.removeEventListener("keydown", this._onViewKeyDown);
-      currList.addEventListener("keypress", this._onViewKeyPress);
       currList.addEventListener("keydown", this._onViewKeyDown);
       currList.setAttribute("orient", "vertical");
 
       this._parent.removeChild(prevList);
       this._parent.appendChild(currList);
 
       if (!this._store.length) {
         this._appendEmptyNotice();
@@ -452,34 +448,34 @@ VariablesView.prototype = {
     container.hidden = !this._store.length;
 
     let searchbox = this._searchboxNode = document.createElement("textbox");
     searchbox.className = "variables-view-searchinput devtools-filterinput";
     searchbox.setAttribute("placeholder", this._searchboxPlaceholder);
     searchbox.setAttribute("type", "search");
     searchbox.setAttribute("flex", "1");
     searchbox.addEventListener("command", this._onSearchboxInput);
-    searchbox.addEventListener("keypress", this._onSearchboxKeyPress);
+    searchbox.addEventListener("keydown", this._onSearchboxKeyDown);
 
     container.appendChild(searchbox);
     ownerNode.insertBefore(container, this._parent);
   },
 
   /**
    * Disables variable and property searching in this view.
    * Use the "searchEnabled" setter to disable searching.
    */
   _disableSearch: function () {
     // If searching was already disabled, no need to re-disable it again.
     if (!this._searchboxContainer) {
       return;
     }
     this._searchboxContainer.remove();
     this._searchboxNode.removeEventListener("command", this._onSearchboxInput);
-    this._searchboxNode.removeEventListener("keypress", this._onSearchboxKeyPress);
+    this._searchboxNode.removeEventListener("keydown", this._onSearchboxKeyDown);
 
     this._searchboxContainer = null;
     this._searchboxNode = null;
   },
 
   /**
    * Sets the variables searchbox container hidden or visible.
    * It's hidden by default.
@@ -498,19 +494,19 @@ VariablesView.prototype = {
   /**
    * Listener handling the searchbox input event.
    */
   _onSearchboxInput: function () {
     this.scheduleSearch(this._searchboxNode.value);
   },
 
   /**
-   * Listener handling the searchbox key press event.
+   * Listener handling the searchbox keydown event.
    */
-  _onSearchboxKeyPress: function (e) {
+  _onSearchboxKeyDown: function (e) {
     switch (e.keyCode) {
       case KeyCodes.DOM_VK_RETURN:
         this._onSearchboxInput();
         return;
       case KeyCodes.DOM_VK_ESCAPE:
         this._searchboxNode.value = "";
         this._onSearchboxInput();
         return;
@@ -806,25 +802,35 @@ VariablesView.prototype = {
       aItem.collapse();
     }
     aItem._target.focus();
     this.boxObject.ensureElementIsVisible(aItem._arrow);
     return true;
   },
 
   /**
-   * Listener handling a key press event on the view.
+   * Listener handling a key down event on the view.
    */
-  _onViewKeyPress: function (e) {
+  _onViewKeyDown: function (e) {
     let item = this.getFocusedItem();
 
     // Prevent scrolling when pressing navigation keys.
     ViewHelpers.preventScrolling(e);
 
     switch (e.keyCode) {
+      case KeyCodes.DOM_VK_C:
+        // Copy current selection to clipboard.
+        if (e.ctrlKey || e.metaKey) {
+          let item = this.getFocusedItem();
+          clipboardHelper.copyString(
+            item._nameString + item.separatorStr + item._valueString
+          );
+        }
+        return;
+
       case KeyCodes.DOM_VK_UP:
         // Always rewind focus.
         this.focusPrevItem(true);
         return;
 
       case KeyCodes.DOM_VK_DOWN:
         // Always advance focus.
         this.focusNextItem(true);
@@ -895,31 +901,16 @@ VariablesView.prototype = {
 
       case KeyCodes.DOM_VK_INSERT:
         item._onAddProperty(e);
         return;
     }
   },
 
   /**
-   * Listener handling a key down event on the view.
-   */
-  _onViewKeyDown: function (e) {
-    if (e.keyCode == KeyCodes.DOM_VK_C) {
-      // Copy current selection to clipboard.
-      if (e.ctrlKey || e.metaKey) {
-        let item = this.getFocusedItem();
-        clipboardHelper.copyString(
-          item._nameString + item.separatorStr + item._valueString
-        );
-      }
-    }
-  },
-
-  /**
    * Sets the text displayed in this container when there are no available items.
    * @param string aValue
    */
   set emptyText(aValue) {
     if (this._emptyTextNode) {
       this._emptyTextNode.setAttribute("value", aValue);
     }
     this._emptyTextValue = aValue;
@@ -4011,35 +4002,35 @@ Editable.prototype = {
     // When the value is a string (displayed as "value"), then we probably want
     // to change it to another string in the textbox, so to avoid typing the ""
     // again, tackle with the selection bounds just a bit.
     if (initialString.match(/^".+"$/)) {
       input.selectionEnd--;
       input.selectionStart++;
     }
 
-    this._onKeypress = this._onKeypress.bind(this);
+    this._onKeydown = this._onKeydown.bind(this);
     this._onBlur = this._onBlur.bind(this);
-    input.addEventListener("keypress", this._onKeypress);
+    input.addEventListener("keydown", this._onKeydown);
     input.addEventListener("blur", this._onBlur);
 
     this._prevExpandable = this._variable.twisty;
     this._prevExpanded = this._variable.expanded;
     this._variable.collapse();
     this._variable.hideArrow();
     this._variable.locked = true;
     this._variable.editing = true;
   },
 
   /**
    * Remove the input box and restore the Variable or Property to its previous
    * state.
    */
   deactivate: function () {
-    this._input.removeEventListener("keypress", this._onKeypress);
+    this._input.removeEventListener("keydown", this._onKeydown);
     this._input.removeEventListener("blur", this.deactivate);
     this._input.parentNode.replaceChild(this.label, this._input);
     this._input = null;
 
     let { boxObject } = this._variable._variablesView;
     boxObject.scrollBy(-this._variable._target, 0);
     this._variable.locked = false;
     this._variable.twisty = this._prevExpandable;
@@ -4082,17 +4073,17 @@ Editable.prototype = {
    */
   _onBlur: function () {
     this.deactivate();
   },
 
   /**
    * Event handler for when the input receives a key press.
    */
-  _onKeypress: function (e) {
+  _onKeydown: function (e) {
     e.stopPropagation();
 
     switch (e.keyCode) {
       case KeyCodes.DOM_VK_TAB:
         this._next();
         break;
       case KeyCodes.DOM_VK_RETURN:
         this._save();
--- a/devtools/client/shared/widgets/tooltip/SwatchBasedEditorTooltip.js
+++ b/devtools/client/shared/widgets/tooltip/SwatchBasedEditorTooltip.js
@@ -208,40 +208,40 @@ class SwatchBasedEditorTooltip {
   preview(value) {
     if (this.activeSwatch) {
       let swatch = this.swatches.get(this.activeSwatch);
       swatch.callbacks.onPreview(value);
     }
   }
 
   /**
-   * This parent class only calls this on <esc> keypress
+   * This parent class only calls this on <esc> keydown
    */
   revert() {
     if (this.activeSwatch) {
       this._reverted = true;
       let swatch = this.swatches.get(this.activeSwatch);
       this.tooltip.once("hidden", () => {
         swatch.callbacks.onRevert();
       });
     }
   }
 
   /**
-   * This parent class only calls this on <enter> keypress
+   * This parent class only calls this on <enter> keydown
    */
   commit() {
     if (this.activeSwatch) {
       let swatch = this.swatches.get(this.activeSwatch);
       swatch.callbacks.onCommit();
     }
   }
 
   destroy() {
     this.swatches.clear();
     this.activeSwatch = null;
-    this.tooltip.off("keypress", this._onTooltipKeypress);
+    this.tooltip.off("keydown", this._onTooltipKeydown);
     this.tooltip.destroy();
     this.shortcuts.destroy();
   }
 }
 
 module.exports = SwatchBasedEditorTooltip;
--- a/devtools/client/shared/widgets/tooltip/Tooltip.js
+++ b/devtools/client/shared/widgets/tooltip/Tooltip.js
@@ -80,17 +80,17 @@ const POPUP_EVENTS = ["shown", "hidden",
  *        - noAutoFocus {Boolean} Should the focus automatically go to the panel
  *        when it opens. Defaults to true.
  *
  * Fires these events:
  * - showing : just before the tooltip shows
  * - shown : when the tooltip is shown
  * - hiding : just before the tooltip closes
  * - hidden : when the tooltip gets hidden
- * - keypress : when any key gets pressed, with keyCode
+ * - keydown : when any key gets pressed, with keyCode
  */
 
 class Tooltip {
   constructor(doc, {
   consumeOutsideClick = false,
   closeOnKeys = [ESCAPE_KEYCODE],
   noAutoFocus = true,
   closeOnEvents = [],
@@ -126,31 +126,31 @@ class Tooltip {
             this.emit(name);
           }
         };
       })(eventName);
       this.panel.addEventListener("popup" + eventName,
         this["_onPopup" + eventName]);
     }
 
-  // Listen to keypress events to close the tooltip if configured to do so
+  // Listen to keydown events to close the tooltip if configured to do so
     let win = this.doc.querySelector("window");
-    this._onKeyPress = event => {
+    this._onKeyDown = event => {
       if (this.panel.hidden) {
         return;
       }
 
-      this.emit("keypress", event.keyCode);
+      this.emit("keydown", event.keyCode);
       if (this.closeOnKeys.includes(event.keyCode) &&
           this.isShown()) {
         event.stopPropagation();
         this.hide();
       }
     };
-    win.addEventListener("keypress", this._onKeyPress);
+    win.addEventListener("keydown", this._onKeyDown);
 
   // Listen to custom emitters' events to close the tooltip
     this.hide = this.hide.bind(this);
     for (let {emitter, event, useCapture} of this.closeOnEvents) {
       for (let add of ["addEventListener", "on"]) {
         if (add in emitter) {
           emitter[add](event, this.hide, useCapture);
           break;
@@ -229,17 +229,17 @@ class Tooltip {
     this.hide();
 
     for (let eventName of POPUP_EVENTS) {
       this.panel.removeEventListener("popup" + eventName,
         this["_onPopup" + eventName]);
     }
 
     let win = this.doc.querySelector("window");
-    win.removeEventListener("keypress", this._onKeyPress);
+    win.removeEventListener("keydown", this._onKeyDown);
 
     for (let {emitter, event, useCapture} of this.closeOnEvents) {
       for (let remove of ["removeEventListener", "off"]) {
         if (remove in emitter) {
           emitter[remove](event, this.hide, useCapture);
           break;
         }
       }
--- a/devtools/client/shared/widgets/view-helpers.js
+++ b/devtools/client/shared/widgets/view-helpers.js
@@ -192,17 +192,17 @@ const ViewHelpers = exports.ViewHelpers 
         e.stopPropagation();
     }
   },
 
   /**
    * Check if the enter key or space was pressed
    *
    * @param event event
-   *        The event triggered by a keypress on an element
+   *        The event triggered by a keydown or keypress on an element
    */
   isSpaceOrReturn: function (event) {
     return event.keyCode === KeyCodes.DOM_VK_SPACE ||
           event.keyCode === KeyCodes.DOM_VK_RETURN;
   },
 
   /**
    * Sets a toggled pane hidden or visible. The pane can either be displayed on
@@ -502,17 +502,17 @@ Item.prototype = {
  *
  * Optional attributes that may be handled (when calling
  * get/set/removeAttribute):
  *   - "emptyText": label temporarily added when there are no items present
  *   - "headerText": label permanently added as a header
  *
  * For automagical keyboard and mouse accessibility, the widget should be an
  * event emitter with the following events:
- *   - "keyPress" -> (aName:string, aEvent:KeyboardEvent)
+ *   - "keyDown" -> (aName:string, aEvent:KeyboardEvent)
  *   - "mousePress" -> (aName:string, aEvent:MouseEvent)
  */
 const WidgetMethods = exports.WidgetMethods = {
   /**
    * Sets the element node or widget associated with this container.
    * @param nsIDOMNode | object widget
    */
   set widget(widget) {
@@ -521,17 +521,17 @@ const WidgetMethods = exports.WidgetMeth
     // Can't use a WeakMap for _itemsByValue because keys are strings, and
     // can't use one for _itemsByElement either, since it needs to be iterable.
     this._itemsByValue = new Map();
     this._itemsByElement = new Map();
     this._stagedItems = [];
 
     // Handle internal events emitted by the widget if necessary.
     if (ViewHelpers.isEventEmitter(widget)) {
-      widget.on("keyPress", this._onWidgetKeyPress.bind(this));
+      widget.on("keyDown", this._onWidgetKeyDown.bind(this));
       widget.on("mousePress", this._onWidgetMousePress.bind(this));
     }
   },
 
   /**
    * Gets the element node or widget associated with this container.
    * @return nsIDOMNode | object
    */
@@ -1484,21 +1484,21 @@ const WidgetMethods = exports.WidgetMeth
    *        The item describing a target element.
    */
   _unlinkItem: function (item) {
     this._itemsByValue.delete(item._value);
     this._itemsByElement.delete(item._target);
   },
 
   /**
-   * The keyPress event listener for this container.
+   * The keyDown event listener for this container.
    * @param string name
    * @param KeyboardEvent event
    */
-  _onWidgetKeyPress: function (name, event) {
+  _onWidgetKeyDown: function (name, event) {
     // Prevent scrolling when pressing navigation keys.
     ViewHelpers.preventScrolling(event);
 
     switch (event.keyCode) {
       case KeyCodes.DOM_VK_UP:
       case KeyCodes.DOM_VK_LEFT:
         this.focusPrevItem();
         break;