Как я могу обнаружить события клавиатуры в Gmail - PullRequest
3 голосов
/ 24 февраля 2012

Я пишу расширение для браузера, которое должно прикреплять обработчики к событиям keyup и keydown на всех страницах.Я могу заставить его работать довольно хорошо с помощью следующего кода скрипта контента.

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

Я не могу заставить это работать в Gmail.В частности, я не могу заставить его работать при составлении тела нового письма.Это будет работать везде, где я тестировал.Я думаю, что проблема в том, что Gmail вызывает stopPropagation на всех событиях клавиатуры, но трудно отладить их свернутый код.Я думал, что установка третьего параметра на true приведет к тому, что событие будет записано во время CAPTURE_PHASE, но это не работает.

Как мне захватить события keyup и keydown при создании нового тела в Gmail с помощью скрипта контента Google Chrome?

Редактировать:

Я гарантировалчто мои скрипты содержимого внедряются во все iframes DOM, добавляя "all_frames": true, в мой манифест.Я даже пытался использовать следующий код:

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.

1 Ответ

6 голосов
/ 25 февраля 2012

Ваш код не работает, потому что event.srcElement относится к элементу <iframe>, а не к его содержимому.Для доступа к документу с содержимым необходимо дождаться загрузки кадра (onload или опроса), а затем использовать frame.contentDocument для доступа к кадру.

Начиная с Chrome 37.0.1995.0, вы также можетеиспользуйте match_about_blank all_frames ), чтобы вставить сценарий содержимого в кадр 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.

Обратите внимание, что я использовал опрос вместо событий мутации DOM, поскольку последние сильно снижают производительность .

...