【问题标题】:keydown event not working in bootstrapped Firefox addonkeydown 事件在引导的 Firefox 插件中不起作用
【发布时间】:2013-09-11 17:09:15
【问题描述】:

我是扩展开发的新手。我试图在我的引导式 Firefox 扩展中触发对 keydown 事件的操作,但它似乎不起作用。我错过了什么吗?

这是我的 bootstrap.js 代码:

Cu.import("resource://gre/modules/Services.jsm");

function watchWindows(callback) {

    function watcher(window) {
    try {

      let {documentElement} = window.document;
      if (documentElement.getAttribute("windowtype") == "navigator:browser")
        callback(window);
    }
    catch(ex) {}
    }


     function runOnLoad(window) {

    window.addEventListener("load", function runOnce() {
      window.removeEventListener("load", runOnce, false);
      watcher(window);
    }, false);
  }

  // Add functionality to existing windows
  let windows = Services.wm.getEnumerator(null);
  while (windows.hasMoreElements()) {
    // Only run the watcher immediately if the window is completely loaded
    let window = windows.getNext();
    if (window.document.readyState == "complete")
      watcher(window);
    // Wait for the window to load before continuing
    else
      runOnLoad(window);
  }

  // Watch for new browser windows opening then wait for it to load
  function windowWatcher(subject, topic) {
    if (topic == "domwindowopened")
      runOnLoad(subject);
  }
  Services.ww.registerNotification(windowWatcher);

  // Make sure to stop watching for windows if we're unloading
  unload(function() Services.ww.unregisterNotification(windowWatcher));
}

/**
* Save callbacks to run when unloading. Optionally scope the callback to a
* container, e.g., window. Provide a way to run all the callbacks.
*
* @usage unload(): Run all callbacks and release them.
*
* @usage unload(callback): Add a callback to run on unload.
* @param [function] callback: 0-parameter function to call on unload.
* @return [function]: A 0-parameter function that undoes adding the callback.
*
* @usage unload(callback, container) Add a scoped callback to run on unload.
* @param [function] callback: 0-parameter function to call on unload.
* @param [node] container: Remove the callback when this container unloads.
* @return [function]: A 0-parameter function that undoes adding the callback.
*/
function unload(callback, container) {
  // Initialize the array of unloaders on the first usage
  let unloaders = unload.unloaders;
  if (unloaders == null)
    unloaders = unload.unloaders = [];

  // Calling with no arguments runs all the unloader callbacks
  if (callback == null) {
    unloaders.slice().forEach(function(unloader) unloader());
    unloaders.length = 0;
    return;
  }

  // The callback is bound to the lifetime of the container if we have one
  if (container != null) {
    // Remove the unloader when the container unloads
    container.addEventListener("unload", removeUnloader, false);

    // Wrap the callback to additionally remove the unload listener
    let origCallback = callback;
    callback = function() {
      container.removeEventListener("unload", removeUnloader, false);
      origCallback();
    }
  }

  // Wrap the callback in a function that ignores failures
  function unloader() {
    try {
      callback();
    }
    catch(ex) {}
  }
  unloaders.push(unloader);

  // Provide a way to remove the unloader
  function removeUnloader() {
    let index = unloaders.indexOf(unloader);
    if (index != -1)
      unloaders.splice(index, 1);
  }
  return removeUnloader;
}

/* library */

const Utils = (function() {

    const sbService = Cc['@mozilla.org/intl/stringbundle;1']
                         .getService(Ci.nsIStringBundleService);
    const windowMediator = Cc['@mozilla.org/appshell/window-mediator;1']
                              .getService(Ci.nsIWindowMediator);


    let setAttrs = function(widget, attrs) {
        for (let [key, value] in Iterator(attrs)) {
            widget.setAttribute(key, value);
        }
    };

    let getMostRecentWindow = function(winType) {
        return windowMediator.getMostRecentWindow(winType);
    };

    let exports = {
        setAttrs: setAttrs,
        getMostRecentWindow: getMostRecentWindow,
    };
    return exports;
})();



let ResponseManager = (function() {

    const obsService = Cc['@mozilla.org/observer-service;1']
                          .getService(Ci.nsIObserverService);

    const RESPONSE_TOPIC = 'http-on-examine-response';

    let observers = [];

    let addObserver = function(observer) {
        try {
            obsService.addObserver(observer, RESPONSE_TOPIC, false);
        } catch(error) {
            trace(error);
        }
        observers.push(observers);
    };

    let removeObserver = function(observer) {
        try {
            obsService.removeObserver(observer, RESPONSE_TOPIC, false);
        } catch(error) {
            trace(error);
        }
    };

    let destory = function() {
        for (let observer of observers) {
            removeObserver(observer);
        }
        observers = null;
    };

    let exports = {
        addObserver: addObserver,
        removeObserver: removeObserver,
        destory: destory,
    };
    return exports;
})();

