Adds DuckDuckGo keyboard shortcuts to other search engines
// ==UserScript==
// @name DDG Shortcuts
// @version 1.2.1
// @description Adds DuckDuckGo keyboard shortcuts to other search engines
// @author ReimarPB
// @match *://*/*
// @namespace https://reimarpb.com/userscripts
// @grant none
// @noframes
// ==/UserScript==
(function() {
// The CSS selectors for each search engine to get different parts of the page
var selectors = {
google: {
input: "input[name=q]",
tab: ".hdtb-mitem a, .hdtb-mitem.hdtb-msel, .T47uwc > a, .T47uwc > span",
currentTab: ".hdtb-mitem.hdtb-msel, .rQEFy.NZmxZe",
resultHoverElem: ".LC20lb.MBeuO.DKV0Md",
resultHoverClass: "AraNOb",
resultLink: ".yuRUbf a",
},
startpage: {
input: "#q",
tab: ".inline-nav-menu__link__post-link, .css-dkelex",
currentTab: ".inline-nav-menu__link__post-link.inline-nav-menu__link__active, .css-156jy2m button",
resultHoverElem: ".w-gl__result",
resultHoverClass: "linkHover",
resultLink: ".w-gl__result-title.result-link",
},
brave: {
input: "#searchbox",
tab: ".tab-item > a",
currentTab: ".tab-item.active > a",
resultLink: ".result-header",
},
searx: {
input: "#q",
tab: ".category > label, #categories > label",
currentTab: ".category input[type=checkbox]:checked + label, #categories input[type=checkbox]:checked + label",
resultLink: ".result > h3 > a, .result_header > a",
}
};
// Get selectors for this search engine
if (location.host.indexOf("www.google.") === 0 && location.pathname.indexOf("/search") === 0)
selectors = selectors.google;
else if (location.host === "www.startpage.com" && location.pathname == "/sp/search")
selectors = selectors.startpage;
else if (location.host === "search.brave.com" && ["/search", "/images", "/news", "/videos"].indexOf(location.pathname) !== -1)
selectors = selectors.brave;
else if (window.searx || window.searxng) {
selectors = selectors.searx;
document.getElementById("q").blur(); // Remove autofocus
} else return;
var tabs = document.querySelectorAll(selectors.tab);
var resultIndex = -1;
var tabIndex = [].indexOf.call(tabs, document.querySelector(selectors.currentTab));
document.addEventListener("keydown", function(event) {
// Return if input is focused
if (document.querySelector("input:focus")) return;
var preventDefault = true;
if (selectors.resultHoverElem) var resultHoverElems = document.querySelectorAll(selectors.resultHoverElem);
var resultLinks = document.querySelectorAll(selectors.resultLink);
var searchField = document.querySelector(selectors.input);
var currentResult = resultLinks[resultIndex === -1 ? 0 : resultIndex]; // Default to first result if none selected
switch (event.key) {
// Focus search field
case "/":
case "h":
searchField.focus();
searchField.select();
break;
// Domain search
case "d":
searchField.value = searchField.value
.replace(/site:\S+/g, "")
.replace(/\s+$/, "")
+ " site:" + currentResult.host;
searchField.form.submit();
break;
// Open link
case "Enter":
case "l":
case "o":
// Allow CTRL + Enter
if (event.ctrlKey) {
preventDefault = false;
break;
}
location.href = currentResult.href;
break;
// Open link in new tab
case "'":
case "v":
open(currentResult.href, "_blank");
break;
// Scroll to top
case "t":
scrollTo({ top: 0 });
resultIndex = -1;
break;
// Move between results
case "ArrowUp":
case "k":
if (resultIndex === 0) resultLinks[resultIndex--].blur();
if (resultLinks[resultIndex - 1]) resultLinks[--resultIndex].focus();
resultUpdated();
break;
case "ArrowDown":
case "j":
if (resultLinks[resultIndex + 1]) resultLinks[++resultIndex].focus();
resultUpdated();
break;
case "m":
resultIndex = 0;
resultUpdated();
break;
// Change tabs
case "ArrowLeft":
if (tabs[tabIndex - 1]) tabs[tabIndex - 1].click();
break;
case "ArrowRight":
if (tabs[tabIndex + 1]) tabs[tabIndex + 1].click();
break;
default:
preventDefault = false;
}
if (preventDefault) event.preventDefault();
// Called when the user presses down/up
function resultUpdated() {
// Remove old hover effect
if (selectors.resultHoverClass) {
var old = document.querySelector("." + selectors.resultHoverClass + selectors.resultHoverElem);
if (old) old.classList.remove(selectors.resultHoverClass);
}
if (resultIndex >= 0) {
// Scroll to result
var elem = resultLinks[resultIndex], top = 0;
do {
top += elem.offsetTop || 0;
elem = elem.offsetParent;
} while(elem)
scrollTo({ top: top - innerHeight / 2 });
// Add hover effect
if (resultHoverElems) resultHoverElems[resultIndex].classList.add(selectors.resultHoverClass);
}
}
});
})();