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.2
// @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==


(function() {
    'use strict';

    // Check if the URL indicates the current page is a Google Docs or Google Slides page
    if (window.location.href.includes("docs.google.com/document/d") || window.location.href.includes("docs.google.com/presentation/d")) {
        // Create a black button on the toolbar next to the "Help" button
        const toolbar = document.querySelector('.docs-material .docs-titlebar-right');
        if (toolbar) {
            const blackButton = document.createElement("div");
            blackButton.textContent = "Human-Typer";
            blackButton.style.backgroundColor = "black";
            blackButton.style.color = "white";
            blackButton.style.padding = "10px 20px";
            blackButton.style.borderRadius = "5px";
            blackButton.style.cursor = "pointer";
            blackButton.style.marginLeft = "10px"; // Add margin to separate from other toolbar items
            blackButton.id = "human-typer-button";
            toolbar.appendChild(blackButton);

            // Function to create and display the UI overlay
            function showUIOverlay() {
                const overlay = document.createElement("div");
                overlay.id = "human-typer-overlay";
                overlay.style.position = "fixed";
                overlay.style.bottom = "10px";
                overlay.style.right = "10px";
                overlay.style.backgroundColor = "rgba(255, 255, 255, 0.9)";
                overlay.style.padding = "15px";
                overlay.style.borderRadius = "8px";
                overlay.style.boxShadow = "0px 2px 10px rgba(0, 0, 0, 0.1)";
                overlay.style.zIndex = "9999";
                overlay.style.display = "flex";
                overlay.style.flexDirection = "column";
                overlay.style.width = "250px";

                // Text input field for user input
                const textInput = document.createElement("textarea");
                textInput.rows = "4";
                textInput.placeholder = "Enter text to type...";
                textInput.style.marginBottom = "10px";
                textInput.style.width = "100%";
                textInput.style.padding = "8px";
                textInput.style.border = "1px solid #ccc";
                textInput.style.borderRadius = "4px";

                // Typing speed customization
                const speedLabel = document.createElement("p");
                speedLabel.textContent = "Typing speed:";
                const speedSelect = document.createElement("select");
                speedSelect.options.add(new Option("Fast", "fast"));
                speedSelect.options.add(new Option("Medium", "medium"));
                speedSelect.options.add(new Option("Normal", "normal"));
                speedSelect.options.add(new Option("Slow", "slow"));

                // Typing error customization
                const errorLabel = document.createElement("p");
                errorLabel.textContent = "Number of typing errors:";
                const errorInput = document.createElement("input");
                errorInput.type = "number";
                errorInput.min = "0";
                errorInput.value = "0";

                // Break time customization
                const breakLabel = document.createElement("p");
                breakLabel.textContent = "Number of breaks:";
                const breakInput = document.createElement("input");
                breakInput.type = "number";
                breakInput.min = "0";
                breakInput.value = "0";

                const breakDurationLabel = document.createElement("p");
                breakDurationLabel.textContent = "Duration of each break (minutes):";
                const breakDurationInput = document.createElement("input");
                breakDurationInput.type = "number";
                breakDurationInput.min = "0";
                breakDurationInput.value = "0";

                // Confirm button to start typing
                const confirmButton = document.createElement("button");
                confirmButton.textContent = "Start Typing";
                confirmButton.style.padding = "8px 16px";
                confirmButton.style.backgroundColor = "#1a73e8";
                confirmButton.style.color = "white";
                confirmButton.style.border = "none";
                confirmButton.style.borderRadius = "4px";
                confirmButton.style.cursor = "pointer";

                // Append elements to the overlay
                overlay.appendChild(textInput);
                overlay.appendChild(speedLabel);
                overlay.appendChild(speedSelect);
                overlay.appendChild(errorLabel);
                overlay.appendChild(errorInput);
                overlay.appendChild(breakLabel);
                overlay.appendChild(breakInput);
                overlay.appendChild(breakDurationLabel);
                overlay.appendChild(breakDurationInput);
                overlay.appendChild(confirmButton);

                // Append the overlay to the body
                document.body.appendChild(overlay);

                // Event listener for the confirm button
                confirmButton.addEventListener("click", () => {
                    const text = textInput.value.trim();
                    const speed = speedSelect.value;
                    const numErrors = parseInt(errorInput.value);
                    const numBreaks = parseInt(breakInput.value);
                    const breakDuration = parseInt(breakDurationInput.value);

                    // If text is empty, do nothing
                    if (!text) return;

                    // Remove the overlay from the page
                    document.body.removeChild(overlay);

                    // Call function to start typing
                    startTyping(text, speed, numErrors, numBreaks, breakDuration);
                });
            }

            // Event listener for the black button
            blackButton.addEventListener("click", () => {
                // Show the UI overlay when the black button is clicked
                showUIOverlay();
            });

            // Function to simulate typing with errors and breaks
            function startTyping(text, speed, numErrors, numBreaks, breakDuration) {
                const inputElement = document.querySelector(".docs-texteventtarget-iframe").contentDocument.activeElement;
                const speedSettings = {
                    fast: { lowerBound: 50, upperBound: 150 },
                    medium: { lowerBound: 60, upperBound: 220 },
                    normal: { lowerBound: 70, upperBound: 200 },
                    slow: { lowerBound: 80, upperBound: 250 }
                };

                const lowerBound = speedSettings[speed].lowerBound;
                const upperBound = speedSettings[speed].upperBound;

                let currentErrorCount = 0;
                let currentBreakCount = 0;
                let breakInterval = Math.floor(text.length / numBreaks);
                let breakTime = breakDuration * 60 * 1000; // Convert break duration from minutes to milliseconds

                async function typeCharacter(character, delay) {
                    return new Promise((resolve) => {
                        if (currentErrorCount < numErrors && Math.random() < 0.05) {
                            // Introduce a random typing error
                            inputElement.value += character;
                            inputElement.value = inputElement.value.slice(0, -2);
                            currentErrorCount++;
                        } else {
                            inputElement.value += character;
                        }

                        setTimeout(resolve, delay);
                    });
                }

                async function typeText(text) {
                    for (let i = 0; i < text.length; i++) {
                        const delay = Math.floor(Math.random() * (upperBound - lowerBound + 1)) + lowerBound;

                        if (currentBreakCount < numBreaks && i > 0 && i % breakInterval === 0) {
                            // Take a break
                            await new Promise((resolve) => setTimeout(resolve, breakTime));
                            currentBreakCount++;
                        }

                        await typeCharacter(text[i], delay);
                    }
                }

                // Start typing the text
                typeText(text);
            }
        }
    }
})();