Javascript 如何在Gmail中检测键盘事件

Javascript 如何在Gmail中检测键盘事件,javascript,javascript-events,google-chrome-extension,gmail,Javascript,Javascript Events,Google Chrome Extension,Gmail,我正在编写一个浏览器扩展,它需要将处理程序附加到所有页面上的keyup和keydown事件。我可以使用以下内容脚本代码使其工作得非常好 document.addEventListener("keydown",keyDown, true); document.addEventListener("keyup", keyUp, true); 不过,我无法在Gmail中实现这一点。具体地说,在撰写新电子邮件的正文时,我无法让它工作。它将在我测试过的其他任何地方工作。我认为问题是因为Gmai

我正在编写一个浏览器扩展,它需要将处理程序附加到所有页面上的keyup和keydown事件。我可以使用以下内容脚本代码使其工作得非常好

document.addEventListener("keydown",keyDown, true);      
document.addEventListener("keyup", keyUp, true);
不过,我无法在Gmail中实现这一点。具体地说,在撰写新电子邮件的正文时,我无法让它工作。它将在我测试过的其他任何地方工作。我认为问题是因为Gmail正在对所有键盘事件调用
stopPropagation
,但很难调试它们的最小化代码。我认为将第三个参数设置为
true
会导致在
CAPTURE\u阶段捕获事件,但这不起作用

如何在Gmail中用Google Chrome内容脚本编写新正文时捕获
keyup
keydown
事件

编辑:


我通过向清单中添加
“all_frames”:true、
,确保我的内容脚本被注入到DOM的所有iframes中。我甚至尝试使用以下代码:

document.addEventListener("DOMNodeInserted", function (event) {
     if(event.type === "DOMNodeInserted") {
        if(event.srcElement.nodeName === "IFRAME") {
        console.log(event.srcElement.nodeName + " iframe detected");
        event.srcElement.addEventListener("keydown", function(kevent) {
            document.dispatchEvent(kevent);
            }, true);
        event.srcElement.addEventListener("keyup", function(kevent) {
            document.dispatchEvent(kevent);
            }, true);

    }
}
},true);

这仍然不能解决Gmail的问题

您的代码不起作用,因为
event.srcElement
引用的是
元素,而不是其内容。要访问其内容文档,您必须等待加载帧(
onload
或轮询),然后使用
frame.contentDocument
访问帧

从Chrome 37.0.1995.0开始,您还可以使用(with)在捕获事件并将其发送到父内容脚本的
about:blank
框架中插入内容脚本

以下是原始想法的实现示例(使用轮询):

manifest.json的相关部分:

  "content_scripts": [{
      "matches": ["*://mail.google.com/*"],
      "js": ["contentscript.js"],
      "run_at": "document_end"
  }],
contentscript.js

function keyDown(e) {console.log(e.which);}; // Test
function keyUp(e) {console.log(e.keyCode);}; // Test
(function checkForNewIframe(doc) {
    if (!doc) return; // document does not exist. Cya

    // Note: It is important to use "true", to bind events to the capturing
    // phase. If omitted or set to false, the event listener will be bound
    // to the bubbling phase, where the event is not visible any more when
    // Gmail calls event.stopPropagation().
    // Calling addEventListener with the same arguments multiple times bind
    // the listener only once, so we don't have to set a guard for that.
    doc.addEventListener('keydown', keyDown, true);
    doc.addEventListener('keyup', keyUp, true);
    doc.hasSeenDocument = true;
    for (var i = 0, contentDocument; i<frames.length; i++) {
        try {
            contentDocument = iframes[i].document;
        } catch (e) {
            continue; // Same-origin policy violation?
        }
        if (contentDocument && !contentDocument.hasSeenDocument) {
            // Add poller to the new iframe
            checkForNewIframe(iframes[i].contentDocument);
        }
    }
    setTimeout(checkForNewIframe, 250, doc; // <-- delay of 1/4 second
})(document); // Initiate recursive function for the document.
函数keyDown(e){console.log(e.which);};//试验
函数keyUp(e){console.log(e.keyCode);};//试验
(用于新iFrame(文档)的功能检查){
如果(!doc)return;//文档不存在。Cya
//注意:使用“true”将事件绑定到捕获对象非常重要
//如果省略或设置为false,事件侦听器将被绑定
//到冒泡阶段,在冒泡阶段,当
//Gmail调用event.stopperPagation()。
//多次使用相同参数调用addEventListener绑定
//听众只有一次,所以我们不必为此设置防护。
文件addEventListener('keydown',keydown,true);
文件addEventListener('keyup',keyup,true);
doc.hassendocument=true;

对于(var i=0,contentDocument;iGmail)而言,往往也有很多iFrame。请确保您正在侦听正确的事件。我已确保将我的内容脚本注入到所有iFrame中。我甚至尝试了一个构建,在其中我检测到iFrame被添加到DOM中的情况,如下所示:(参见编辑)我用这段代码做了一个单独的测试扩展,在gmail电子邮件文档的正文中键入时它将不起作用。@ZeroDivide gmail的电子邮件正文是一个框架中的一个框架。我用一个递归的、不冲突的函数更新了我的答案,以添加事件。@ZeroDivide我添加了这个长期轮询来解释添加的元素稍后。当您创建新消息时,会创建一个新的iframe。使用
DOMNodeInserted
来检测这一点会显著降低性能。轮询是一个更好的解决方案。如果立即为新iframe创建一个侦听器不太重要,请增加延迟。我添加了这些数字以确保不使用该变量。我使用了
rw
,因为这就是我给自己的自定义变量加前缀的方式。这些数字等于你问题的posted。加在一起,我得到了一个非常独特的描述性变量。@DavidJeske请在你发表评论之前花些时间阅读这三条评论(这里有一个链接可以让它更明显:所以Q&a:)@RobW键按捕获阶段参数是我的关键。正确设置后,键按事件在gmail compose窗口中为键触发,而无需使用all_frames=true或循环所有iframe文档。