How to disable facebook hotkeys with Chrome extension?
Asked Answered
W

3

8

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!

Wristwatch answered 24/1, 2012 at 5:16 Comment(0)
M
6

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.

Malediction answered 24/1, 2012 at 7:13 Comment(3)
Thanks for this. This is indeed insightful! I have found there is no need to host on another site as this works: script.setAttribute("src", chrome.extension.getURL("override-fb-hotkeys.js") ); however the code document.documentElement.onkeydown = function(e){}; within the injected file does not disable the fb shortcuts so any more help would be welcome!Wristwatch
You would need to reverse engineer the code on the Facebook page to determine how the key events were being captured and handled and then override that functionality. I looked a bit but nothing jumped out. I did notice that when i removed the element with id "blueBarHolder" (the entire top bar) then the hotkeys did not work.Malediction
Hey,i want to ask you since you seem to know stuff. Do you know if there's a clever workaround to simply JUST disable the shortcuts in Facebook on Chrome? I can't stand the fact that L is like (I use ctrl+l VERY often to go to nav bar). Like, even a simple one line script would helpMissionary
H
14

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(){});
Haileyhailfellowwellmet answered 24/1, 2012 at 21:29 Comment(4)
And what if facebook code override Object.defineProperty?Phonon
@Phonon If you run code with run_at; "document _start", then it should not be possible.Haileyhailfellowwellmet
Is it possible for 2 diff extensions to do document_start?Phonon
@Phonon Yes, but if the extension that runs first defines a property with configurable:false, then extensions that runs after that cannot redefine the property.Haileyhailfellowwellmet
M
6

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.

Malediction answered 24/1, 2012 at 7:13 Comment(3)
Thanks for this. This is indeed insightful! I have found there is no need to host on another site as this works: script.setAttribute("src", chrome.extension.getURL("override-fb-hotkeys.js") ); however the code document.documentElement.onkeydown = function(e){}; within the injected file does not disable the fb shortcuts so any more help would be welcome!Wristwatch
You would need to reverse engineer the code on the Facebook page to determine how the key events were being captured and handled and then override that functionality. I looked a bit but nothing jumped out. I did notice that when i removed the element with id "blueBarHolder" (the entire top bar) then the hotkeys did not work.Malediction
Hey,i want to ask you since you seem to know stuff. Do you know if there's a clever workaround to simply JUST disable the shortcuts in Facebook on Chrome? I can't stand the fact that L is like (I use ctrl+l VERY often to go to nav bar). Like, even a simple one line script would helpMissionary
M
1

This is how you can do it using jQuery

Remove all shortcuts for any webpage:

$('[accessKey]').attr('accessKey','')
Mill answered 16/6, 2013 at 19:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.