Greasy Fork

鼠标滚轮速度调节器

可调节鼠标滚轮翻页速度的修改功能,支持0.1x到5.0x速度调节,带有现代化UI界面

// ==UserScript==
// @name         鼠标滚轮速度调节器
// @name:en      Mouse Wheel Speed Controller
// @version      1.0.0
// @description  可调节鼠标滚轮翻页速度的修改功能,支持0.1x到5.0x速度调节,带有现代化UI界面
// @description:en  Adjustable mouse wheel scrolling speed controller with modern UI, supports 0.1x to 5.0x speed adjustment
// @author       Rabbbit
// @match        *://*/*
// @exclude      https://*.google.com/recaptcha/*
// @exclude      https://accounts.google.com/*
// @exclude      https://login.microsoftonline.com/*
// @icon         data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNjQiIHZpZXdCb3g9IjAgMCA2NCA2NCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPGNpcmNsZSBjeD0iMzIiIGN5PSIzMiIgcj0iMzAiIGZpbGw9IiM0Q0FGNTAZZ0xaZXIoMTM1ZGVnLCAjNENBRjUwLCAjMjE5NjUzKSIvPgo8cGF0aCBkPSJNMzIgMTZWNDhNMTYgMzJINDgiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iNCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+CjxjaXJjbGUgY3g9IjMyIiBjeT0iMzIiIHI9IjgiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo=
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_addStyle
// @grant        GM_registerMenuCommand
// @grant        GM_notification
// @run-at       document-end
// @noframes
// @license      MIT
// @compatible   chrome 支持Chrome浏览器
// @compatible   firefox 支持Firefox浏览器
// @compatible   edge 支持Edge浏览器
// @compatible   safari 支持Safari浏览器
// @compatible   opera 支持Opera浏览器
// @namespace https://greasyfork.org/users/1483317
// ==/UserScript==