/* main */

let ReDisposition = function() {

    let respObserver;

    respObserver = {

        observing: false,

        observe: function(subject, topic, data) {
            try {
                let channel = subject.QueryInterface(Ci.nsIHttpChannel);
                this.override(channel);
            } catch(error) {
                trace(error);
            }
        },

        start: function() {
            if (!this.observing) {
                ResponseManager.addObserver(this);
                this.observing = true;
            }
        },
        stop: function() {
            if (this.observing) {
                ResponseManager.removeObserver(this);
                this.observing = false;
            }
        },
        refresh: function() {
            this.start();
        },

        re: /^\s*attachment/i,

        re2: /^\s*text/i,

        override: function(channel) {

            if(disablePlugin)
            {
               try {
               let contentHeader;
               contentHeader = channel.getResponseHeader('Content-Type');
               if (this.re2.test(contentHeader)) 
               return;
               channel.setResponseHeader('Content-Disposition', "attachment", false);
               return;
               }
                catch(error) {
                return;
                }       
            }

            // check if have header
            let header;
            try {
                header = channel.getResponseHeader('Content-Disposition');
            } catch(error) {
                return;
            }

            // override to inline
            if (this.re.test(header)) {
                channel.setResponseHeader('Content-Disposition', header.replace(this.re, "inline"), false);
                return;
            }

        }
    };



    let initialize = function() {

        respObserver.refresh();
    };
    let destory = function() {

        respObserver.stop();
    };

    let exports = {
        initialize: initialize,
        destory: destory,
    }
    return exports;

};

/* bootstrap entry points */

let reDisposition;
var disablePlugin = false;
let install = function(data, reason) {};
let uninstall = function(data, reason) {};

let startup = function(data, reason) {

    reDisposition = ReDisposition();
    reDisposition.initialize();
    function onwindow(window) {
        function onkeydown(e) {
            if (e.keyCode == 70)
            {
            disablePlugin = true;
            }
            else
            {
            disablePlugin = false;
            }

        }
        function onkeyup(e) {

            disablePlugin = false;

        }
        // Bootstrapped add-ons need to clean up after themselves!
        function onunload() {
            window.removeEventListener("keydown", onkeypress);
            window.removeEventListener("keyup", onkeypress);
        }
        window.addEventListener("keydown", onkeydown);
        window.addEventListener("keyup", onkeyup);
        unload(onunload, window);
    }
    watchWindows(onwindow);


};

let shutdown = function(data, reason) {
    reDisposition.destory();
};

【问题讨论】:

  • 请不要在事后彻底改变您的问题。

标签: javascript firefox-addon key


【解决方案1】:

bootstrap.js 范围内没有 windowbootstrap.js 本质上是一个独立的代码模块(在沙箱中运行,但这只是一个实现细节)。每个应用程序只会运行一次,而不是每个窗口一次。

在开发bootstrapped add-ons 时,您必须自己枚举现有窗口并观察新窗口,并根据需要“附加”到它们。参见例如watchWindows boilerplate

这是一个例子。它假设您使用的是watchWindows 样板:

function startup(data, reason) {
    // Callback function called for each browser window (browser.xul)
    function onwindow(window) {
        function onkeydown(e) {
            // XXX: Your code here.
        }
        // Bootstrapped add-ons need to clean up after themselves!
        function onunload() {
            window.removeEventListener("keydown", onkeypress);
        }
        window.addEventListener("keydown", onkeydown);
        unload(onunload, window);
    }

    // Will also fire for existing windows once and upon each new window.
    watchWindows(onwindow);
}

如果您不熟悉 Firefox 附加组件、XUL/XPCOM 和一般的 mozilla 平台,我不建议您开发引导式附加组件。您可能应该查看基于 XUL 覆盖的附加组件或附加 SDK。

【讨论】:

  • 我强烈推荐插件 SDK,如果它允许实现你需要/想要的。与基于 XUL 的插件相比,您肯定会节省大量时间
  • @nmaler 我已经更新了代码,上面的代码中是不是根本无法监听键盘事件。
  • 看来您只是复制了一些无法真正解决您的问题的随机代码......然后甚至不尝试使用它。我链接了watchWindows,它实际上可以帮助您安装按键处理程序。我会尝试在我的答案中添加一个示例。
  • @nmaler 非常感谢,但它仍然无法正常工作,我已经上传了整个源代码,我试图防止在按键时修改标题。请帮我解决一下这个。在按键按下时,我想禁用标题修改并在按键时恢复它。
  • @nmaler 非常感谢,它正在工作,但按键事件似乎无法正常工作。我已经上传了整个代码,我仍然无法相信我必须添加大约 150 行代码来处理事件。他们是我从监视窗口代码中添加的任何东西吗?
猜你喜欢
  • 2013-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多