diff --git a/dom/base/BrowserElementChild.js b/dom/base/BrowserElementChild.js index 8f6bcf742d7..fcff9b5a276 100644 --- a/dom/base/BrowserElementChild.js +++ b/dom/base/BrowserElementChild.js @@ -9,6 +9,15 @@ let Ci = Components.interfaces; let Cc = Components.classes; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +// Event whitelisted for bubbling. +let whitelistedEvents = [ + Ci.nsIDOMKeyEvent.DOM_VK_ESCAPE, // Back button. + Ci.nsIDOMKeyEvent.DOM_VK_CONTEXT_MENU, + Ci.nsIDOMKeyEvent.DOM_VK_F5, // Search button. + Ci.nsIDOMKeyEvent.DOM_VK_PAGE_UP, // Volume up. + Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN // Volume down. +]; + function debug(msg) { //dump("BrowserElementChild - " + msg + "\n"); } @@ -32,6 +41,8 @@ function sendSyncMsg(msg, data) { * the parent process. */ +var global = this; + function BrowserElementChild() { this._init(); }; @@ -57,7 +68,7 @@ BrowserElementChild.prototype = { // Get the app manifest from the parent, if our frame has one. let appManifestURL = sendSyncMsg('get-mozapp-manifest-url')[0]; let windowUtils = content.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Components.interfaces.nsIDOMWindowUtils); + .getInterface(Ci.nsIDOMWindowUtils); if (!!appManifestURL) { windowUtils.setIsApp(true); @@ -78,6 +89,21 @@ BrowserElementChild.prototype = { addMessageListener("browser-element-api:get-screenshot", this._recvGetScreenshot.bind(this)); + + let els = Cc["@mozilla.org/eventlistenerservice;1"] + .getService(Ci.nsIEventListenerService); + + // We are using the system group for those events so if something in the + // content called .stopPropagation() this will still be called. + els.addSystemEventListener(global, 'keydown', + this._keyEventHandler.bind(this), + /* useCapture = */ true); + els.addSystemEventListener(global, 'keypress', + this._keyEventHandler.bind(this), + /* useCapture = */ true); + els.addSystemEventListener(global, 'keyup', + this._keyEventHandler.bind(this), + /* useCapture = */ true); }, _titleChangedHandler: function(e) { @@ -129,6 +155,16 @@ BrowserElementChild.prototype = { }); }, + _keyEventHandler: function(e) { + if (whitelistedEvents.indexOf(e.keyCode) != -1 && !e.defaultPrevented) { + sendAsyncMsg('keyevent', { + type: e.type, + code: e.keyCode, + charCode: e.charCode, + }); + } + }, + // The docShell keeps a weak reference to the progress listener, so we need // to keep a strong ref to it ourselves. _progressListener: { diff --git a/dom/base/BrowserElementParent.js b/dom/base/BrowserElementParent.js index 4cde5d26f43..9c0a03f61e3 100644 --- a/dom/base/BrowserElementParent.js +++ b/dom/base/BrowserElementParent.js @@ -106,6 +106,7 @@ BrowserElementParent.prototype = { addMessageListener("titlechange", this._fireEventFromMsg); addMessageListener("iconchange", this._fireEventFromMsg); addMessageListener("get-mozapp-manifest-url", this._sendMozAppManifestURL); + addMessageListener("keyevent", this._fireKeyEvent); mm.addMessageListener('browser-element-api:got-screenshot', this._recvGotScreenshot.bind(this)); @@ -164,6 +165,18 @@ BrowserElementParent.prototype = { return req; }, + _fireKeyEvent: function(frameElement, data) { + let win = frameElement.ownerDocument.defaultView; + let evt = frameElement.ownerDocument.createEvent("KeyboardEvent"); + + evt.initKeyEvent(data.json.type, true, true, win, + false, false, false, false, // modifiers + data.json.keyCode, + data.json.charCode); + + frameElement.dispatchEvent(evt); + }, + observe: function(subject, topic, data) { switch(topic) { case 'app-startup': diff --git a/dom/tests/mochitest/browser-frame/Makefile.in b/dom/tests/mochitest/browser-frame/Makefile.in index 92e8c6dc1fb..0544969c275 100644 --- a/dom/tests/mochitest/browser-frame/Makefile.in +++ b/dom/tests/mochitest/browser-frame/Makefile.in @@ -14,6 +14,7 @@ include $(topsrcdir)/config/rules.mk _TEST_FILES = \ file_empty.html \ + file_focus.html \ browserFrameHelpers.js \ test_browserFrame1.html \ test_browserFrame2.html \ @@ -24,6 +25,7 @@ _TEST_FILES = \ test_browserFrame7.html \ test_browserFrame8.html \ test_browserFrame9.html \ + test_browserFrame_keyEvents.html \ $(NULL) libs:: $(_TEST_FILES) diff --git a/dom/tests/mochitest/browser-frame/browserFrameHelpers.js b/dom/tests/mochitest/browser-frame/browserFrameHelpers.js index 6d834cd2724..f75478783c7 100644 --- a/dom/tests/mochitest/browser-frame/browserFrameHelpers.js +++ b/dom/tests/mochitest/browser-frame/browserFrameHelpers.js @@ -106,6 +106,9 @@ const browserFrameHelpers = { 'emptyPage2': 'http://example.org' + window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) + '/file_empty.html', + 'focusPage': 'http://example.org' + + window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) + + '/file_focus.html', }; browserFrameHelpers.origEnabledPref = browserFrameHelpers.getEnabledPref(); diff --git a/dom/tests/mochitest/browser-frame/file_focus.html b/dom/tests/mochitest/browser-frame/file_focus.html new file mode 100644 index 00000000000..563858a9b9d --- /dev/null +++ b/dom/tests/mochitest/browser-frame/file_focus.html @@ -0,0 +1,25 @@ + +
+ +Aloha! My URL is . + + + + + + diff --git a/dom/tests/mochitest/browser-frame/test_browserFrame_keyEvents.html b/dom/tests/mochitest/browser-frame/test_browserFrame_keyEvents.html new file mode 100644 index 00000000000..a63a7feec62 --- /dev/null +++ b/dom/tests/mochitest/browser-frame/test_browserFrame_keyEvents.html @@ -0,0 +1,99 @@ + + + + +