NoMouseGoogle

Shortcut for Google search results. j/k to move focus, l/h to open in new/background tab.

当前为 2022-03-24 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name NoMouseGoogle
  3. // @namespace com.gmail.fujifruity.greasemonkey
  4. // @version 1.9
  5. // @description Shortcut for Google search results. j/k to move focus, l/h to open in new/background tab.
  6. // @author fujifruity
  7. // @include https://www.google.com/search*
  8. // @grant GM.openInTab
  9. // @license MIT
  10. // ==/UserScript==
  11.  
  12. {
  13. const items = [...document.querySelectorAll('#rso div[data-hveid][data-ved]')]
  14. .filter(e => e.offsetParent != null /* is visible */)
  15. const open = inBackground => {
  16. const url = findCurrentItem().querySelector('a').href
  17. GM.openInTab(url, inBackground)
  18. }
  19. const tag = "noMouseGoogleCurrentItem"
  20. const findCurrentItem = () => items.find(e => e.hasAttribute(tag))
  21.  
  22. const moveCursor = step => {
  23. const currentItem = findCurrentItem()
  24. const r = currentItem.getBoundingClientRect();
  25. const inScreen = (0 < r.top && r.top < window.innerHeight
  26. || 0 < r.bottom && r.bottom < window.innerHeight)
  27. if (!inScreen) {
  28. const dist = e => {
  29. const r = e.getBoundingClientRect()
  30. return Math.abs(window.innerHeight - (r.top + r.bottom))
  31. }
  32. const nearestItem = items.reduce((acc,e) => dist(acc) < dist(e) ? acc : e )
  33. select(nearestItem)
  34. return
  35. }
  36. const nextIdx = (items.indexOf(currentItem) + step + items.length) % items.length
  37. select(items[nextIdx])
  38. }
  39. const highlight = e => {
  40. const isDarkTheme = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
  41. e.style.backgroundColor = isDarkTheme ? '#2a2a2a' : 'WhiteSmoke'
  42. }
  43. const select = item => {
  44. // Deselect current item.
  45. const currentItem = findCurrentItem()
  46. if (currentItem) {
  47. currentItem.style.backgroundColor = null
  48. currentItem.removeAttribute(tag)
  49. }
  50. // Select the item.
  51. item.setAttribute(tag, '')
  52. highlight(item)
  53. item.scrollIntoView({ behavior: "smooth", block: "center" })
  54. }
  55.  
  56. // Select the first item without scrolling.
  57. items[0].setAttribute(tag, '')
  58. highlight(items[0])
  59.  
  60. window.addEventListener('keydown', event => {
  61. if (event.target.tagName == "INPUT" || event.ctrlKey || event.altKey) return
  62. if (event.key == 'j') moveCursor(+1)
  63. if (event.key == 'k') moveCursor(-1)
  64. if (event.key == 'l') open(false)
  65. if (event.key == 'h') open(true)
  66. })
  67.  
  68. }