Human-Typer by Warrior

Simulate human typing in Google Docs and Slides with customizable settings such as typing speed, errors, and breaks.

当前为 2024-04-27 提交的版本,查看 最新版本

// ==UserScript==
// @name         Human-Typer by Warrior
// @description  Simulate human typing in Google Docs and Slides with customizable settings such as typing speed, errors, and breaks.
// @version      1.0
// @namespace    http://yournamespace.com/human-typer
// @match        *://docs.google.com/document/*
// @match        *://docs.google.com/presentation/*
// @include      *://docs.google.com/document/*
// @include      *://docs.google.com/presentation/*
// @license      MIT
// ==/UserScript==

(() => {
    // Initialize Human-Typer UI
    const initHumanTyper = () => {
        // Create the "Human-Typer" button
        const humanTyperButton = document.createElement("div");
        humanTyperButton.textContent = "Human-Typer";
        humanTyperButton.style.backgroundColor = "#000";
        humanTyperButton.style.color = "#fff";
        humanTyperButton.style.position = "fixed";
        humanTyperButton.style.bottom = "20px";
        humanTyperButton.style.right = "20px";
        humanTyperButton.style.padding = "10px";
        humanTyperButton.style.borderRadius = "5px";
        humanTyperButton.style.cursor = "pointer";
        humanTyperButton.id = "human-typer-button";
        
        // Append the button to the body
        document.body.appendChild(humanTyperButton);
        
        // Event listener for button click
        humanTyperButton.addEventListener("click", showOverlay);
    };

    // Function to display the overlay for settings
    const showOverlay = () => {
        // Create the overlay container
        const overlay = document.createElement("div");
        overlay.style.position = "fixed";
        overlay.style.bottom = "20px";
        overlay.style.right = "20px";
        overlay.style.backgroundColor = "#fff";
        overlay.style.padding = "10px";
        overlay.style.borderRadius = "5px";
        overlay.style.boxShadow = "0 0 10px rgba(0, 0, 0, 0.5)";
        overlay.style.zIndex = "9999";

        // Create the text area for user input
        const textArea = document.createElement("textarea");
        textArea.rows = "5";
        textArea.cols = "30";
        textArea.placeholder = "Enter text to type...";
        overlay.appendChild(textArea);
        
        // Create the speed select dropdown
        const speedSelect = document.createElement("select");
        speedSelect.innerHTML = `
            <option value="fast">Fast (50ms - 150ms)</option>
            <option value="medium">Medium (60ms - 220ms)</option>
            <option value="normal">Normal (70ms - 200ms)</option>
            <option value="slow">Slow (80ms - 250ms)</option>
        `;
        overlay.appendChild(document.createElement("br"));
        overlay.appendChild(document.createTextNode("Typing Speed: "));
        overlay.appendChild(speedSelect);
        
        // Create the error rate input
        const errorRateInput = document.createElement("input");
        errorRateInput.type = "number";
        errorRateInput.min = "0";
        errorRateInput.max = "20";
        errorRateInput.value = "0"; // Default error rate is 0%
        overlay.appendChild(document.createElement("br"));
        overlay.appendChild(document.createTextNode("Error Rate (%): "));
        overlay.appendChild(errorRateInput);

        // Create the break time input
        const breakTimeInput = document.createElement("input");
        breakTimeInput.type = "number";
        breakTimeInput.min = "0";
        breakTimeInput.max = "10";
        breakTimeInput.value = "0"; // Default break time is 0 minutes
        overlay.appendChild(document.createElement("br"));
        overlay.appendChild(document.createTextNode("Break Time (min): "));
        overlay.appendChild(breakTimeInput);

        // Create the number of breaks input
        const breakCountInput = document.createElement("input");
        breakCountInput.type = "number";
        breakCountInput.min = "0";
        breakCountInput.max = "10";
        breakCountInput.value = "0"; // Default break count is 0
        overlay.appendChild(document.createElement("br"));
        overlay.appendChild(document.createTextNode("Number of Breaks: "));
        overlay.appendChild(breakCountInput);
        
        // Create the start button
        const startButton = document.createElement("button");
        startButton.textContent = "Start Typing";
        startButton.style.marginTop = "10px";
        overlay.appendChild(document.createElement("br"));
        overlay.appendChild(startButton);

        // Append the overlay to the body
        document.body.appendChild(overlay);
        
        // Event listener for start button click
        startButton.addEventListener("click", () => {
            const userText = textArea.value;
            const typingSpeed = speedSelect.value;
            const errorRate = parseFloat(errorRateInput.value);
            const breakTime = parseFloat(breakTimeInput.value);
            const breakCount = parseInt(breakCountInput.value, 10);
            
            // Remove the overlay after clicking start
            document.body.removeChild(overlay);
            
            // Start typing with the specified settings
            simulateTyping(userText, typingSpeed, errorRate, breakTime, breakCount);
        });
    };

    // Function to simulate typing with specified settings
    const simulateTyping = (text, typingSpeed, errorRate, breakTime, breakCount) => {
        // Define typing speed ranges
        const speedRanges = {
            fast: [50, 150],
            medium: [60, 220],
            normal: [70, 200],
            slow: [80, 250]
        };
        
        // Get the delay range based on typing speed
        const [minDelay, maxDelay] = speedRanges[typingSpeed];
        
        // Calculate error occurrences and break intervals
        const totalCharacters = text.length;
        const totalErrors = Math.floor((errorRate / 100) * totalCharacters);
        const breakIntervals = breakCount ? Math.floor(totalCharacters / breakCount) : totalCharacters;
        
        // Create an input event for typing
        const inputEvent = new Event("input");
        
        let errorCount = 0;
        let breakCountCurrent = 0;

        // Recursive function to type each character
        const typeCharacter = (index = 0) => {
            if (index >= text.length || cancelTyping) {
                console.log("Typing completed.");
                return;
            }

            // Simulate a break if specified
            if (breakCountCurrent < breakCount && index > 0 && index % breakIntervals === 0) {
                console.log(`Taking a break for ${breakTime} minute(s)`);
                setTimeout(() => {
                    breakCountCurrent++;
                    typeCharacter(index);
                }, breakTime * 60000); // Convert minutes to milliseconds
                return;
            }

            // Simulate a typing error
            if (errorCount < totalErrors && Math.random() < errorRate / 100) {
                console.log(`Typing error at index ${index}`);
                const mistake = text.charAt(index);
                // Make a mistake and then fix it
                if (document.activeElement.tagName === "INPUT" || document.activeElement.tagName === "TEXTAREA") {
                    document.activeElement.value += mistake;
                    document.activeElement.dispatchEvent(inputEvent);
                    setTimeout(() => {
                        document.activeElement.value = document.activeElement.value.slice(0, -1); // Delete the last character (mistake)
                        document.activeElement.dispatchEvent(inputEvent);
                        errorCount++;
                        typeCharacter(index); // Retry typing the correct character
                    }, randomDelay(minDelay, maxDelay));
                    return;
                }
            }

            // Type the character at the current index
            if (document.activeElement.tagName === "INPUT" || document.activeElement.tagName === "TEXTAREA") {
                document.activeElement.value += text.charAt(index);
                document.activeElement.dispatchEvent(inputEvent);
            }

            // Move to the next character after a delay
            setTimeout(() => {
                typeCharacter(index + 1);
            }, randomDelay(minDelay, maxDelay));
        };

        // Start typing from the first character
        typeCharacter();
    };

    // Helper function to generate a random delay between the given range
    const randomDelay = (min, max) => Math.random() * (max - min) + min;

    // Initialize the extension when a Google Doc or Slide is opened
    if (window.location.href.includes("docs.google.com/document/d") || window.location.href.includes("docs.google.com/presentation/d")) {
        initHumanTyper();
    }
})();