Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I detect keyboard events in Gmail

I am writing a browser extension that needs to attach handlers to the keyup and keydown events on all pages. I can get it working pretty well with the following content script code.

document.addEventListener("keydown",keyDown, true);      
document.addEventListener("keyup", keyUp, true);

I can't get this to work in Gmail though. Specifically I can't get it to work when composing the body of an new email. It will work everywhere else I have tested. I think the problem is because Gmail is calling stopPropagation on all keyboard events but it is difficult to debug their minimized code. I thought that setting the 3rd parameter to true would cause the event to be captured during the CAPTURE_PHASE but this isn't working.

How can I capture keyup and keydown events while composing a new body in Gmail with a Google Chrome content script?

Edit:

I've ensured that my content scripts are being injected into all iframes of the DOM by adding "all_frames": true, to my manifest. I have even tried using the following code:

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);

This still doesn't fix the issue with Gmail.

like image 879
Stephen__T Avatar asked Feb 24 '12 02:02

Stephen__T


People also ask

What are the events associated with keyboard?

There are three types of keyboard events: keydown , keypress , and keyup .

How do I use keyboard events?

There are three different keyboard events in JavaScript: keydown : Keydown happens when the key is pressed down, and auto repeats if the key is pressed down for long. keypress : This event is fired when an alphabetic, numeric, or punctuation key is pressed down. keyup : Keyup happens when the key is released.

What are the keyboard event fired?

Explanation: The keydown and keyup are the keyboard events are fired when the user presses or releases a key on the keyboard. They are generated for modifier keys, function keys, and alphanumeric keys. 2.


1 Answers

Your code doesn't work because event.srcElement refers to the <iframe> element, not its content. To access its content document, you have to wait for the frame to be loaded (onload or polling), then use frame.contentDocument to access the frame.

Starting from Chrome 37.0.1995.0, you can also use the match_about_blank (with all_frames) to insert a content script in the about:blank frame that captures the event and sends it to the parent content script.

Here is an example of an implementation for the original idea (using polling):

The relevant parts of 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.

Note that I used polling instead of DOM mutation events, because the latter heavily reduces performance.

like image 136
Rob W Avatar answered Oct 17 '22 04:10

Rob W