Smooth Scrolling

Smoothly scrolls the page when a button is held

当前为 2021-03-28 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Smooth Scrolling
  3. // @description Smoothly scrolls the page when a button is held
  4. // @version 1.1.2
  5. // @author sllypper
  6. // @homepage https://gf.qytechs.cn/en/users/55535-sllypper
  7. // @namespace https://gf.qytechs.cn/en/users/55535-sllypper
  8. // @match *://forums.spacebattles.com/*
  9. // @match *://forums.sufficientvelocity.com/*
  10. // @match *://forum.questionablequesting.com/*
  11. // @match *://fanfiction.net/*
  12. // @match *://archiveofourown.org/*
  13. // @match *://turb0translation.blogspot.com/*
  14. // @match *://chyoa.com/*
  15. // @match *://fiction.live/*
  16. // @grant none
  17. // @todo make keybinds easily configurable
  18. // ==/UserScript==
  19.  
  20. (function() {
  21. 'use strict';
  22.  
  23. // Smooth Scrolling Settings
  24.  
  25. // how much it scrolls every time (in pixels)
  26. let scrollAmount = 16;
  27.  
  28. // how long between ticks (in ms)
  29. // 16.66667 = 60 frames per second
  30. // not used if experimental is true
  31. let scrollPeriod = 16.66667;
  32.  
  33. // how much holding Shift will multiply the scrollAmount
  34. let shiftSpeedMod = 2.0;
  35.  
  36. //
  37.  
  38. // Experimental settings
  39.  
  40. // Use the alternative experimental Scroller
  41. // it's bound to your screen framerate
  42. // is supposed to be smoother
  43. let experimental = true;
  44.  
  45. // Scroll Speed in times per second
  46. // set to 0 to match your refresh rate (smooth perfection)
  47. // values above your framerate scrolls every frame
  48. let fps = 0
  49.  
  50. // programming magic stuff
  51.  
  52. const states = {
  53. NONE: 0,
  54. UP: 1,
  55. SHIFTUP: 2,
  56. DOWN: 3,
  57. SHIFTDOWN: 4
  58. }
  59. let scrollState = states.NONE;
  60. let currScrollAction = null;
  61. let isTyping = false;
  62.  
  63. document.addEventListener('focus', function(evt) {
  64. var target = evt.target;
  65. if((target.nodeName === 'INPUT' && target.type === 'text') || target.nodeName === 'TEXTAREA') isTyping = true;
  66. // else isTyping = false;
  67. }, true);
  68.  
  69. document.addEventListener('blur', function(evt) {
  70. var target = evt.target;
  71. if((target.nodeName === 'INPUT' && target.type === 'text') || target.nodeName === 'TEXTAREA') isTyping = false;
  72. }, true);
  73.  
  74. document.addEventListener("keydown", event => {
  75. // ignore keybindings when text input is focused
  76. if (isTyping || event.isComposing || event.target.getAttribute('medium-editor') != null || event.target.getAttribute('contenteditable') != null) {
  77. //console.log('entered first if')
  78. event.stopPropagation();
  79. return;
  80. }
  81. switch (event.code) {
  82. case "KeyW":
  83. case "KeyK":
  84. case "ArrowUp": {
  85. event.preventDefault();
  86. if (scrollState !== states.UP && !event.shiftKey) {
  87. //event.preventDefault();
  88. clearScrollAction();
  89. scrollState = states.UP;
  90. scrollAction(-scrollAmount);
  91. } else if (scrollState !== states.SHIFTUP && event.shiftKey) {
  92. //event.preventDefault();
  93. clearScrollAction();
  94. scrollState = states.SHIFTUP;
  95. scrollAction(-scrollAmount*shiftSpeedMod);
  96. }
  97. break;
  98. }
  99. case "KeyS":
  100. case "KeyJ":
  101. case "ArrowDown": {
  102. event.preventDefault();
  103. if (scrollState !== states.DOWN && !event.shiftKey) {
  104. // event.preventDefault();
  105. clearScrollAction();
  106. scrollState = states.DOWN;
  107. scrollAction(scrollAmount);
  108. } else if (scrollState !== states.SHIFTDOWN && event.shiftKey) {
  109. // event.preventDefault();
  110. clearScrollAction();
  111. scrollState = states.SHIFTDOWN;
  112. scrollAction(scrollAmount*shiftSpeedMod);
  113. }
  114. break;
  115. }
  116. }
  117. });
  118.  
  119. document.addEventListener("keyup", event => {
  120. switch(event.code) {
  121. case 'KeyW':
  122. case 'KeyK':
  123. case 'KeyJ':
  124. case 'KeyS':
  125. case 'ArrowDown':
  126. case 'ArrowUp':
  127. clearScrollAction();
  128. break
  129. default:
  130. // using even.key for any Shift Key
  131. if (event.key === "Shift") {
  132. clearScrollAction();
  133. }
  134. break;
  135. }
  136. });
  137.  
  138. function scrollAction(amount) {
  139. if (experimental) {
  140. scroller.move(amount)
  141. return;
  142. }
  143.  
  144. currScrollAction = setInterval(() => {
  145. window.scrollBy(0, amount);
  146. }, scrollPeriod)
  147. }
  148.  
  149. function clearScrollAction() {
  150. clearInterval(currScrollAction);
  151. currScrollAction = null;
  152. scrollState = states.NONE;
  153. scroller.stop();
  154. }
  155.  
  156. // experimental bit
  157.  
  158. let scroller = new Scroller(fps)
  159.  
  160. function Scroller(fps) {
  161.  
  162. var delay,
  163. time,
  164. frame,
  165. tref,
  166. amount;
  167.  
  168. function loop(timestamp) {
  169. if (fps !== 0) {
  170. // Scroll with fps behavior
  171. if (time === null) {time = timestamp; timestamp = 0}
  172. var seg = Math.floor((timestamp - time) / delay);
  173. if (seg > frame) {
  174. frame = seg;
  175. window.scrollBy(0, amount);
  176. }
  177. } else {
  178. // Scroll every frame behavior
  179. window.scrollBy(0, amount);
  180. }
  181. tref = requestAnimationFrame(loop)
  182. }
  183.  
  184. this.move = function(pixels) {
  185. amount = pixels;
  186. delay = 1000 / fps;
  187. frame = -1;
  188. time = null;
  189. tref = requestAnimationFrame(loop);
  190. }
  191.  
  192. this.stop = function() {
  193. cancelAnimationFrame(tref);
  194. };
  195. }
  196.  
  197. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址