bring back the keyboard navigation in Google Search
当前为
// ==UserScript==
// @name Google Search keyboard navigation
// @namespace http://tampermonkey.net/
// @version 2025-05-28
// @description bring back the keyboard navigation in Google Search
// @author victor141516
// @match https://www.google.com/search?q=*
// @icon https://www.google.com/s2/favicons?sz=64&domain=google.com
// @grant none
// @license MIT
// ==/UserScript==
(function () {
"use strict";
const BASE_CLASS_NAME = "x-keyboard-utils";
const ACTIVE_CLASS_NAME = "x-keyboard-utils-active";
function appendCss() {
const styles = `
.${BASE_CLASS_NAME}.${ACTIVE_CLASS_NAME}:before {
content: '';
z-index: 100;
display: block;
position: absolute;
pointer-events: none;
border: 15px solid transparent;
border-left-color: blue;
left: -20px;
}
`;
const styleElement = document.createElement("style");
styleElement.textContent = styles;
document.head.appendChild(styleElement);
}
(async () => {
let activeIndex = 0;
/** @type {Array<HTMLElement>} */
let $results = [];
document.addEventListener("keydown", (e) => {
const isArrowDown = e.key === "ArrowDown";
const isArrowUp = e.key === "ArrowUp";
const isEnter = e.key === "Enter";
if (!isArrowDown && !isArrowUp && !isEnter) return;
e.preventDefault();
if (isArrowDown) {
activeIndex = Math.min(activeIndex + 1, $results.length - 1);
} else if (isArrowUp) {
activeIndex = Math.max(activeIndex - 1, 0);
} else if (isEnter) {
$results[activeIndex].querySelector("a").click();
}
updateArrow();
});
function updateArrow() {
$results.forEach((e) => {
e.classList.remove(ACTIVE_CLASS_NAME);
});
$results[activeIndex].classList.add(ACTIVE_CLASS_NAME);
$results[activeIndex].scrollIntoView({
behavior: "smooth",
block: "center",
inline: "center",
});
}
function initializeResultElements() {
$results = Array.from(
document.querySelectorAll(
"div[data-async-context^=query] > div:has(div[lang])"
)
);
$results.forEach(($result) => {
if ($result.classList.contains(BASE_CLASS_NAME)) return;
$result.classList.add(BASE_CLASS_NAME);
});
}
const targetNode = document.querySelector("div[data-async-context^=query]");
const callback = (mutationList) => {
for (const mutation of mutationList) {
if (mutation.type === "childList") {
initializeResultElements();
}
}
};
const observer = new MutationObserver(callback);
observer.observe(targetNode, {
attributes: false,
childList: true,
subtree: false,
});
appendCss();
initializeResultElements();
updateArrow();
})();
})();