cool thingy!

Per-page X-Mouse-like controls: custom actions for extra buttons, wheel, and hover focus (where possible) in Safari.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey, Greasemonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Userscripts.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een gebruikersscriptbeheerder nodig.

(Ik heb al een user script manager, laat me het downloaden!)

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

(Ik heb al een beheerder - laat me doorgaan met de installatie!)

// ==UserScript==
// @name         cool thingy!
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Per-page X-Mouse-like controls: custom actions for extra buttons, wheel, and hover focus (where possible) in Safari.
// @author       You
// @match        *://*/*
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    // =========================
    // CONFIG: TWEAK THIS PART
    // =========================

    // Example actions:
    //  - "back": window.history.back()
    //  - "forward": window.history.forward()
    //  - "scrollUp"/"scrollDown": window.scrollBy(...)
    //  - "top": scroll to top
    //  - "bottom": scroll to bottom
    //  - "none": do nothing / let default happen

    const CONFIG = {
        // Map mouse buttons to actions
        // 0 = left, 1 = middle, 2 = right, 3+ = extra (if browser exposes them)
        buttonMap: {
            1: 'autoScrollToggle', // middle click toggles auto-scroll
            3: 'back',             // XButton1 (if exposed) -> back
            4: 'forward'           // XButton2 (if exposed) -> forward
        },

        // Auto-scroll speed (pixels per frame)
        autoScrollSpeed: 8,

        // Enable "focus window on hover" style behavior (limited in browser)
        focusOnHover: true
    };

    // =========================
    // INTERNAL STATE
    // =========================

    let autoScrollActive = false;
    let autoScrollDirection = 1; // 1 = down, -1 = up
    let autoScrollRAF = null;

    // =========================
    // ACTION HANDLERS
    // =========================

    function doAction(action, event) {
        switch (action) {
            case 'back':
                event.preventDefault();
                window.history.back();
                break;
            case 'forward':
                event.preventDefault();
                window.history.forward();
                break;
            case 'scrollUp':
                event.preventDefault();
                window.scrollBy({ top: -200, left: 0, behavior: 'smooth' });
                break;
            case 'scrollDown':
                event.preventDefault();
                window.scrollBy({ top: 200, left: 0, behavior: 'smooth' });
                break;
            case 'top':
                event.preventDefault();
                window.scrollTo({ top: 0, left: 0, behavior: 'smooth' });
                break;
            case 'bottom':
                event.preventDefault();
                window.scrollTo({ top: document.body.scrollHeight, left: 0, behavior: 'smooth' });
                break;
            case 'autoScrollToggle':
                event.preventDefault();
                toggleAutoScroll(event);
                break;
            case 'none':
            default:
                // Let default behavior happen
                break;
        }
    }

    // =========================
    // AUTO-SCROLL
    // =========================

    function autoScrollLoop() {
        if (!autoScrollActive) return;
        window.scrollBy(0, CONFIG.autoScrollSpeed * autoScrollDirection);
        autoScrollRAF = window.requestAnimationFrame(autoScrollLoop);
    }

    function toggleAutoScroll(event) {
        // Direction based on where you clicked relative to center
        const centerY = window.innerHeight / 2;
        autoScrollDirection = (event.clientY < centerY) ? -1 : 1;

        if (autoScrollActive) {
            autoScrollActive = false;
            if (autoScrollRAF) {
                window.cancelAnimationFrame(autoScrollRAF);
                autoScrollRAF = null;
            }
        } else {
            autoScrollActive = true;
            autoScrollLoop();
        }
    }

    // =========================
    // EVENT LISTENERS
    // =========================

    // Mouse button remapping
    window.addEventListener('mousedown', function (e) {
        // e.button: 0=left,1=middle,2=right, 3+=extra (if supported)
        const action = CONFIG.buttonMap[e.button];
        if (!action) return;
        doAction(action, e);
    }, true);

    // Optional: focus-on-hover style (limited)
    if (CONFIG.focusOnHover) {
        window.addEventListener('mouseover', function (e) {
            // We can't change OS-level focus, but we can visually "focus" elements.
            const el = e.target;
            if (el && el.focus && typeof el.focus === 'function') {
                // Only auto-focus inputs, textareas, and contenteditable
                const tag = el.tagName.toLowerCase();
                const isEditable =
                    tag === 'input' ||
                    tag === 'textarea' ||
                    el.isContentEditable;

                if (isEditable) {
                    el.focus({ preventScroll: true });
                }
            }
        }, true);
    }

    // Safety: stop auto-scroll on user input
    ['wheel', 'keydown', 'mousedown'].forEach(type => {
        window.addEventListener(type, () => {
            if (!autoScrollActive) return;
            autoScrollActive = false;
            if (autoScrollRAF) {
                window.cancelAnimationFrame(autoScrollRAF);
                autoScrollRAF = null;
            }
        }, { passive: true });
    });

})();