Skip to content

Instantly share code, notes, and snippets.

@lionel-rowe
Last active March 5, 2023 03:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lionel-rowe/25b9ccf76379e3e12988bff837f6f492 to your computer and use it in GitHub Desktop.
Save lionel-rowe/25b9ccf76379e3e12988bff837f6f492 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name Disable arrow key hijacking
// @description Stop websites from hijacking left and right arrow keys.
// @author Lionel Rowe
// @run-at document-start
// @match http://*/*
// @match https://*/*
// @grant none
// @version 0.3
// @namespace https://github.com/lionel-rowe
// ==/UserScript==
/**
* @returns { 'mdbook' | 'gitbook' | null } The generator used to create the
* current website, if any. `null` = none or unknown; any truthy value is a
* site generator that is known to hijack arrow keys.
*/
const getSiteGeneratorName = () => {
const walker = document.createTreeWalker(
document.head,
NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT,
)
let node
while (node = walker.nextNode()) {
switch (node.nodeType) {
case Node.COMMENT_NODE: {
if (/\bmdbook\b/i.test(node.textContent)) {
return 'mdbook'
}
break
}
case Node.ELEMENT_NODE: {
if (node.tagName === 'META'
&& node.name === 'generator'
&& /\bgitbook\b/i.test(node.getAttribute('content'))
) {
return 'gitbook'
}
break
}
}
}
return null
}
const modifiers = Object.fromEntries(['ctrl', 'alt', 'shift', 'meta']
.map((k) => [k, `${k}Key`]))
const matches = (event) => (matcher) => Object.values(modifiers)
.every((v) => matcher.includes(v) === event[v])
const disableArrowKeyHijacking = () => {
document.addEventListener('keydown', (e) => {
const { ctrl, alt, shift } = modifiers
const normalScrolling = [[]]
const textSelection = [[shift], [ctrl, shift]]
const browserHistoryNavigation = [[alt]]
const nativeCombos = [normalScrolling, textSelection, browserHistoryNavigation].flat(1)
const isTextInputMode = ['INPUT', 'TEXTAREA'].includes(document.activeElement.nodeName)
if (['ArrowLeft', 'ArrowRight'].includes(e.key) && nativeCombos.some(matches(e)) || isTextInputMode) {
e.stopImmediatePropagation()
console.error(`Possible hijacking of ${e.key} was prevented.`)
}
})
}
const reduceClickableNavHitboxes = (siteGeneratorName) => {
const selectors = {
mdbook: '.nav-chapters',
gitbook: '.navigation',
}
const selector = selectors[siteGeneratorName]
if (selector) {
document.head.insertAdjacentHTML('beforeend', `<style>${selector} {
height: 10rem;
top: 50%;
transform: translateY(-50%);
}</style>`);
}
}
const siteGeneratorName = getSiteGeneratorName()
if (siteGeneratorName) {
disableArrowKeyHijacking()
reduceClickableNavHitboxes(siteGeneratorName)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment