Last active
February 16, 2025 17:45
-
-
Save Doomwhite/604465d56c0638d35e79803ec09669d0 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 Smooth Scrolling | |
// @description Smoothly scrolls the page when a button is held | |
// @version 1.1.2 | |
// @author sllypper | |
// @homepage https://greasyfork.org/en/users/55535-sllypper | |
// @namespace https://greasyfork.org/en/users/55535-sllypper | |
// @match *://*/* | |
// @grant none | |
// @todo make keybinds easily configurable | |
// @downloadURL https://update.greasyfork.org/scripts/423926/Smooth%20Scrolling.user.js | |
// @updateURL https://update.greasyfork.org/scripts/423926/Smooth%20Scrolling.meta.js | |
// ==/UserScript== | |
(function() { | |
'use strict'; | |
// Smooth Scrolling Settings | |
// how much it scrolls every time (in pixels) | |
let scrollAmount = 10; | |
// how long between ticks (in ms) | |
// 16.66667 = 60 frames per second | |
// not used if experimental is true | |
let scrollPeriod = 16.66667; | |
// how much holding Shift will multiply the scrollAmount | |
let shiftSpeedMod = 2.0; | |
// | |
// Experimental settings | |
// Use the alternative experimental Scroller | |
// it's bound to your screen framerate | |
// is supposed to be smoother | |
let experimental = true; | |
// Scroll Speed in times per second | |
// set to 0 to match your refresh rate (smooth perfection) | |
// values above your framerate scrolls every frame | |
let fps = 0 | |
// programming magic stuff | |
const states = { | |
NONE: 0, | |
UP: 1, | |
SHIFTUP: 2, | |
DOWN: 3, | |
SHIFTDOWN: 4 | |
} | |
let scrollState = states.NONE; | |
let currScrollAction = null; | |
let isTyping = false; | |
document.addEventListener('focus', function(evt) { | |
var target = evt.target; | |
if((target.nodeName === 'INPUT' && target.type === 'text') || target.nodeName === 'TEXTAREA') isTyping = true; | |
// else isTyping = false; | |
}, true); | |
document.addEventListener('blur', function(evt) { | |
var target = evt.target; | |
if((target.nodeName === 'INPUT' && target.type === 'text') || target.nodeName === 'TEXTAREA') isTyping = false; | |
}, true); | |
document.addEventListener("keydown", event => { | |
// ignore keybindings when text input is focused | |
if (isTyping || event.isComposing || event.target.getAttribute('medium-editor') != null || event.target.getAttribute('contenteditable') != null) { | |
//console.log('entered first if') | |
event.stopPropagation(); | |
return; | |
} | |
switch (event.code) { | |
case "KeyW": | |
case "KeyK": | |
case "ArrowUp": { | |
event.preventDefault(); | |
if (scrollState !== states.UP && !event.shiftKey) { | |
//event.preventDefault(); | |
clearScrollAction(); | |
scrollState = states.UP; | |
scrollAction(-scrollAmount); | |
} else if (scrollState !== states.SHIFTUP && event.shiftKey) { | |
//event.preventDefault(); | |
clearScrollAction(); | |
scrollState = states.SHIFTUP; | |
scrollAction(-scrollAmount*shiftSpeedMod); | |
} | |
break; | |
} | |
case "KeyS": | |
case "KeyJ": | |
case "ArrowDown": { | |
event.preventDefault(); | |
if (scrollState !== states.DOWN && !event.shiftKey) { | |
// event.preventDefault(); | |
clearScrollAction(); | |
scrollState = states.DOWN; | |
scrollAction(scrollAmount); | |
} else if (scrollState !== states.SHIFTDOWN && event.shiftKey) { | |
// event.preventDefault(); | |
clearScrollAction(); | |
scrollState = states.SHIFTDOWN; | |
scrollAction(scrollAmount*shiftSpeedMod); | |
} | |
break; | |
} | |
} | |
}); | |
document.addEventListener("keyup", event => { | |
switch(event.code) { | |
case 'KeyW': | |
case 'KeyK': | |
case 'KeyJ': | |
case 'KeyS': | |
case 'ArrowDown': | |
case 'ArrowUp': | |
clearScrollAction(); | |
break | |
default: | |
// using even.key for any Shift Key | |
if (event.key === "Shift") { | |
clearScrollAction(); | |
} | |
break; | |
} | |
}); | |
function scrollAction(amount) { | |
if (experimental) { | |
scroller.move(amount) | |
return; | |
} | |
currScrollAction = setInterval(() => { | |
window.scrollBy(0, amount); | |
}, scrollPeriod) | |
} | |
function clearScrollAction() { | |
clearInterval(currScrollAction); | |
currScrollAction = null; | |
scrollState = states.NONE; | |
scroller.stop(); | |
} | |
// experimental bit | |
let scroller = new Scroller(fps) | |
function Scroller(fps) { | |
var delay, | |
time, | |
frame, | |
tref, | |
amount; | |
function loop(timestamp) { | |
if (fps !== 0) { | |
// Scroll with fps behavior | |
if (time === null) {time = timestamp; timestamp = 0} | |
var seg = Math.floor((timestamp - time) / delay); | |
if (seg > frame) { | |
frame = seg; | |
window.scrollBy(0, amount); | |
} | |
} else { | |
// Scroll every frame behavior | |
window.scrollBy(0, amount); | |
} | |
tref = requestAnimationFrame(loop) | |
} | |
this.move = function(pixels) { | |
amount = pixels; | |
delay = 1000 / fps; | |
frame = -1; | |
time = null; | |
tref = requestAnimationFrame(loop); | |
} | |
this.stop = function() { | |
cancelAnimationFrame(tref); | |
}; | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This removes the annoying delay whenever arrow scrolling in firefox. This is mostly a Windows issue.