-->

How to disable facebook hotkeys with Chrome extens

2019-01-17 09:23发布

问题:

I have created a Chrome extension that uses the hotkeys [Alt]+[0...9] only to discover facebook uses the same hotkeys. Is there any way possible my extension could disable facebook's hotkeys so that mine fire alone? I'm fairly certain I have identified the code facebook uses to implement their [Alt]+[0...9] hotkeys:

document.documentElement.onkeydown=function(a){a=a||window.event;var b=a.target||a.srcElement;var c=a.keyCode==13&&!a.altKey&&!a.ctrlKey&&!a.metaKey&&!a.shiftKey&&CSS.hasClass...

This is in a script called from the head of the root document. I have tried the following to disable them:

//contents script:
$().ready( function() {
  document.documentElement.onkeydown = '';
});

and even

$().ready( function() {
  document.documentElement.onkeydown = function(e){};
});

I am guessing further that the reason neither of these attempts work is because although Chrome extension content scripts share a DOM with any webpage on which they run, perhaps they do not share coding environments? Any insight would be appreciated!

回答1:

Your intuition is correct, the JavaScript that runs from a content script as part of a Chrome Extension is run in a sandbox that does not have access to the JavaScript that is executed in the containing page.

Per the Chrome doc on Content Scripts:

However, content scripts have some limitations. They cannot:
*  Use chrome.* APIs (except for parts of chrome.extension)
*  Use variables or functions defined by their extension's pages
*  Use variables or functions defined by web pages or by other content scripts

First off, I would recommend that you consider different shortcut keys. Overriding the functionality of existing shortcut keys for your own extension could provide a jarring user experience for someone that is expecting the Facebook shortcut key. Imagine if an extension overrode the ctrl-c and ctrl-p shortcuts that are a part of the desktop OS for copy and paste - I think you would have some upset users that would probably remove the thing that changed the behavior they learned prior.

However, if you are insistent, then here is a workaround to loading JavaScript that will execute in the context of the containing page:

Edit: Updated per comment to reference JS file in a plugin instead of one hosted on the web

First, you will need to create a JavaScript file in your chrome plugin: override-fb-hotkeys.js.

First, you will need to host a JavaScript file somewhere on the web that contains the script that you want to execute in the page, let us say you host it at: http://example.com/override-fb-hotkeys.js.

Then, from your content script, you can insert a script tag into the DOM that references your JavaScript file, something like this:

    var script = document.createElement('script');
    script.setAttribute("type", "text/javascript");
    script.setAttribute("async", true);
    script.setAttribute("src", chrome.extension.getURL("override-fb-hotkeys.js")); //Assuming your host supports both http and https
    var head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement;
    head.insertBefore(script, head.firstChild)

The JavaScript will then be fetched and executed in the context of the containing page, not the sandboxed code from the Chrome plugin.



回答2:

Chrome's Content scripts are executed in a Sandboxed environment [source]. There is no direct way to communicate with the global (window) object.

Another common pitfall is that the developer forgets how/when the script is injected.

  • By default, the script is injected at a point called "document_idle". At this point, the document is not busy (DOMContentLoaded has fired, window.onload may or may not have fired).
  • As a result, the functions in the script may be overwritten immediately after declaration.

To inject a small script, I recommend to add the code directly to the Content Script:

var actualCode = '/* Code here (see below for inspiration) */';

var script = document.createElement('script');
script.appendChild(document.createTextNode(actualCode));
(document.head || document.documentElement).appendChild(script);
script.parentNode.removeChild(script);

If you want to make sure that the method is not going to be overwritten, you can use Object.defineProperty, to define an immutable property:

Object.defineProperty(document.documentElement, 'onkeydown', {
    value: function() {},
    writable: false,     /* Cannot be overwritten, default false */
    configurable: false, /* Cannot be deleted, or modified */
    enumerable: true     /* Does not really matter. If true, it's visible in
                             a for-loop. If false, it's not*/
});

The previously mentioned method is supported in Firefox 4+ and at least Chrome 5+. If you want to also support Firefox 2+ and Chrome 1+, you can play with the __defineSetter__, to prevent onkeydown from being defined:

document.documentElement.__defineSetter__('onkeydown', function(){});


回答3:

This is how you can do it using jQuery

Remove all shortcuts for any webpage:

$('[accessKey]').attr('accessKey','')