(function() {
    'use strict';

    // 防止在iframe中运行
    if (window.top !== window.self) {
        return;
    }

    console.log('🖱️ 鼠标滚轮速度调节器已启动');

    // 默认配置
    let config = {
        speedMultiplier: parseFloat(GM_getValue('scrollSpeedMultiplier', '1.0')),
        isEnabled: GM_getValue('scrollSpeedEnabled', 'true') === 'true',
        panelVisible: GM_getValue('panelVisible', 'true') === 'true'
    };

    // 添加样式
    GM_addStyle(`
        #scroll-speed-panel {
            position: fixed;
            top: 20px;
            right: 20px;
            background: linear-gradient(135deg, rgba(0, 0, 0, 0.9), rgba(30, 30, 30, 0.9));
            color: white;
            padding: 16px;
            border-radius: 12px;
            z-index: 99999;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            font-size: 14px;
            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
            min-width: 220px;
            user-select: none;
            border: 1px solid rgba(255, 255, 255, 0.1);
            cursor: move;
            backdrop-filter: blur(10px);
            transition: all 0.3s ease;
        }

        #scroll-speed-panel:hover {
            box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
            transform: translateY(-2px);
        }

        #scroll-speed-panel.hidden {
            transform: translateX(calc(100% - 40px));
        }

        #scroll-speed-panel .title {
            margin-bottom: 12px;
            font-weight: 600;
            text-align: center;
            font-size: 16px;
            color: #fff;
        }

        #scroll-speed-panel .speed-display {
            margin-bottom: 10px;
            text-align: center;
            font-weight: 500;
        }

        #scroll-speed-panel .speed-value {
            color: #4CAF50;
            font-weight: bold;
            font-size: 16px;
        }

        #scroll-speed-panel .slider-container {
            margin-bottom: 12px;
            position: relative;
        }

        #scroll-speed-panel .slider {
            width: 100%;
            height: 6px;
            border-radius: 3px;
            background: rgba(255, 255, 255, 0.2);
            outline: none;
            cursor: pointer;
            -webkit-appearance: none;
        }

        #scroll-speed-panel .slider::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 18px;
            height: 18px;
            border-radius: 50%;
            background: #4CAF50;
            cursor: pointer;
            box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
            transition: all 0.2s ease;
        }

        #scroll-speed-panel .slider::-webkit-slider-thumb:hover {
            transform: scale(1.2);
            background: #66BB6A;
        }

        #scroll-speed-panel .slider::-moz-range-thumb {
            width: 18px;
            height: 18px;
            border-radius: 50%;
            background: #4CAF50;
            cursor: pointer;
            border: none;
            box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
        }

        #scroll-speed-panel .button-row {
            display: flex;
            gap: 8px;
            margin-bottom: 12px;
        }

        #scroll-speed-panel .btn {
            flex: 1;
            padding: 8px 12px;
            cursor: pointer;
            border: none;
            border-radius: 6px;
            color: white;
            font-size: 12px;
            font-weight: 500;
            transition: all 0.2s ease;
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }

        #scroll-speed-panel .btn:hover {
            transform: translateY(-1px);
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
        }

        #scroll-speed-panel .btn-reset {
            background: linear-gradient(135deg, #6c757d, #5a6268);
        }

        #scroll-speed-panel .btn-reset:hover {
            background: linear-gradient(135deg, #5a6268, #495057);
        }

        #scroll-speed-panel .btn-toggle {
            background: linear-gradient(135deg, #dc3545, #c82333);
        }

        #scroll-speed-panel .btn-toggle.enabled {
            background: linear-gradient(135deg, #28a745, #1e7e34);
        }

        #scroll-speed-panel .btn-toggle:hover {
            opacity: 0.9;
        }

        #scroll-speed-panel .btn-hide {
            background: linear-gradient(135deg, #6f42c1, #5a2d91);
            margin-top: 4px;
            width: 100%;
        }

        #scroll-speed-panel .btn-hide:hover {
            background: linear-gradient(135deg, #5a2d91, #4c2a85);
        }

        #scroll-speed-panel .help-text {
            font-size: 11px;
            color: #ccc;
            line-height: 1.4;
            text-align: center;
            margin-bottom: 8px;
        }

        #scroll-speed-panel .status {
            text-align: center;
            font-size: 11px;
            padding: 4px 8px;
            border-radius: 12px;
            margin-bottom: 8px;
        }

        #scroll-speed-panel .status.enabled {
            background: rgba(40, 167, 69, 0.2);
            color: #28a745;
        }

        #scroll-speed-panel .status.disabled {
            background: rgba(220, 53, 69, 0.2);
            color: #dc3545;
        }

        #scroll-speed-mini {
            position: fixed;
            top: 20px;
            right: 20px;
            width: 40px;
            height: 40px;
            background: linear-gradient(135deg, rgba(0, 0, 0, 0.9), rgba(30, 30, 30, 0.9));
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            z-index: 99999;
            box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
            backdrop-filter: blur(10px);
            border: 1px solid rgba(255, 255, 255, 0.1);
            transition: all 0.3s ease;
        }

        #scroll-speed-mini:hover {
            transform: scale(1.1);
            box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);
        }

        #scroll-speed-mini .icon {
            color: white;
            font-size: 18px;
        }
    `);

    // 创建控制面板
    function createControlPanel() {
        const panel = document.createElement('div');
        panel.id = 'scroll-speed-panel';
        panel.className = config.panelVisible ? '' : 'hidden';

        panel.innerHTML = `
            <div class="title">🖱️ 滚轮速度调节</div>
            <div class="status ${config.isEnabled ? 'enabled' : 'disabled'}">
                ${config.isEnabled ? '● 已启用' : '● 已禁用'}
            </div>
            <div class="speed-display">
                速度倍数: <span class="speed-value" id="speed-value">${config.speedMultiplier.toFixed(1)}x</span>
            </div>
            <div class="slider-container">
                <input type="range" id="speed-slider" class="slider" min="0.1" max="5.0" step="0.1" value="${config.speedMultiplier}">
            </div>
            <div class="button-row">
                <button id="reset-btn" class="btn btn-reset">重置</button>
                <button id="toggle-btn" class="btn btn-toggle ${config.isEnabled ? 'enabled' : ''}">
                    ${config.isEnabled ? '关闭' : '开启'}
                </button>
            </div>
            <div class="help-text">
                拖动滑块调节速度<br>
                0.1x=很慢 | 1.0x=正常 | 5.0x=很快
            </div>
            <button id="hide-btn" class="btn btn-hide">隐藏面板</button>
        `;

        document.body.appendChild(panel);

        // 如果面板隐藏,创建迷你图标
        if (!config.panelVisible) {
            createMiniIcon();
        }

        return panel;
    }

    // 创建迷你图标
    function createMiniIcon() {
        const existing = document.getElementById('scroll-speed-mini');
        if (existing) return;

        const mini = document.createElement('div');
        mini.id = 'scroll-speed-mini';
        mini.innerHTML = '<div class="icon">🖱️</div>';

        mini.addEventListener('click', function() {
            config.panelVisible = true;
            GM_setValue('panelVisible', 'true');
            document.getElementById('scroll-speed-panel').className = '';
            mini.remove();
        });

        document.body.appendChild(mini);
    }

    // 绑定控制面板事件
    function bindPanelEvents() {
        const speedSlider = document.getElementById('speed-slider');
        const speedValue = document.getElementById('speed-value');
        const resetBtn = document.getElementById('reset-btn');
        const toggleBtn = document.getElementById('toggle-btn');
        const hideBtn = document.getElementById('hide-btn');
        const statusEl = document.querySelector('.status');

        // 更新显示
        function updateDisplay() {
            speedValue.textContent = config.speedMultiplier.toFixed(1) + 'x';
            speedSlider.value = config.speedMultiplier;
            toggleBtn.textContent = config.isEnabled ? '关闭' : '开启';
            toggleBtn.className = `btn btn-toggle ${config.isEnabled ? 'enabled' : ''}`;
            statusEl.textContent = config.isEnabled ? '● 已启用' : '● 已禁用';
            statusEl.className = `status ${config.isEnabled ? 'enabled' : 'disabled'}`;
        }

        // 滑块事件
        speedSlider.addEventListener('input', function() {
            config.speedMultiplier = parseFloat(this.value);
            speedValue.textContent = config.speedMultiplier.toFixed(1) + 'x';
            GM_setValue('scrollSpeedMultiplier', config.speedMultiplier.toString());
        });

        // 重置按钮
        resetBtn.addEventListener('click', function() {
            config.speedMultiplier = 1.0;
            updateDisplay();
            GM_setValue('scrollSpeedMultiplier', '1.0');
        });

        // 开关按钮
        toggleBtn.addEventListener('click', function() {
            config.isEnabled = !config.isEnabled;
            updateDisplay();
            GM_setValue('scrollSpeedEnabled', config.isEnabled.toString());
        });

        // 隐藏按钮
        hideBtn.addEventListener('click', function() {
            config.panelVisible = false;
            GM_setValue('panelVisible', 'false');
            document.getElementById('scroll-speed-panel').className = 'hidden';
            setTimeout(createMiniIcon, 300);
        });
    }

    // 使面板可拖拽
    function makeDraggable() {
        const panel = document.getElementById('scroll-speed-panel');
        let isDragging = false;
        let startX, startY, initialX, initialY;

        panel.addEventListener('mousedown', function(e) {
            // 避免在控件上拖拽
            if (e.target.tagName === 'INPUT' || e.target.tagName === 'BUTTON') {
                return;
            }

            isDragging = true;
            startX = e.clientX;
            startY = e.clientY;
            initialX = panel.offsetLeft;
            initialY = panel.offsetTop;

            panel.style.cursor = 'grabbing';
            e.preventDefault();
        });

        document.addEventListener('mousemove', function(e) {
            if (!isDragging) return;

            const dx = e.clientX - startX;
            const dy = e.clientY - startY;

            const newX = Math.max(0, Math.min(window.innerWidth - panel.offsetWidth, initialX + dx));
            const newY = Math.max(0, Math.min(window.innerHeight - panel.offsetHeight, initialY + dy));

            panel.style.left = newX + 'px';
            panel.style.top = newY + 'px';
            panel.style.right = 'auto';
        });

        document.addEventListener('mouseup', function() {
            if (isDragging) {
                isDragging = false;
                panel.style.cursor = 'move';
            }
        });
    }

    // 滚轮事件处理
    function handleWheel(e) {
        if (!config.isEnabled || config.speedMultiplier === 1.0) {
            return;
        }

        e.preventDefault();
        e.stopPropagation();

        const deltaY = e.deltaY * config.speedMultiplier;
        const deltaX = e.deltaX * config.speedMultiplier;

        window.scrollBy({
            left: deltaX,
            top: deltaY,
            behavior: 'auto'
        });
    }

    // 注册菜单命令
    function registerMenuCommands() {
        GM_registerMenuCommand('显示/隐藏控制面板', function() {
            config.panelVisible = !config.panelVisible;
            GM_setValue('panelVisible', config.panelVisible.toString());

            const panel = document.getElementById('scroll-speed-panel');
            const mini = document.getElementById('scroll-speed-mini');

            if (config.panelVisible) {
                panel.className = '';
                if (mini) mini.remove();
            } else {
                panel.className = 'hidden';
                setTimeout(createMiniIcon, 300);
            }
        });

        GM_registerMenuCommand('重置所有设置', function() {
            if (confirm('确定要重置所有设置吗?')) {
                config.speedMultiplier = 1.0;
                config.isEnabled = true;
                config.panelVisible = true;

                GM_setValue('scrollSpeedMultiplier', '1.0');
                GM_setValue('scrollSpeedEnabled', 'true');
                GM_setValue('panelVisible', 'true');

                location.reload();
            }
        });
    }

    // 初始化
    function init() {
        try {
            // 等待页面加载
            if (!document.body) {
                setTimeout(init, 100);
                return;
            }

            // 创建控制面板
            createControlPanel();

            // 绑定事件
            bindPanelEvents();
            makeDraggable();
            registerMenuCommands();

            // 添加滚轮事件监听 - 使用捕获模式
            document.addEventListener('wheel', handleWheel, {
                passive: false,
                capture: true
            });

            console.log('鼠标滚轮速度调节器初始化完成!当前设置:', config);

            // 显示欢迎通知(仅首次安装)
            if (GM_getValue('firstInstall', 'true') === 'true') {
                GM_setValue('firstInstall', 'false');
                setTimeout(() => {
                    GM_notification({
                        title: '🖱️ 滚轮速度调节器',
                        text: '安装成功!可在右上角看到控制面板',
                        timeout: 3000
                    });
                }, 1000);
            }

        } catch (error) {
            console.error('滚轮速度调节器初始化失败:', error);
        }
    }

    // 启动
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

})();