Human-Typer for Google Docs/Slides

Simulate human typing in Google Docs and Google Slides with realistic features.

Versione datata 07/09/2024. Vedi la nuova versione l'ultima versione.

// ==UserScript==
// @name         Human-Typer for Google Docs/Slides
// @namespace    http://tampermonkey.net/
// @version      0.3
// @description  Simulate human typing in Google Docs and Google Slides with realistic features.
// @author       Your Name
// @match        https://docs.google.com/*
// @match        https://slides.google.com/*
// @grant        none
// @require      https://code.jquery.com/jquery-3.6.0.min.js
// ==/UserScript==

(function() {
    'use strict';

    // Constants
    const TYPING_SPEEDS = {
        fast: [50, 100],
        medium: [100, 200],
        normal: [200, 300],
        slow: [300, 500]
    };

    let settings = {
        text: "",
        speed: "normal",
        errorRate: 0,
        breakTime: 1, // minutes
        breakCount: 1
    };

    function addButton() {
        // Attempt to add the button to different locations in Google Docs or Slides
        let interval = setInterval(() => {
            const toolbar = document.querySelector('.docs-titlebar');
            if (toolbar && !document.querySelector('#human-typer-button')) {
                clearInterval(interval);

                const button = document.createElement('button');
                button.id = 'human-typer-button';
                button.textContent = 'Human-Typer';
                button.style.position = 'fixed';
                button.style.top = '10px';
                button.style.right = '10px';
                button.style.backgroundColor = '#007bff';
                button.style.color = '#fff';
                button.style.border = 'none';
                button.style.padding = '10px 20px';
                button.style.borderRadius = '5px';
                button.style.cursor = 'pointer';
                button.onclick = openSettingsOverlay;
                document.body.appendChild(button);
            }
        }, 1000); // Check every second
    }

    function openSettingsOverlay() {
        if (document.querySelector('#human-typer-overlay')) return;

        const overlay = document.createElement('div');
        overlay.id = 'human-typer-overlay';
        overlay.style.position = 'fixed';
        overlay.style.top = '50px';
        overlay.style.right = '50px';
        overlay.style.backgroundColor = '#fff';
        overlay.style.border = '1px solid #ccc';
        overlay.style.padding = '20px';
        overlay.style.zIndex = 1000;
        overlay.style.boxShadow = '0 4px 8px rgba(0,0,0,0.2)';

        overlay.innerHTML = `
            <h3>Human-Typer Settings</h3>
            <label for="ht-text">Text:</label><br>
            <textarea id="ht-text" rows="4" cols="30"></textarea><br><br>
            <label for="ht-speed">Typing Speed:</label><br>
            <select id="ht-speed">
                <option value="fast">Fast</option>
                <option value="medium">Medium</option>
                <option value="normal" selected>Normal</option>
                <option value="slow">Slow</option>
            </select><br><br>
            <label for="ht-error-rate">Error Rate (%):</label><br>
            <input type="number" id="ht-error-rate" min="0" max="20" value="0"><br><br>
            <label for="ht-break-time">Break Time (minutes):</label><br>
            <input type="number" id="ht-break-time" min="0" value="1"><br><br>
            <label for="ht-break-count">Break Count:</label><br>
            <input type="number" id="ht-break-count" min="0" value="1"><br><br>
            <button id="ht-start-typing">Start Typing</button>
            <button id="ht-close">Close</button>
        `;

        document.body.appendChild(overlay);
        document.getElementById('ht-text').value = settings.text;
        document.getElementById('ht-speed').value = settings.speed;
        document.getElementById('ht-error-rate').value = settings.errorRate;
        document.getElementById('ht-break-time').value = settings.breakTime;
        document.getElementById('ht-break-count').value = settings.breakCount;

        document.getElementById('ht-start-typing').onclick = startTyping;
        document.getElementById('ht-close').onclick = () => overlay.remove();
    }

    function startTyping() {
        settings.text = document.getElementById('ht-text').value;
        settings.speed = document.getElementById('ht-speed').value;
        settings.errorRate = parseInt(document.getElementById('ht-error-rate').value, 10);
        settings.breakTime = parseInt(document.getElementById('ht-break-time').value, 10) * 60000; // convert to ms
        settings.breakCount = parseInt(document.getElementById('ht-break-count').value, 10);

        document.getElementById('human-typer-overlay').remove();
        typeText();
    }

    function typeText() {
        const typingArea = document.activeElement;
        const text = settings.text.split('');
        const [minDelay, maxDelay] = TYPING_SPEEDS[settings.speed];
        const totalBreaks = settings.breakCount;
        let breakInterval = settings.breakTime / totalBreaks;
        let currentBreak = 0;

        function simulateError(char) {
            return Math.random() * 100 < settings.errorRate ? 
                String.fromCharCode(Math.random() * (126 - 33) + 33) : 
                char;
        }

        function typeNextChar() {
            if (text.length === 0) return;

            let char = text.shift();
            char = simulateError(char);
            typingArea.focus();
            const event = new Event('input', { bubbles: true });
            typingArea.textContent += char;
            typingArea.dispatchEvent(event);

            let delay = Math.floor(Math.random() * (maxDelay - minDelay + 1)) + minDelay;
            setTimeout(() => {
                if (text.length === 0 && currentBreak < totalBreaks) {
                    currentBreak++;
                    setTimeout(typeNextChar, breakInterval);
                } else {
                    typeNextChar();
                }
            }, delay);
        }

        typeNextChar();
    }

    window.addEventListener('load', addButton);
})();