Smart Paste Simulator

Вставка с симуляцией ручного ввода

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

You will need to install an extension such as Tampermonkey to install this script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name         Smart Paste Simulator
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Вставка с симуляцией ручного ввода
// @author       Вы
// @match        *://*/*
// @grant        GM_addStyle
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    // Переменная для отслеживания последнего поля
    let lastFocusedElement = null;

    // Минимальные стили
    GM_addStyle(`
        #smart-paste-btn {
            position: fixed;
            bottom: 20px;
            right: 20px;
            width: 60px;
            height: 60px;
            background: linear-gradient(135deg, #4CAF50, #45a049);
            color: white;
            border: none;
            border-radius: 50%;
            cursor: pointer;
            z-index: 999999;
            font-size: 24px;
            box-shadow: 0 4px 12px rgba(76, 175, 80, 0.4);
            transition: all 0.3s ease;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 0;
        }

        #smart-paste-btn:hover {
            transform: scale(1.1);
            box-shadow: 0 6px 15px rgba(76, 175, 80, 0.6);
            background: linear-gradient(135deg, #45a049, #3d8b40);
        }

        #smart-paste-btn:active {
            transform: scale(0.95);
        }

        #smart-paste-btn.loading {
            background: linear-gradient(135deg, #FF9800, #F57C00);
            animation: pulse 1s infinite;
        }

        @keyframes pulse {
            0% { transform: scale(1); }
            50% { transform: scale(1.05); }
            100% { transform: scale(1); }
        }
    `);

    // Создаем кнопку
    function createButton() {
        const button = document.createElement('button');
        button.id = 'smart-paste-btn';
        button.innerHTML = '📋';
        button.title = 'Вставить с симуляцией ввода (Ctrl+Shift+V)';

        button.addEventListener('click', handlePaste);
        document.body.appendChild(button);

        // Добавляем хоткей
        document.addEventListener('keydown', function(e) {
            if (e.ctrlKey && e.shiftKey && e.key === 'V') {
                e.preventDefault();
                handlePaste();
            }
        });

        // Отслеживаем последний сфокусированный элемент
        document.addEventListener('focusin', function(e) {
            const target = e.target;
            if (target.tagName === 'INPUT' ||
                target.tagName === 'TEXTAREA' ||
                target.isContentEditable) {
                lastFocusedElement = target;
            }
        }, true);

        // Также отслеживаем клики на contenteditable
        document.addEventListener('click', function(e) {
            if (e.target.isContentEditable) {
                lastFocusedElement = e.target;
            }
        }, true);
    }

    // Основная функция вставки
    async function handlePaste() {
        const button = document.getElementById('smart-paste-btn');

        // Пытаемся определить целевой элемент
        let targetElement = lastFocusedElement || document.activeElement;

        // Проверяем, подходит ли элемент для ввода
        if (!targetElement || !isInputElement(targetElement)) {
            showNotification('⚠️ Сначала кликните в поле ввода');

            // Подсвечиваем все поля на странице
            const inputFields = document.querySelectorAll('input, textarea, [contenteditable]');
            inputFields.forEach(field => {
                const originalBorder = field.style.border;
                field.style.border = '2px solid #4CAF50';
                field.style.boxShadow = '0 0 8px rgba(76, 175, 80, 0.5)';

                setTimeout(() => {
                    field.style.border = originalBorder;
                    field.style.boxShadow = '';
                }, 2000);
            });

            return;
        }

        // Восстанавливаем фокус
        targetElement.focus();

        try {
            // Пытаемся прочитать буфер обмена
            const text = await navigator.clipboard.readText();

            if (!text) {
                showNotification('⚠️ Буфер обмена пуст');
                return;
            }

            // Начинаем симуляцию
            button.classList.add('loading');
            button.innerHTML = '⌨️';

            // Симулируем ввод
            await simulateTyping(targetElement, text);

            button.classList.remove('loading');
            button.innerHTML = '✅';

            setTimeout(() => {
                button.innerHTML = '📋';
            }, 1000);

        } catch (err) {
            button.classList.remove('loading');
            button.innerHTML = '📋';
            showNotification('⚠️ Не могу прочитать буфер обмена');
            console.error('Clipboard error:', err);
        }
    }

    // Проверка элемента ввода
    function isInputElement(element) {
        return element.tagName === 'INPUT' ||
               element.tagName === 'TEXTAREA' ||
               element.isContentEditable;
    }

    // Улучшенная симуляция ввода
    async function simulateTyping(element, text) {
        const isInput = element.tagName === 'INPUT' || element.tagName === 'TEXTARTEAA';
        const originalValue = isInput ? element.value : element.textContent;

        // Очищаем поле
        if (isInput) {
            element.value = '';
        } else {
            element.textContent = '';
        }

        // Триггерим события очистки
        triggerEvent(element, 'input');
        triggerEvent(element, 'change');

        // Разбиваем текст на части для более плавного ввода
        const chunks = splitTextIntoChunks(text);
        let typedLength = 0;

        for (const chunk of chunks) {
            await typeChunk(element, chunk, isInput);
            typedLength += chunk.length;

            // Показываем прогресс каждые 50 символов
            if (typedLength % 50 === 0) {
                showNotification(`⌨️ Введено ${typedLength}/${text.length} символов`);
            }
        }

        // Финальные события
        triggerEvent(element, 'change');

        // Возвращаем фокус
        setTimeout(() => element.focus(), 50);

        showNotification(`✅ Вставлено ${text.length} символов`);
    }

    // Разбивка текста на чанки
    function splitTextIntoChunks(text) {
        const chunks = [];
        let currentChunk = '';
        let inWord = false;

        for (let i = 0; i < text.length; i++) {
            const char = text[i];
            currentChunk += char;

            // Разбиваем по словам или после 3-10 символов
            const shouldBreak =
                char === ' ' ||
                char === '\n' ||
                char === ',' ||
                char === '.' ||
                currentChunk.length >= 3 + Math.random() * 7;

            if (shouldBreak && currentChunk.length > 0) {
                chunks.push(currentChunk);
                currentChunk = '';
            }
        }

        if (currentChunk.length > 0) {
            chunks.push(currentChunk);
        }

        return chunks;
    }

    // Ввод одного чанка
    async function typeChunk(element, chunk, isInput) {
        return new Promise(resolve => {
            let index = 0;

            function typeNextChar() {
                if (index < chunk.length) {
                    const char = chunk[index];

                    // Случайная задержка (имитация человеческой скорости)
                    const delay = 20 + Math.random() * 30;

                    // Создаем события
                    const keydownEvent = new KeyboardEvent('keydown', {
                        key: char,
                        code: getKeyCode(char),
                        keyCode: char.charCodeAt(0),
                        bubbles: true,
                        cancelable: true
                    });

                    const keypressEvent = new KeyboardEvent('keypress', {
                        key: char,
                        code: getKeyCode(char),
                        keyCode: char.charCodeAt(0),
                        bubbles: true,
                        cancelable: true
                    });

                    // Диспатчим события
                    element.dispatchEvent(keydownEvent);
                    element.dispatchEvent(keypressEvent);

                    // Добавляем символ
                    if (isInput) {
                        element.value += char;
                    } else {
                        element.textContent += char;
                    }

                    // Событие input
                    const inputEvent = new InputEvent('input', {
                        data: char,
                        inputType: 'insertText',
                        bubbles: true
                    });
                    element.dispatchEvent(inputEvent);

                    // Обновляем курсор
                    if (isInput) {
                        element.selectionStart = element.selectionEnd = element.value.length;
                    }

                    // Поддерживаем фокус
                    element.focus();

                    index++;
                    setTimeout(typeNextChar, delay);
                } else {
                    resolve();
                }
            }

            typeNextChar();
        });
    }

    // Получение кода клавиши
    function getKeyCode(char) {
        if (char === ' ') return 'Space';
        if (char === '\n') return 'Enter';
        if (char === '\t') return 'Tab';
        if (char.length === 1 && char.match(/[a-z]/i)) return `Key${char.toUpperCase()}`;
        if (char.length === 1 && char.match(/[0-9]/)) return `Digit${char}`;
        return char;
    }

    // Триггеринг события
    function triggerEvent(element, eventName) {
        const event = new Event(eventName, { bubbles: true });
        element.dispatchEvent(event);
    }

    // Простое уведомление
    function showNotification(message) {
        // Удаляем старое уведомление
        const oldNote = document.getElementById('smart-paste-notification');
        if (oldNote) oldNote.remove();

        const notification = document.createElement('div');
        notification.id = 'smart-paste-notification';
        notification.textContent = message;

        notification.style.cssText = `
            position: fixed;
            top: 20px;
            right: 20px;
            background: #333;
            color: white;
            padding: 10px 15px;
            border-radius: 6px;
            z-index: 999998;
            font-family: system-ui, -apple-system, sans-serif;
            font-size: 13px;
            box-shadow: 0 3px 10px rgba(0,0,0,0.2);
            animation: fadeIn 0.3s ease;
        `;

        document.body.appendChild(notification);

        setTimeout(() => {
            notification.style.animation = 'fadeOut 0.3s ease';
            setTimeout(() => notification.remove(), 300);
        }, 2000);

        // Добавляем стили анимации
        if (!document.querySelector('#smart-paste-styles')) {
            const style = document.createElement('style');
            style.id = 'smart-paste-styles';
            style.textContent = `
                @keyframes fadeIn {
                    from { opacity: 0; transform: translateY(-10px); }
                    to { opacity: 1; transform: translateY(0); }
                }
                @keyframes fadeOut {
                    from { opacity: 1; transform: translateY(0); }
                    to { opacity: 0; transform: translateY(-10px); }
                }
            `;
            document.head.appendChild(style);
        }
    }

    // Инициализация
    setTimeout(() => {
        createButton();
        showNotification('📋 Smart Paste загружен. Нажмите кнопку или Ctrl+Shift+V');
    }, 1000);
})();