Instantly share code, notes, and snippets.
Last active
October 25, 2024 14:36
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
Save udaken/72334ce6086a47eb746fa3a6a8cc777a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Google Search Keyboard Navigation | |
// @namespace http://tampermonkey.net/ | |
// @version 0.7 | |
// @description Navigate Google search results using 'j' (down), 'k' (up), and Enter (open) keys | |
// @author Your name | |
// @match https://www.google.com/search?* | |
// @grant GM_addStyle | |
// @downloadURL https://gist.github.com/udaken/72334ce6086a47eb746fa3a6a8cc777a/raw/google_search_keyboard_navigation.user.js | |
// @updateURL https://gist.github.com/udaken/72334ce6086a47eb746fa3a6a8cc777a/raw/google_search_keyboard_navigation.user.js | |
// ==/UserScript== | |
(function() { | |
'use strict'; | |
// CSSスタイルを追加 | |
GM_addStyle(` | |
div.g[tabindex="-1"]:focus { | |
outline: none; | |
background-color: #E8F0FE !important; | |
border-radius: 4px; | |
} | |
div.g[tabindex="-1"]:focus * { | |
background-color: transparent !important; | |
} | |
`); | |
let currentIndex = -1; | |
const searchResults = []; | |
function initializeSearchResults() { | |
// Google検索結果の要素を取得し、tabindex属性を追加 | |
const results = document.querySelectorAll('div.g'); | |
searchResults.length = 0; | |
results.forEach(result => { | |
result.setAttribute('tabindex', '-1'); | |
searchResults.push(result); | |
}); | |
} | |
function focusResult(index) { | |
// 現在の結果からフォーカスを外す | |
if (currentIndex >= 0 && currentIndex < searchResults.length) { | |
searchResults[currentIndex].blur(); | |
} | |
// 新しい結果にフォーカス | |
if (index >= 0 && index < searchResults.length) { | |
const resultElement = searchResults[index]; | |
resultElement.focus(); | |
resultElement.scrollIntoView({ | |
behavior: 'smooth', | |
block: 'center' | |
}); | |
} | |
} | |
function moveToNextResult() { | |
if (searchResults.length === 0) { | |
initializeSearchResults(); | |
} | |
currentIndex++; | |
if (currentIndex >= searchResults.length) { | |
currentIndex = 0; | |
} | |
focusResult(currentIndex); | |
} | |
function moveToPreviousResult() { | |
if (searchResults.length === 0) { | |
initializeSearchResults(); | |
} | |
currentIndex--; | |
if (currentIndex < 0) { | |
currentIndex = searchResults.length - 1; | |
} | |
focusResult(currentIndex); | |
} | |
function openCurrentResult(event) { | |
if (currentIndex >= 0 && currentIndex < searchResults.length) { | |
const link = searchResults[currentIndex].querySelector('a'); | |
if (link) { | |
if (event.ctrlKey) { | |
window.open(link.href, '_blank'); | |
} else { | |
window.location.href = link.href; | |
} | |
} | |
} | |
} | |
// 最初の結果を選択する | |
function selectFirstResult() { | |
if (currentIndex === -1 && searchResults.length > 0) { | |
currentIndex = 0; | |
focusResult(currentIndex); | |
} | |
} | |
// キーボードイベントリスナーを追加 | |
document.addEventListener('keydown', function(e) { | |
// 入力フィールドやテキストエリアでの入力時は動作しないようにする | |
if (document.activeElement.tagName === 'INPUT' || document.activeElement.tagName === 'TEXTAREA') { | |
return; | |
} | |
// Alt と組み合わせた場合は動作しない | |
if (e.altKey || e.shiftKey || e.ctrlKey) { | |
return; | |
} | |
switch (e.key) { | |
case 'j': | |
moveToNextResult(); | |
e.preventDefault(); | |
break; | |
case 'k': | |
moveToPreviousResult(); | |
e.preventDefault(); | |
break; | |
case 'v': | |
if (currentIndex !== -1) { | |
openCurrentResult(e); | |
e.preventDefault(); | |
} | |
break; | |
} | |
}); | |
// ページロード時の初期化 | |
function initialize() { | |
initializeSearchResults(); | |
selectFirstResult(); | |
} | |
// ページロード時に初期化 | |
initialize(); | |
// 動的に結果が追加される可能性があるため、定期的に結果を更新 | |
const observer = new MutationObserver(() => { | |
initializeSearchResults(); | |
}); | |
observer.observe(document.body, { | |
childList: true, | |
subtree: true | |
}); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment