File size: 4,824 Bytes
364eb96
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
(function () {
    console.log("%c Monkeytype Cheat Initiated (Persistent Mode) ", "background: #222; color: #bada55; font-size: 20px");

    const keyMap = {
        ' ': { code: 'Space', keyCode: 32 },
        '\n': { code: 'Enter', keyCode: 13 },
    };

    let isArmed = false;

    function typeChar(char) {
        const target = document.activeElement || document.body;
        let key = char;
        let code, keyCode;

        if (keyMap[char]) {
            code = keyMap[char].code;
            keyCode = keyMap[char].keyCode;
        } else {
            code = `Key${char.toUpperCase()}`;
            keyCode = char.toUpperCase().charCodeAt(0);
        }

        const eventOptions = {
            key: key,
            code: code,
            keyCode: keyCode,
            which: keyCode,
            bubbles: true,
            cancelable: true,
            isTrusted: true
        };

        target.dispatchEvent(new KeyboardEvent('keydown', eventOptions));
        target.dispatchEvent(new KeyboardEvent('keypress', eventOptions));

        const inputEvent = new InputEvent('input', {
            data: char,
            inputType: 'insertText',
            bubbles: true,
            cancelable: true
        });
        target.dispatchEvent(inputEvent);

        target.dispatchEvent(new KeyboardEvent('keyup', eventOptions));
    }

    function getDelay() {
        return 100 + (Math.random() * 60 - 30);
    }

    async function cheat(textToType) {
        console.log(`Typing ${textToType.length} chars...`);
        for (let i = 0; i < textToType.length; i++) {
            // Check if test was reset mid-run
            if (!document.querySelector('#words .word.active')) {
                console.log("Test reset detected. Stopping current run.");
                return;
            }
            typeChar(textToType[i]);
            await new Promise(r => setTimeout(r, getDelay()));
        }
    }

    function getFullText() {
        const words = document.querySelectorAll('#words .word');
        let fullBuffer = "";
        words.forEach((word, index) => {
            const letters = word.querySelectorAll('letter');
            letters.forEach(l => fullBuffer += l.textContent);
            if (index < words.length - 1) fullBuffer += " ";
        });
        return fullBuffer;
    }

    const triggerHandler = (e) => {
        if (!isArmed) return;

        if (e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey) {
            const targetText = getFullText();
            if (!targetText) return;

            const firstChar = targetText[0];
            if (firstChar && e.key === firstChar) {
                isArmed = false; // Disarm to prevent double trigger
                const remainingText = targetText.substring(1);
                console.log("Triggered! Starting...");
                setTimeout(() => cheat(remainingText), 150);
            }
        }
    };

    function armCheat() {
        // Debounce slightly to ensure DOM is ready
        setTimeout(() => {
            const text = getFullText();
            if (text.length > 0) {
                isArmed = true;
                console.log("Cheat RE-ARMED. Waiting for first key...");
            } else {
                console.log("Training ended or no words found.");
            }
        }, 500);
    }

    // LISTENER: Watch for Keydown (Trigger)
    // We add this ONCE and keep it capable of firing whenever 'isArmed' is true.
    window.addEventListener('keydown', triggerHandler);

    // MUTATION OBSERVER: Watch for "Restart Test"
    // When #words changes (new words added), we re-arm.
    const wordsContainer = document.querySelector('#words');
    if (wordsContainer) {
        const observer = new MutationObserver((mutations) => {
            for (const mutation of mutations) {
                // If words are added/removed, it means test reset/changed
                if (mutation.type === 'childList') {
                    // Check if we have new words
                    const words = document.querySelectorAll('#words .word');
                    if (words.length > 5) { // Arbitrary threshold to ensure it's a real set of words
                        armCheat();
                        // We break to avoid calling armCheat multiple times per batch update
                        break;
                    }
                }
            }
        });

        observer.observe(wordsContainer, { childList: true });
        console.log("Observer attached. Auto-restart enabled.");

        // Initial Arm
        armCheat();
    } else {
        console.error("Container #words not found. Is the page loaded?");
    }
})();