如何在 AddonSDK 中成功发出 KeyboardEvent "Ctrl+T"

How to successfully emit KeyboardEvent "Ctrl+T" in AddonSDK

我在 Mozilla AddonSDK 上的一个小任务上需要一些帮助。

我正在尝试在新选项卡中打开元素 hyperlink,同时保留浏览器会话状态和任何 JavaScript 事件。

这意味着简单地抓住元素的 hreftab.open(href) 不太可能提供理想的支持。

最好在某个元素上模拟 Ctrl+ 打开 link在一个新的 window.

当前尝试:

var tabs = require("sdk/tabs");

exports.testOpenTabCommand = function(assert, done) {
  var html = 'data:text/html,<html><title></title><body><a href="http://example.com">Click</a></body></html>';
  var script = [
    'self.port.on("openNewTab", function(selector){',
    '  var elm = document.querySelector(selector);',
    '  var ev = new KeyboardEvent(\'keydown\', {',
    '    ctrlKey: true,',
    '    key: \'t\'',
    '  });',
    '  elm.dispatchEvent(ev);',
    '  self.port.emit("tabOpened", true);',
    '})'
  ].join('');

  tabs.open({
    url: html,
    onLoad: function(tab) {
      var worker = tab.attach({
        contentScript: script,
        contentScriptWhen: 'ready'
      });
      worker.port.on('tabOpened', function (){
        // first tab is `about:blank`
        // second tab is the html above
        // third tab should be the clicked link
        assert.equal(tabs.length, 3);
        tab.close(function(){
          done();
        });
      });
      worker.port.emit('openNewTab', 'a');
    }
  });
};

require('sdk/test').run(exports);

感谢您的回答和评论。

谢谢。

如果我理解正确的话,在我看来你只需要添加 inBackground 属性 当你打开 link 使用 tabs.open:

tabs.open({
  url: href,
  inBackground: true
});

如果不是这种情况,请告诉我,我们会找出替代方案。

更新(见评论):

为了正确合成击键和鼠标事件,尤其是在带有 e10s 的新版 Firefox 中,我们需要做一些更复杂的事情,例如:

const tabs = require("sdk/tabs");
const { OS } = require("sdk/system/runtime");
const { getTabBrowserForTab } = require("sdk/tabs/utils");
const { viewFor } = require("sdk/view/core");

const { Cc, Ci } = require("chrome");

const remote = (f) => "data:application/javascript," + encodeURIComponent(`(${f}())`);

const globalMessageManager = Cc["@mozilla.org/globalmessagemanager;1"]
                              .getService(Ci.nsIMessageListenerManager);

// it would be better put the code of the content function in an
// external module, and then use `framescript/manager` to load it
globalMessageManager.loadFrameScript(remote(function() {
  let domWindowUtils = this.content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                       .getInterface(Components.interfaces.nsIDOMWindowUtils);

  this.addMessageListener("myaddon:click", ({target, json}) => {
    let { accelKey, selector } = json;
    let node = this.content.document.querySelector(selector);
    let { top, left } = node.getBoxQuads()[0].bounds;

    // Simulate the click with the proper accel key
    let accel = domWindowUtils["MODIFIER_" + accelKey];
    domWindowUtils.sendMouseEvent("mousedown", left + 1, top + 1, 0, 1, 0, accel);
    domWindowUtils.sendMouseEvent("mouseup", left + 1, top + 1, 0, 1, accel);

    target.sendAsyncMessage("myaddon:clicked");
  });
}), true);

const synthesizeClickFor = (tab, selector) => new Promise((resolve) => {
  let { selectedBrowser } = getTabBrowserForTab(viewFor(tab));

  globalMessageManager.addMessageListener("myaddon:clicked", function listener({json}) {
    this.removeMessageListener("myaddon:clicked", listener);

    resolve();
  });

  let accelKey = OS === "Darwin" ? "META" : "CONTROL";
  selectedBrowser.messageManager.sendAsyncMessage("myaddon:click", { selector, accelKey });
});

exports.testOpenTabCommand = function(assert, done) {
  var html = "data:text/html,<html><title></title><body><a href='http://mozilla.org'>Click</a></body></html>";

  tabs.open({
    url: html,
    onLoad: function(tab) {
      synthesizeClickFor(tab, "a").then(() => {
        assert.ok(tabs.length, 3, "expected 3 tabs")

        // you need to close also the 3rd tab
        tabs[2].close(() => tab.close(done));
      });
    }
  });
};

require('sdk/test').run(exports);

这模拟左键单击加加速键 (ctrl (MODIFIER_CONTROL) 在 Win / Linux, cmd ⌘ (MODIFIER_META) 在 OS X 上)。您也可以用类似的方式合成密钥,参见:https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIDOMWindowUtils#sendKeyEvent%28%29