Read articles hands-free! Pres Ctrl-Down or Opt-Down to start slowly scrolling the page. Press again to adjust speed. Escape or Space to stop.
当前为
// ==UserScript==
// @name Auto scroll keys [adopted]
// @namespace http://userscripts.org/users/44573
// @version 1.1.4
// @license MIT
// @description Read articles hands-free! Pres Ctrl-Down or Opt-Down to start slowly scrolling the page. Press again to adjust speed. Escape or Space to stop.
// @grant none
// @include *
// ==/UserScript==
// This script is a derivative of http://userscripts-mirror.org/scripts/show/70300 by PaC1250
// Options:
var initialSpeed = 10; // Pixels per second
var maxPerSecond = 60; // Target FPS
var resetThreshold = 10; // If the user scrolls the page manually by more pixels than this value, then we will start scrolling from the new position.
// When zoomed in, a page pixel will be larger than a screen pixel. Enabling this will shift by fractions of a page pixel, rather than whole page pixels, so that the text won't make multi-pixel jumps.
var attemptSubPixelScrolling = false;
// But at default zoom, sub-pixel scrolling may look a little bit jittery, so this option will enable sub-pixel zooming only when it's needed.
// (Although personally in Chrome I found sub-pixel zooming looked preferable even at zoom 100%.)
// This overwrites the value of attemptSubPixelScrolling when scrolling begins.
var attemptSubPixelScrollingOnlyIfZoomedIn = true;
// The user may perform normal scrolling actions during auto-scroll (e.g. by pressing Up or PageUp or using the scroll bar). We will detect and ackowledge these (update realy) if we see a difference of more than this many pixels.
// If the threshold is set too low, the script's own scrolling will trigger it, especially on slower machines or under heavy load.
// But if set too high, the threshold may fail to fire if, when the user presses Up to scroll back a little, the browser performs that with a smooth scroll of lots of small movements, rather than one larger jump.
// BUG: When zoomed in, jumping by a whole (unzoomed) pixel it too coarse, because we see the text move by more than one screen pixel. But we cannot control that: we give the browser a float for scrolling but it rounds it to an int!
// A possible workaround would be to perform some scrolling (perhaps just the remainder part before rounding) as a transform on the page. This might not work in all browsers.
// 2012/10/09 Now runs at 60fps or whatever the machine can handle
// Constants:
var DOM_VK_DOWN = 40;
var DOM_VK_UP = 38;
var DOM_VK_ESCAPE = 27;
var DOM_VK_SPACE = 32;
var DOM_VK_ENTER = 13;
// Runtime:
var u44573_go = false;
var scrollSpeed = 0;
var lastTime;
var realx, realy; // We store scroll position as floats; basing scrolling on a float is smoother than the browser's int-rounded scrollTop. But we may need to keep realy in sync with scrollTop, if the user changes the later during auto-scroll.
window.addEventListener('keydown', u44573_handler, true);
var transformBeforeScrolling;
function u44573_handler(e) {
var change = 0.60; // Probably could be lowered a bit if we make scrollSpeed truly analogue.
var upDelta, downDelta; // The acceleration of each key
if (scrollSpeed === 0 || !u44573_go) {
upDelta = initialSpeed;
downDelta = initialSpeed;
} else {
if (Math.abs(scrollSpeed) < 0.1) {
scrollSpeed = 0.1 * sgn(scrollSpeed);
}
downDelta = Math.abs(scrollSpeed)*change;
upDelta = Math.abs(scrollSpeed)*change/(1+change);
if (scrollSpeed < 0) {
var tmpDelta = downDelta;
downDelta = upDelta;
upDelta = tmpDelta;
}
}
// Scroll downwards with CTRL-Down_Arrow or Opt-Down_Arrow on Mac
if((e.altKey || e.ctrlKey) && e.keyCode == DOM_VK_DOWN) {
scrollSpeed += downDelta;
e.preventDefault();
}
// Scroll upwards with CTRL-Up_Arrow or Opt-Up_Arrow on Mac
if((e.altKey || e.ctrlKey) && e.keyCode == DOM_VK_UP) {
scrollSpeed -= upDelta;
e.preventDefault();
}
if(!u44573_go && scrollSpeed != 0) {
startScroller();
}
// Stop (ESCAPE or ENTER or SPACE)
if (e.keyCode == DOM_VK_ESCAPE || e.keyCode == DOM_VK_ENTER || e.keyCode == DOM_VK_SPACE) {
if (u44573_go) {
u44573_go = false;
scrollSpeed = 0;
if (attemptSubPixelScrolling) {
document.body.style.transform = transformBeforeScrolling;
}
// Do not pass keydown event to page:
e.preventDefault(); // Most browsers
return false; // IE
}
}
}
function sgn(x) {
return ( x>0 ? +1 : x<0 ? -1 : 0 );
}
var abs = Math.abs;
function startScroller() {
u44573_go = true;
var s = u44573_getScrollPosition();
realx = s[0];
realy = s[1];
lastTime = new Date().getTime();
transformBeforeScrolling = document.body.style.transform;
if (attemptSubPixelScrollingOnlyIfZoomedIn) {
// This technique find the zoom level in Chrome
// For other browser, see https://github.com/tombigel/detect-zoom or http://stackoverflow.com/questions/1713771
var screenCssPixelRatio = window.outerWidth / window.innerWidth;
console.log("Detected zoom: "+screenCssPixelRatio);
var isZoomedIn = (screenCssPixelRatio >= 1.05);
attemptSubPixelScrolling = isZoomedIn;
}
u44573_goScroll();
}
function queueNextFrame(callback, duration) {
if (typeof window.requestAnimationFrame === 'function') {
window.requestAnimationFrame(callback);
} else {
setTimeout(callback, duration);
}
}
function u44573_goScroll() {
if (u44573_go) {
// Check if the user has scrolled the page with a key since we last scrolled.
// If so, update our realx,realy.
// BUG: Argh the check isn't working in Firefox 90% of the time!
// Hold down the key to beat those odds.
var s = u44573_getScrollPosition();
if ( abs(s[0]-realx) > resetThreshold || abs(s[1]-realy) > resetThreshold ) {
realx = s[0];
realy = s[1];
}
var timeNow = new Date().getTime();
var elapsed = timeNow - lastTime;
var jumpPixels = abs(scrollSpeed) * elapsed/1000;
var timeToNext = 1000/maxPerSecond;
// Rather than running at a fixed FPS, at slow speeds the approaches below would delay the next callback until it was time to move to the next pixel. This was more efficient on slow machines.
/*
// The browser can only jump a whole number of pixels, and it rounds down.
// We had to do the following anyway for jumpPixels<1 but by doing it for
// small numbers (<5) we workaround the analogue/digital bug. (5*1.2=6)
if (jumpPixels < 3) {
timeToNext /= jumpPixels;
// jumpPixels /= jumpPixels;
jumpPixels = 1;
}
*/
/*
var timeToNext = 1000/abs(scrollSpeed);
if (timeToNext < 1000/maxPerSecond) {
jumpPixels = abs(scrollSpeed)/maxPerSecond;
timeToNext = 1000/maxPerSecond;
} else {
jumpPixels = 1;
}
*/
realy += jumpPixels*sgn(scrollSpeed);
//var inty = Math.round(realy);
var inty = Math.floor(realy);
if (attemptSubPixelScrolling) {
var remaindery = realy - inty;
var transform = transformBeforeScrolling + " translate(0px, "+(-remaindery)+"px)";
document.body.style.transform = transform;
}
window.scroll(realx, inty); // Leave it to browser to round real values to ints
lastTime = timeNow;
if (scrollSpeed == 0) {
u44573_go = false;
} else {
queueNextFrame(u44573_goScroll, timeToNext);
}
}
}
function u44573_getScrollPosition() {
return Array((document.documentElement && document.documentElement.scrollLeft) || window.pageXOffset || self.pageXOffset || document.body.scrollLeft,(document.documentElement && document.documentElement.scrollTop) || window.pageYOffset || self.pageYOffset || document.body.scrollTop);
}
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址