Intercept Shortcuts
-
Gist: https://gist.github.com/luetage/b6c6fdee713c0b3569e9daa9ee7b73bb
This is a simple userscript stopping websites from hijacking shortcuts intended for the browser. The original solution to this problem can be found here: https://superuser.com/questions/168087/how-to-forbid-keyboard-shortcut-stealing-by-websites-in-firefox.
I adapted the script for my personal needs in Vivaldi browser. I’m using single key shortcuts and websites like Github or Discord often interfere with navigation. The script intercepts all shortcuts but whitelisted ones and introduces a shortcut to let the next shortcut pass, which makes it possible to still send any shortcut to the website, should the need arise. Writing in input fields is not affected and the whitelisted keys allow for basic actions such as toggling playback (space), leaving fullscreen (esc), navigating menus (arrow keys) and jumping from element to element (tab, shift).
// ==UserScript== // @name Intercept Shortcuts // @namespace https://gist.github.com/luetage/b6c6fdee713c0b3569e9daa9ee7b73bb // @updateURL https://gist.github.com/luetage/b6c6fdee713c0b3569e9daa9ee7b73bb/raw // @supportURL https://forum.vivaldi.net/post/459981 // @description Stops websites from hijacking keyboard shortcuts. // @version 2022.9.0 // @author luetage // @match *://*/* // @run-at document-start // ==/UserScript== (function () { "use strict"; const pass = () => { si++; if (si > 3) { document.removeEventListener("keyup", pass); si = 0; } }; let si = 0; // whitelist const keycodes = [ "Escape", "Tab", "Enter", " ", "Shift", "ArrowLeft", "ArrowDown", "ArrowUp", "ArrowRight", ]; document.addEventListener("keydown", (e) => { // console.log(e.key); // shortcut for letting the next shortcut pass (alt-n) if (e.key === "n" && e.altKey) { si = 1; document.addEventListener("keyup", pass); } else if (si === 0 && keycodes.indexOf(e.key) === -1) { e.cancelBubble = true; e.stopImmediatePropagation(); } return false; }); })();
Userscripts can be installed by creating a file (e.g.
intercept-shortcuts.user.js
) and dragging it overvivaldi://extensions/
, after enabling developer mode. There is no need to install a userscript manager extension like Tamper‐ or Violentmonkey, but it’s of course an option. The script can be freely adapted to your own needs, by changing the whitelist, targeting specific shortcuts, targeting a specific site, &c.[ You can safely ignore following paragraph, if you don’t use Vimium ]
Now here comes the catch: I’m a Vimium user and in my opinion this userscript does what Vimium should already do, namely stopping sites from stealing shortcuts. This is not the case, because Vimium apparently assumes all browser shortcuts having a modifier key and all website shortcuts being single key shortcuts; and therefore it only intercepts shortcuts defined in the extension itself. Gladly Vimium and this userscript work well together and complement each other, with the exception of passing a shortcut to the website. Using the shortcut to pass the next shortcut to the website from Vimium, will be blocked by this userscript. Conversely using the same functionality in this userscript will be potentially blocked by Vimium, should the shortcut be in use. The workaround is setting both shortcuts to the same value (in my casealt-n
) and then while keepingalt
pressed, pressing then
key 3 times. The first time Vimium will trigger, blocking our shortcut from triggering. The second time our shortcut triggers, because Vimium lets it pass. And the third time Vimium will let the next shortcut pass, while the userscript is still in the state of passing. After letting go ofalt-n
, the next shortcut we type will be passed to the website by both Vimium and the userscript. While this isn’t perfect, it isn’t as painful as I initially thought and works well. At least the functionality is restored, should we ever need it.Relevant links:
https://forum.vivaldi.net/topic/43366/stop-websites-from-reassigning-vivaldi-shortcuts/
https://forum.vivaldi.net/topic/58516/hello-guys-im-new-here-have-a-question-about-a-keyboard-shortcut/
https://forum.vivaldi.net/topic/38701/i-want-to-prevent-websites-highjacking-stealing-vivaldi-keyboard-commands-so-i-can-rely-on-shortcuts -
Would it be possible to convert this to a script using a blacklist instead of a whitelist? I would like to use most website shortcuts apart from a few for which I would like the browser shortcut to take precedence.
-
Yes, the original script I linked blacklists shortcuts on specific sites. You could do something like this:
// ==UserScript== // @name Intercept Shortcuts // @homepageURL https://github.com/luetage/intercept-shortcuts // @description Stops websites from hijacking keyboard shortcuts. // @version 0.8 // @match *://*.vivaldi.net/* // @match *://*.stackexchange.com/* // @run-at document-start { 'use strict'; const keycodes = [9, 13, 16, 27, 32, 37, 38, 39, 40]; // blacklists tab, enter, shift, escape, space and arrow keys document.addEventListener('keydown', e => { // console.log(e.keyCode); if (keycodes.indexOf(e.keyCode) !== -1 || e.Keycode === 74 && e.ctrlKey) { // additionally blacklists alt-j shortcut e.cancelBubble = true; e.stopImmediatePropagation(); } return false; }) }
-
@luetage Thanks!
-
@luetage Nice. Might have to use this to fix some sites.
One suggestion is you could try changing it to use
event.key
instead ofevent.keyCode
to make it slightly more user readable. I also believekeyCode
is depreciated.Like this:
// ==UserScript== // @name Intercept Shortcuts // @homepageURL https://github.com/luetage/intercept-shortcuts // @description Stops websites from hijacking keyboard shortcuts. // @version 0.8 // @match *://*/* // @run-at document-start { ("use strict"); let pass = () => { si++; if (si > 3) { document.removeEventListener("keyup", pass); si = 0; } }; let si = 0; const keycodes = ["tab", "enter", "shift", "escape", " ", "arrowleft", "arrowup", "arrowright", "arrowdown"]; //whitelists document.addEventListener("keydown", (e) => { let key = e.key.toLowerCase(); if (key === "j" && e.altKey) { //shortcut for letting the next shortcut pass (alt-j) si = 1; document.addEventListener("keyup", pass); } else if (si === 0 && keycodes.indexOf(key) === -1) { e.cancelBubble = true; e.stopImmediatePropagation(); } return false; }); }
Only downside is it takes a few extra bytes of memory.
-
@nomadic That’s what I get for reading 10 year old code I suppose. Don’t think this will be an issue for another 10 years, because I can’t imagine browser vendors will throw it out that easily, but we might as well switch it around. Thanks for the suggestion.
-
@nomadic What I don’t get is why make space display as space? Why not just call it
Space
and be done with it. It’s hard to recognize in the DevTools and it’s confusing and inconsistent with what’s being done on operating system level. IIt feels like everybody makes up their own standards, because they can </sigh> -
@luetage Yeah, that is something that annoys me too.
In the hotkey options UI that I made for an extension (and reused for another), I used a function to format some keys to be displayed according to my preferences.
Probably overkill and unnecessary for this user script.
The Function
function formateHotkeys(set1) { let replaceTable = { Control: "Ctrl", Arrowup: "↑", Arrowright: "→", Arrowdown: "↓", Arrowleft: "←", " ": " Space", // Needed 2 spaces so every space in output string doesn't get changed to "Space" Pageup: "PgUp", Pagedown: "PgDn", Delete: "Del", }; let keyString = [...set1].map((c) => c.slice(0, 1).toUpperCase() + c.slice(1).toLowerCase()).join(" + "); keyString = keyString.replace( /Control|Arrowup|Arrowright|Arrowdown|Arrowleft|\s\s|Pageup|Pagedown|Delete/g, function (match) { return replaceTable[match]; } ); // Bug-Fix: if the hotkey was only a space, then the replace doesn't work properly keyString = keyString === " " ? "Space" : keyString; return keyString; }
So a set like this: "
Set(2) {"Control", "ArrowUp"}
" would be made into a string like this: "Ctrl + ↑" -
@luetage Sorry, I need a bit of help: how would I blacklist a multi-key shortcut such as
Ctrl+,
? Also wondering how to update the version you provided for me to use keys instead of keycodes if that would make it more user readable. -
@valiowk Please share your current code and tell me exactly what you want, then I will take a look at it, it’s not a big deal. Btw, if you open DevTools on a page and uncomment the line with
console.log
you can test out keys yourself. If you make itconsole.log(e.key)
, you get the names instead of the codes, just as nomadic showed. -
@luetage I don't have any current code; I was just trying to take the code you gave me and replace the numbers in the
const keycodes
array (actually I was trying to modify the code so that it used keys instead of keycodes the way you edited the main post). The problem is that I don't even know what to replace a number inconst keycodes
by if I want to blacklist a multi-key shortcut: I tried replacing a number by something like44 && e.ctrlKey
and variants on that but Tampermonkey tells me that's not the way to go (it looked wrong even without Tampermonkey telling me so).EDIT: Also, I tried installing your script in the main post in Tampermonkey (to uncomment the line with
console.log
to test out keys myself) but it gives me an error "Invalid UserScript. Sry!"... -
@valiowk Try again, should work now, nomadic just made me aware of a mistake (arrow + direction instead of direction + arrow), maybe Tampermonkey didn’t like that. Tell me whether it works.
And yeah, if you want me to write a version for you I’ll do it. But I need you to list the sites it should work on, if not all sites and all the shortcuts you don’t want the sites to register.
-
@luetage For now I'd just like to blacklist
Ctrl+,
on mail.google.com so that I can use it as a browser shortcut since I never use that Gmail shortcut. I think I'd be able to figure out how to add additional shortcuts on my own once I know how to input a weird shortcut like this (that uses a comma—I don't know if comma can be entered as,
or requires special code). (I know how to use@match
and all that.)EDIT: Tampermonkey is still giving me an error after I used your updated code...
-
@valiowk Try to install it without Tampermonkey.
// ==UserScript== // @name Intercept Shortcuts // @homepageURL https://github.com/luetage/intercept-shortcuts // @description Stops websites from hijacking keyboard shortcuts. // @version 0.9 // @match https://mail.google.com/* // @run-at document-start { 'use strict'; const keycodes = ['CapsLock']; //blacklist document.addEventListener('keydown', e => { console.log(e.key); if (e.key === ',' && e.ctrlKey || keycodes.indexOf(e.key) !== -1) { console.log('trigger'); e.cancelBubble = true; e.stopImmediatePropagation(); } return false; }) }
The blacklist isn’t needed for now, but I kept it and put in capslock. Adjust to your needs. I also left the console logs running and added one so you can check whether a shortcut is successfully being intercepted.
-
@luetage It works (without Tampermonkey), thanks!
-
Why not use
.code
? -
@potmeklecbohdan Because I have no idea what that means.
-
@luetage https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#:~:text=KeyboardEvent.code
For space it gives
"Space"
-
@potmeklecbohdan Makes sense, I’ll probably switch to it myself. As for the public version not so sure, could confuse people who try to adapt the script.
-
@luetage
It was very helpful!