Greasy Fork

Greasy Fork is available in English.

智能自动点击器 (iOS极简版 v1.2)

iOS风格UI,支持悬浮球自由拖拽、坐标记忆及自定义快捷键

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         智能自动点击器 (iOS极简版 v1.2)
// @namespace    http://tampermonkey.net/
// @version      1.2.0
// @description  iOS风格UI,支持悬浮球自由拖拽、坐标记忆及自定义快捷键
// @author       You
// @match        *://*/*
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    // 注入增强版 iOS 风格 CSS
    const style = document.createElement('style');
    style.innerHTML = `
        @supports (-webkit-backdrop-filter: none) or (backdrop-filter: none) {
            .ios-glass {
                background: rgba(255, 255, 255, 0.75) !important;
                -webkit-backdrop-filter: saturate(180%) blur(20px) !important;
                backdrop-filter: saturate(180%) blur(20px) !important;
            }
        }
        .ios-glass {
            background: rgba(255, 255, 255, 0.95);
            border: 1px solid rgba(0, 0, 0, 0.1);
            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
        }
        .auto-clicker-fab {
            position: fixed;
            width: 44px;
            height: 44px;
            border-radius: 22px;
            z-index: 999998;
            cursor: move;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 20px;
            transition: transform 0.2s cubic-bezier(0.2, 0, 0.2, 1), box-shadow 0.2s;
            user-select: none;
            touch-action: none;
        }
        .auto-clicker-fab:active { transform: scale(0.9); }
        .auto-clicker-panel {
            position: fixed;
            z-index: 999997;
            border-radius: 16px;
            padding: 20px;
            display: none;
            width: 280px;
            font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", sans-serif;
            color: #1d1d1f;
        }
        .ios-title { font-size: 17px; font-weight: 600; margin: 0 0 16px 0; text-align: center; }
        .ios-input-group { margin-bottom: 12px; }
        .ios-label { display: block; font-size: 12px; font-weight: 500; color: #86868b; margin-bottom: 6px; text-transform: uppercase; }
        .ios-input { width: 100%; box-sizing: border-box; padding: 10px 12px; background: rgba(0, 0, 0, 0.05); border: none; border-radius: 10px; font-size: 14px; color: #1d1d1f; outline: none; }
        .ios-shortcut-btn { background: rgba(0, 113, 227, 0.1); color: #0071e3; font-weight: 600; text-align: center; cursor: pointer; padding: 8px; border-radius: 8px; font-size: 13px; }
        .ios-btn { width: 100%; padding: 12px; border: none; border-radius: 12px; font-size: 15px; font-weight: 600; cursor: pointer; transition: all 0.2s; margin-bottom: 8px; }
        .ios-btn-primary { background: #0071e3; color: white; }
        .ios-btn-success { background: #34c759; color: white; }
        .ios-btn-danger { background: #ff3b30; color: white; }
        .ios-btn-disabled { background: #e5e5ea; color: #8e8e93; cursor: not-allowed; }
        .ios-flex-row { display: flex; gap: 8px; }
    `;
    document.head.appendChild(style);

    // 配置初始化
    const config = {
        enabled: false,
        delay: 1000,
        clickCount: 0,
        currentClicks: 0,
        targetX: 0,
        targetY: 0,
        hasTarget: false,
        shortcut: { ctrl: true, shift: true, key: 'A', display: 'Ctrl + Shift + A' },
        fabPos: { top: '20px', left: 'auto', right: '20px' }
    };

    // 加载本地配置
    const savedConfig = localStorage.getItem('auto_clicker_v12_config');
    if (savedConfig) Object.assign(config, JSON.parse(savedConfig));

    // 创建元素
    const cursor = document.createElement('div');
    cursor.style.cssText = `position: fixed; width: 30px; height: 30px; border: 2px solid #0071e3; border-radius: 50%; pointer-events: none; z-index: 999999; display: none; background: rgba(0, 113, 227, 0.1); transform: translate(-50%, -50%); transition: transform 0.1s;`;
    
    const mainButton = document.createElement('div');
    mainButton.className = 'auto-clicker-fab ios-glass';
    mainButton.innerHTML = '⚙️';
    Object.assign(mainButton.style, config.fabPos);

    const panel = document.createElement('div');
    panel.className = 'auto-clicker-panel ios-glass';
    // 面板跟随悬浮球位置逻辑
    const updatePanelPos = () => {
        const rect = mainButton.getBoundingClientRect();
        panel.style.top = (rect.bottom + 10) + 'px';
        panel.style.left = (rect.right - 280) + 'px';
    };

    panel.innerHTML = `
        <h3 class="ios-title">点击器设置</h3>
        <div class="ios-input-group">
            <label class="ios-label">快捷键 (点击下方录制)</label>
            <div id="shortcut-display" class="ios-shortcut-btn">${config.shortcut.display}</div>
        </div>
        <div class="ios-input-group"><label class="ios-label">延迟 (ms)</label><input type="number" id="click-delay" class="ios-input" value="${config.delay}"></div>
        <div class="ios-input-group"><label class="ios-label">次数 (0无限)</label><input type="number" id="click-count" class="ios-input" value="${config.clickCount}"></div>
        <button id="set-position-btn" class="ios-btn ios-btn-success">📍 重新设置位置</button>
        <div class="ios-flex-row">
            <button id="start-btn" class="ios-btn ios-btn-primary" style="flex: 1;">▶️ 开始</button>
            <button id="stop-btn" class="ios-btn ios-btn-disabled" style="flex: 1;" disabled>⏹️ 停止</button>
        </div>
    `;

    document.body.append(cursor, mainButton, panel);

    // 拖拽逻辑
    let isDragging = false, dragX, dragY;
    mainButton.addEventListener('mousedown', (e) => {
        isDragging = true;
        dragX = e.clientX - mainButton.offsetLeft;
        dragY = e.clientY - mainButton.offsetTop;
        mainButton.style.transition = 'none';
    });

    document.addEventListener('mousemove', (e) => {
        if (!isDragging) return;
        let x = e.clientX - dragX, y = e.clientY - dragY;
        mainButton.style.left = x + 'px';
        mainButton.style.top = y + 'px';
        mainButton.style.right = 'auto';
        if (panel.style.display === 'block') updatePanelPos();
    });

    document.addEventListener('mouseup', () => {
        if (!isDragging) return;
        isDragging = false;
        mainButton.style.transition = 'transform 0.2s';
        config.fabPos = { top: mainButton.style.top, left: mainButton.style.left, right: 'auto' };
        saveConfig();
    });

    // 快捷键录制
    let isRecording = false;
    const shortcutBtn = document.getElementById('shortcut-display');
    shortcutBtn.addEventListener('click', () => {
        isRecording = true;
        shortcutBtn.innerText = '请按下按键...';
        shortcutBtn.style.background = '#ff9500';
        shortcutBtn.style.color = 'white';
    });

    document.addEventListener('keydown', (e) => {
        if (isRecording) {
            e.preventDefault();
            const keys = [];
            if (e.ctrlKey) keys.push('Ctrl');
            if (e.shiftKey) keys.push('Shift');
            if (e.altKey) keys.push('Alt');
            if (!['Control', 'Shift', 'Alt'].includes(e.key)) keys.push(e.key.toUpperCase());
            
            config.shortcut = {
                ctrl: e.ctrlKey, shift: e.shiftKey, alt: e.altKey,
                key: e.key.toUpperCase(),
                display: keys.join(' + ')
            };
            shortcutBtn.innerText = config.shortcut.display;
            shortcutBtn.style = '';
            isRecording = false;
            saveConfig();
            return;
        }

        // 匹配快捷键启动/停止
        const s = config.shortcut;
        if (e.ctrlKey === s.ctrl && e.shiftKey === s.shift && e.altKey === s.alt && e.key.toUpperCase() === s.key) {
            e.preventDefault();
            config.enabled ? stopClicking() : startClicking();
        }
    });

    // 核心功能逻辑
    function saveConfig() { localStorage.setItem('auto_clicker_v12_config', JSON.stringify(config)); }

    mainButton.addEventListener('click', () => {
        const isVisible = panel.style.display === 'block';
        panel.style.display = isVisible ? 'none' : 'block';
        if (!isVisible) updatePanelPos();
    });

    const setPosBtn = document.getElementById('set-position-btn');
    const startBtn = document.getElementById('start-btn');
    const stopBtn = document.getElementById('stop-btn');
    let clickInterval = null;

    setPosBtn.addEventListener('click', () => {
        setPosBtn.innerText = '请点击目标...';
        setPosBtn.style.background = '#ff9500';
        cursor.style.display = 'block';
        const handler = (e) => {
            e.preventDefault(); e.stopPropagation();
            config.targetX = e.clientX; config.targetY = e.clientY; config.hasTarget = true;
            saveConfig();
            document.removeEventListener('click', handler, true);
            cursor.style.display = 'none';
            setPosBtn.innerText = '📍 重新设置位置';
            setPosBtn.style.background = '';
        };
        document.addEventListener('click', handler, true);
    });

    function performClick() {
        if (config.clickCount > 0 && config.currentClicks >= config.clickCount) return stopClicking();
        const el = document.elementFromPoint(config.targetX, config.targetY);
        if (el) {
            const init = { view: window, bubbles: true, cancelable: true, clientX: config.targetX, clientY: config.targetY, button: 0 };
            ['mousedown', 'mouseup', 'click'].forEach(t => el.dispatchEvent(new MouseEvent(t, init)));
        }
        config.currentClicks++;
        document.getElementById('click-counter') && (document.getElementById('click-counter').innerText = config.currentClicks);
    }

    function startClicking() {
        if (!config.hasTarget) return alert('请先设置位置');
        config.enabled = true; config.currentClicks = 0;
        startBtn.disabled = true; startBtn.className = 'ios-btn ios-btn-disabled';
        stopBtn.disabled = false; stopBtn.className = 'ios-btn ios-btn-danger';
        mainButton.innerHTML = '🔴';
        clickInterval = setInterval(performClick, config.delay);
    }

    function stopClicking() {
        config.enabled = false; clearInterval(clickInterval);
        startBtn.disabled = false; startBtn.className = 'ios-btn ios-btn-primary';
        stopBtn.disabled = true; stopBtn.className = 'ios-btn ios-btn-disabled';
        mainButton.innerHTML = '⚙️';
    }

    startBtn.addEventListener('click', startClicking);
    stopBtn.addEventListener('click', stopClicking);
    document.getElementById('click-delay').addEventListener('change', (e) => { config.delay = e.target.value; saveConfig(); });
    document.getElementById('click-count').addEventListener('change', (e) => { config.clickCount = e.target.value; saveConfig(); });

})();