mtgbrr - Monkeytype Speeder 2025

just press slash and start typing.

// ==UserScript==
// @name mtgbrr - Monkeytype Speeder 2025
// @author natsukitheslashuser 
// @description just press slash and start typing.
// @icon https://i.imgur.com/fUjylt3.png
// @version 42.01
// @match *://monkeytype.com/*
// @run-at document-start
// @grant none
// @license idk
// @namespace natsuki
// ==/UserScript==
/* jshint esversion:6 */

(function() {
    "use strict";

    // Configuration
    const MIN_DELAY = 0;
    const MAX_DELAY = 0;
    const TOGGLE_KEY = "Slash";
    const MISTAKES_PER_MINUTE = 5; // Target mistakes per minute
    const STOP_DELAY = 1; // Ultra-fast 1ms stop delay
    const log = console.log;

    // State variables
    let toggle = false;
    let typingTimeout = null;
    let stopCheckInterval = null;
    let lastKeyPressTime = 0;
    let realKeypressCount = 0;
    let autoKeypressCount = 0;
    let mistakeCount = 0;
    let startTime = 0;
    let isTyping = false;

    function random(min, max) {
        return Math.floor(Math.random() * (max - min + 1) + min);
    }

    function canType() {
        const typingTest = document.getElementById("typingTest");
        if (!typingTest) return false;
        
        const isHidden = typingTest.classList.contains("hidden");
        if (isHidden) toggle = false;
        
        // Only allow typing if toggle is on, test is visible AND we're in active typing state
        return toggle && !isHidden && isTyping;
    }

    function getNextCharacter() {
        const currentWord = document.querySelector(".word.active");
        if (!currentWord) return "";
        
        for (const letter of currentWord.children) {
            if (letter.className === "") return letter.textContent;
        }
        return " ";
    }

    function shouldMakeMistake() {
        // Calculate dynamic mistake chance based on elapsed time to meet target mistakes per minute
        const elapsedSeconds = (Date.now() - startTime) / 1000;
        const elapsedMinutes = elapsedSeconds / 60;
        const targetMistakes = elapsedMinutes * MISTAKES_PER_MINUTE;
        
        // If we've made fewer mistakes than target, increase the chance
        if (mistakeCount < targetMistakes) {
            const remainingTime = 60 - (elapsedSeconds % 60);
            const remainingMistakes = Math.ceil(MISTAKES_PER_MINUTE - mistakeCount % MISTAKES_PER_MINUTE);
            
            // Higher chance as we approach the end of the minute with fewer mistakes
            return Math.random() < (remainingMistakes / (remainingTime * 2));
        }
        
        return false;
    }
    
    function getRandomWrongCharacter(correctChar) {
        const nearbyKeys = {
            'a': ['s', 'q', 'z', 'w'],
            'b': ['v', 'n', 'g', 'h'],
            'c': ['x', 'v', 'd', 'f'],
            'd': ['s', 'f', 'e', 'r'],
            'e': ['w', 'r', 'd', 'f'],
            'f': ['d', 'g', 'r', 't'],
            'g': ['f', 'h', 't', 'y'],
            'h': ['g', 'j', 'y', 'u'],
            'i': ['u', 'o', 'k', 'l'],
            'j': ['h', 'k', 'u', 'i'],
            'k': ['j', 'l', 'i', 'o'],
            'l': ['k', ';', 'o', 'p'],
            'm': ['n', ',', 'j', 'k'],
            'n': ['b', 'm', 'h', 'j'],
            'o': ['i', 'p', 'k', 'l'],
            'p': ['o', '[', 'l', ';'],
            'q': ['w', 'a', '1', '2'],
            'r': ['e', 't', 'd', 'f'],
            's': ['a', 'd', 'w', 'e'],
            't': ['r', 'y', 'f', 'g'],
            'u': ['y', 'i', 'h', 'j'],
            'v': ['c', 'b', 'f', 'g'],
            'w': ['q', 'e', 'a', 's'],
            'x': ['z', 'c', 's', 'd'],
            'y': ['t', 'u', 'g', 'h'],
            'z': ['a', 'x', 's', 'd'],
            ' ': ['n', 'm', 'b', 'v']
        };
        
        if (correctChar in nearbyKeys) {
            const possibleMistakes = nearbyKeys[correctChar];
            return possibleMistakes[Math.floor(Math.random() * possibleMistakes.length)];
        }
        
        // Fallback for characters not in the map
        return String.fromCharCode(correctChar.charCodeAt(0) + (Math.random() > 0.5 ? 1 : -1));
    }

    const InputEvents = {};
    function pressKey(key) {
        const wordsInput = document.getElementById("wordsInput");
        if (!wordsInput) return;
        
        const KeyboardEvent = Object.assign({}, DEFAULT_INPUT_OPTIONS, { target: wordsInput, data: key });
        const InputEvent = Object.assign({}, DEFAULT_KEY_OPTIONS, { target: wordsInput, key: key });

        wordsInput.value += key;
        
        if (InputEvents.beforeinput) InputEvents.beforeinput(InputEvent);
        if (InputEvents.input) InputEvents.input(InputEvent);
        if (InputEvents.keyup) InputEvents.keyup(KeyboardEvent);
        
        autoKeypressCount++;
        
        // Log status occasionally
        if (autoKeypressCount % 10 === 0) {
            log(`Auto: ${autoKeypressCount}, Real: ${realKeypressCount}, Mistakes: ${mistakeCount}`);
        }
    }

    // Ultra-fast continuous stop check
    function setupStopCheck() {
        if (stopCheckInterval) {
            clearInterval(stopCheckInterval);
        }
        
        // Check every 1ms if we should be typing
        stopCheckInterval = setInterval(() => {
            const now = Date.now();
            const idleTime = now - lastKeyPressTime;
            
            // If we haven't had a keypress in STOP_DELAY ms, immediately stop typing
            if (idleTime > STOP_DELAY && isTyping) {
                isTyping = false;
                
                // Clear typing timeout to stop immediately
                if (typingTimeout) {
                    clearTimeout(typingTimeout);
                    typingTimeout = null;
                }
            }
        }, 1); // Check every 1ms for optimal responsiveness
    }

    function typeCharacter() {
        // Clear any existing timeout
        if (typingTimeout) {
            clearTimeout(typingTimeout);
            typingTimeout = null;
        }
        
        // Check if we can type
        if (!canType()) {
            return; // Don't schedule another character if conditions aren't met
        }

        // Get the correct next character
        const nextChar = getNextCharacter();
        
        if (nextChar) {
            // Decide if we should make a mistake
            if (shouldMakeMistake()) {
                const wrongChar = getRandomWrongCharacter(nextChar);
                pressKey(wrongChar);
                mistakeCount++;
                log(`Made mistake: typed '${wrongChar}' instead of '${nextChar}'. Total mistakes: ${mistakeCount}`);
            } else {
                pressKey(nextChar);
            }
            
            // Schedule the next character if still active
            if (canType()) {
                typingTimeout = setTimeout(typeCharacter, random(MIN_DELAY, MAX_DELAY));
            }
        }
    }

    // Handle keydown events
    window.addEventListener("keydown", function(event) {
        if (event.code === TOGGLE_KEY) {
            event.preventDefault();
            if (event.repeat) return;
            
            toggle = !toggle;
            if (toggle) {
                // Reset counters and timers when starting
                realKeypressCount = 0;
                autoKeypressCount = 0;
                mistakeCount = 0;
                startTime = Date.now();
                log("TYPING BOT ENABLED - Press keys to activate typing");
                
                // Set up the ultra-fast stop check interval
                setupStopCheck();
            } else {
                log("TYPING BOT DISABLED");
                
                // Clear all timers
                if (typingTimeout) {
                    clearTimeout(typingTimeout);
                    typingTimeout = null;
                }
                
                if (stopCheckInterval) {
                    clearInterval(stopCheckInterval);
                    stopCheckInterval = null;
                }
                
                isTyping = false;
            }
        } else if (toggle) {
            // Count real keypresses for regular keys
            if (!["Control", "Alt", "Shift", "Meta", "CapsLock", "Tab", "Escape"].includes(event.key)) {
                realKeypressCount++;
                
                // Update the last key press time to keep typing active
                lastKeyPressTime = Date.now();
                
                // Set typing state to active
                isTyping = true;
                
                // Start typing if not already typing
                if (!typingTimeout) {
                    typeCharacter();
                }
                
                // Prevent the keypress from affecting the typing
                event.preventDefault();
            }
        }
    }, true);

    // Clean up when page unloads
    window.addEventListener("beforeunload", function() {
        if (typingTimeout) clearTimeout(typingTimeout);
        if (stopCheckInterval) clearInterval(stopCheckInterval);
    });

    // Intercept event listeners
    function hook(element) {
        element.addEventListener = new Proxy(element.addEventListener, {
            apply(target, _this, args) {
                const [type, listener, ...options] = args;
                if (_this.id === "wordsInput") {
                    InputEvents[type] = listener;
                }
                return target.apply(_this, args);
            }
        });
    }
    hook(HTMLInputElement.prototype);

    const DEFAULT_KEY_OPTIONS = {
        key: "", code: "", keyCode: 0, which: 0, isTrusted: true, altKey: false,
        bubbles: true, cancelBubble: false, cancelable: true, charCode: 0,
        composed: true, ctrlKey: false, currentTarget: null, defaultPrevented: false,
        detail: 0, eventPhase: 0, isComposing: false, location: 0, metaKey: false,
        path: null, repeat: false, returnValue: true, shiftKey: false, srcElement: null,
        target: null, timeStamp: Date.now(), type: "", view: window,
    };

    const DEFAULT_INPUT_OPTIONS = {
        isTrusted: true, bubbles: true, cancelBubble: false, cancelable: false,
        composed: true, data: "", dataTransfer: null, defaultPrevented: false,
        detail: 0, eventPhase: 0, inputType: "insertText", isComposing: false,
        path: null, returnValue: true, sourceCapabilities: null, srcElement: null,
        target: null, currentTarget: null, timeStamp: Date.now(), type: "input",
        view: null, which: 0
    };
    
    log("MonkeyType Script loaded - Press / to toggle, then type to activate");
})();