Human Typer (Ultimate Fix)

Activates via Alt+V. Pause: Ctrl+Shift+Alt. Kill: Ctrl+Shift+Alt+Space. Console: exit

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

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

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

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

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

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Human Typer (Ultimate Fix)
// @namespace    http://tampermonkey.net/
// @version      8.0
// @description  Activates via Alt+V. Pause: Ctrl+Shift+Alt. Kill: Ctrl+Shift+Alt+Space. Console: exit
// @author       You
// @match        *://*/*
// @grant        none
// @run-at       document-idle
// ==/UserScript==

(function() {
    'use strict';

    // --- 1. DEFINE CONSOLE COMMAND AT THE VERY TOP ---
    // This ensures "exit" is ALWAYS defined in the console, even if the rest of the script breaks.
    window.exit = function() {
        clearTimeout(window.__ht_timeout);
        window.__ht_typing = false;
        window.__ht_paused = false;
        window.__ht_target = null;
        console.log('[HumanTyper] 🛑 SCRIPT EXITED.');
    };
    
    console.log('[HumanTyper] Script loaded. Type "exit" in the console to kill it.');

    // --- 2. ANTI-DOUBLE-SCRIPT LOCK ---
    if (window.__humanTyperMutex) {
        console.log('[HumanTyper] Duplicate script detected. Shutting down duplicate.');
        return; 
    }
    window.__humanTyperMutex = true;

    const LOG_PREFIX = '[HumanTyper]';
    const LOG = console.log.bind(console, LOG_PREFIX);

    // Using window.__ht_ variables so the window.exit() function can see and kill them
    window.__ht_typing = false;
    window.__ht_paused = false;
    let textToType = "";
    let currentIndex = 0;
    window.__ht_timeout = null;
    window.__ht_target = null; 

    // --- 3. Intercept Alt+V (New Activation) ---
    document.addEventListener('keydown', async function(e) {
        // Check for Alt+V (and ensure Ctrl/Shift are NOT held)
        if (e.altKey && !e.ctrlKey && !e.shiftKey && e.code === 'KeyV') {
            
            // CRITICAL FIX: stopImmediatePropagation stops Chrome from stealing focus to open the "View" menu
            e.preventDefault(); 
            e.stopPropagation();
            e.stopImmediatePropagation(); 

            if (window.__ht_typing) return;

            LOG('Alt+V detected. Reading clipboard...');

            let txt = '';
            try {
                if (navigator.clipboard && navigator.clipboard.readText) {
                    txt = await navigator.clipboard.readText();
                }
            } catch (err) {
                console.error(LOG_PREFIX, 'Failed to read clipboard.', err);
                console.error(LOG_PREFIX, 'NOTE: If you are testing on a local HTTP:// website, Chrome blocks clipboard access. It MUST be on HTTPS://');
                return;
            }

            if (!txt) {
                LOG('Clipboard is empty.');
                return;
            }

            window.__ht_target = document.activeElement;
            
            if (!window.__ht_target || !(window.__ht_target.isContentEditable || window.__ht_target.tagName === 'INPUT' || window.__ht_target.tagName === 'TEXTAREA')) {
                LOG('Please focus on a text box before pressing Alt+V.');
                return;
            }

            textToType = txt;
            currentIndex = 0;
            window.__ht_typing = true;
            window.__ht_paused = false;
            
            LOG(`Starting typing (${textToType.length} chars)...`);
            typeNextChar();
        }
    }, true); // 'true' means capture phase (runs before the website)

    // --- 4. Intercept Ctrl+Shift+Alt (Pause) & Ctrl+Shift+Alt+Space (Kill Switch) ---
    document.addEventListener('keydown', function(e) {
        if (e.ctrlKey && e.shiftKey && e.altKey) {
            if (e.repeat) return; 
            e.preventDefault();

            // --- KILL SWITCH LOGIC ---
            if (e.code === 'Space') {
                clearTimeout(window.__ht_timeout);
                window.__ht_typing = false;
                window.__ht_paused = false;
                currentIndex = 0;
                textToType = "";
                window.__ht_target = null;
                LOG('🛑 SCRIPT COMPLETELY STOPPED & RESET.');
                return; 
            }

            // --- PAUSE/RESUME LOGIC ---
            if (!window.__ht_typing) return;

            window.__ht_paused = !window.__ht_paused;

            if (window.__ht_paused) {
                clearTimeout(window.__ht_timeout);
                LOG('⏸️ PAUSED');
            } else {
                LOG('▶️ RESUMED');
                typeNextChar(); 
            }
        }
    }, true);

    // --- 5. Foolproof Typing Logic ---
    function typeNextChar() {
        if (!window.__ht_typing || window.__ht_paused) return;
        
        if (!window.__ht_target || !document.body.contains(window.__ht_target)) {
            LOG('Target text box was removed from the page. Stopping.');
            window.__ht_typing = false;
            return;
        }

        if (currentIndex >= textToType.length) {
            window.__ht_typing = false;
            LOG('Typing loop finished. Running verification...');
            verifyOutput(); 
            return;
        }

        // FORCE FOCUS: Keep typing even if invisible or scrolled away
        if (document.activeElement !== window.__ht_target) {
            window.__ht_target.focus();
        }

        const charToType = textToType[currentIndex];

        if (window.__ht_target.tagName === 'INPUT' || window.__ht_target.tagName === 'TEXTAREA') {
            const prototype = window.__ht_target.tagName === 'TEXTAREA' ? window.HTMLTextAreaElement.prototype : window.HTMLInputElement.prototype;
            const nativeSetter = Object.getOwnPropertyDescriptor(prototype, 'value').set;
            
            const start = window.__ht_target.selectionStart;
            const end = window.__ht_target.selectionEnd;
            const newVal = window.__ht_target.value.substring(0, start) + charToType + window.__ht_target.value.substring(end);
            
            nativeSetter.call(window.__ht_target, newVal);
            window.__ht_target.selectionStart = window.__ht_target.selectionEnd = start + 1;
            window.__ht_target.dispatchEvent(new Event('input', { bubbles: true }));
            
        } else if (window.__ht_target.isContentEditable) {
            document.execCommand('insertHTML', false, charToType);
        }

        currentIndex++;
        
        const humanDelay = Math.floor(Math.random() * 30) + 15; 
        window.__ht_timeout = setTimeout(typeNextChar, humanDelay);
    }

    // --- 6. Verification Subroutine ---
    function verifyOutput() {
        if (!window.__ht_target) return;

        let currentText = "";

        if (window.__ht_target.tagName === 'INPUT' || window.__ht_target.tagName === 'TEXTAREA') {
            currentText = window.__ht_target.value;
        } else if (window.__ht_target.isContentEditable) {
            currentText = window.__ht_target.innerText;
        }

        if (currentText === textToType) {
            LOG('✅ VERIFICATION PASSED: Output is 100% identical to clipboard.');
            return;
        }

        LOG('⚠️ MISMATCH DETECTED: Force-correcting text to match clipboard...');
        forceExactText(window.__ht_target, textToType);
    }

    function forceExactText(el, text) {
        el.focus();
        
        if (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA') {
            const prototype = el.tagName === 'TEXTAREA' ? window.HTMLTextAreaElement.prototype : window.HTMLInputElement.prototype;
            const nativeSetter = Object.getOwnPropertyDescriptor(prototype, 'value').set;
            
            nativeSetter.call(el, text);
            el.selectionStart = el.selectionEnd = text.length;
            el.dispatchEvent(new Event('input', { bubbles: true }));
            el.dispatchEvent(new Event('change', { bubbles: true }));
        } else if (el.isContentEditable) {
            const selection = window.getSelection();
            const range = document.createRange();
            range.selectNodeContents(el);
            selection.removeAllRanges();
            selection.addRange(range);
            
            document.execCommand('insertText', false, text);
        }
        
        LOG('✅ FIX APPLIED: Text force-corrected to match clipboard.');
    }

})();