Skip to content

Instantly share code, notes, and snippets.

@leonbrandt
Last active August 14, 2020 09:18
Show Gist options
  • Save leonbrandt/0d67fd06f9de33fccb2b0e9fd248684d to your computer and use it in GitHub Desktop.
Save leonbrandt/0d67fd06f9de33fccb2b0e9fd248684d to your computer and use it in GitHub Desktop.
Google keyboard navigation (Greasemonkey / Tampermonkey)
// ==UserScript==
// @name Google Keyboard Navigator
// @namespace https://www.leonbrandt.com
// @version 1.0.2
// @description Use up/down to navigate over results, left/right to navigate over pages and return to open selected result
// @author Leon Brandt
// @updateURL https://gist.github.com/leonbrandt/0d67fd06f9de33fccb2b0e9fd248684d/raw/google-keyboard-navigator.user.js
// @homepage https://www.leonbrandt.com
// @match https://*/*
// @grant none
// @run-at document-idle
// ==/UserScript==
/*
NEW IN 1.0.2
- Prevent key-navigation while focus in search-input
NEW IN 1.0.1
- Keep selected result in focus (middle of the screen)
- Improved behavior when pressing return (selection is not longer opened when intended do a new search request)
- Automatically navigate to next page when down-key is pressed while the last result on a page is selected
*/
const KEY_UP = 38;
const KEY_DOWN = 40;
const KEY_LEFT = 37;
const KEY_RIGHT = 39;
const KEY_RETURN = 13;
let focus = -1;
let entries = null;
let url = null;
let prev_page = null;
let next_page = null;
function getEntries() {
entries = document.querySelectorAll("#search .g");
}
function getPages() {
prev_page = (document.querySelector("#pnprev") ? document.querySelector("#pnprev").href : null);
next_page = (document.querySelector("#pnnext") ? document.querySelector("#pnnext").href : null);
}
function unselect(i) {
if(i < 0) return;
let el = entries[i];
el.style.border = "none";
el.style.padding = "0";
}
function select(i) {
if(i < 0) return;
let el = entries[i];
el.style.border = "1px solid #707070";
el.style.padding = "10px";
url = el.querySelector(".r > a").href;
el.scrollIntoView({ behavior: 'auto', block: 'center', inline: 'center' });
}
function isInSearchField() {
return document.activeElement === Array.from(document.querySelectorAll("input")).find(e => e.classList.length > 0);
}
(function() {
'use strict';
getPages();
getEntries();
document.onclick = function(evt){
unselect(focus); url = null;
}
document.onkeydown = function(evt){
evt = evt || window.event;
if(evt.keyCode === KEY_RETURN && url){ window.open(url, '_blank'); }
else if(!isInSearchField() && evt.keyCode === KEY_UP && focus > -1){ unselect(focus); select(--focus); }
else if(!isInSearchField() && evt.keyCode === KEY_DOWN){
if(focus < entries.length - 1){ unselect(focus); select(++focus); }
else if(entries && next_page) { location.replace(next_page); }
}
else if(!isInSearchField() && evt.keyCode === KEY_LEFT && prev_page){ location.replace(prev_page); }
else if(!isInSearchField() && evt.keyCode === KEY_RIGHT && next_page){ location.replace(next_page); }
else { unselect(focus); url = null; }
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment