如何在 AddonSDK 中成功发出 KeyboardEvent "Ctrl+T"
How to successfully emit KeyboardEvent "Ctrl+T" in AddonSDK
我在 Mozilla AddonSDK 上的一个小任务上需要一些帮助。
我正在尝试在新选项卡中打开元素 hyperlink,同时保留浏览器会话状态和任何 JavaScript 事件。
这意味着简单地抓住元素的 href
和 tab.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
我在 Mozilla AddonSDK 上的一个小任务上需要一些帮助。
我正在尝试在新选项卡中打开元素 hyperlink,同时保留浏览器会话状态和任何 JavaScript 事件。
这意味着简单地抓住元素的 href
和 tab.open(href)
不太可能提供理想的支持。
最好在某个元素上模拟 Ctrl+
当前尝试:
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