Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to disable facebook hotkeys with Chrome extension?

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!

like image 886
flea whale Avatar asked Jan 24 '12 05:01

flea whale


People also ask

How do I change keyboard shortcuts for Extensions?

From the browser's toolbar, click the Extensions icon and select Manage extension. Click Keyboard shortcuts. Use the Type a shortcut field next to each extension to set a new keyboard shortcut. To remove a shortcut, just click X.


2 Answers

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(){});
like image 123
Rob W Avatar answered Oct 12 '22 22:10

Rob W


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.

like image 43
Adam Ayres Avatar answered Oct 13 '22 00:10

Adam Ayres