File size: 7,412 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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
(function () {
    console.log("%c Monkeytype Command Typer (execCommand) ", "background: #222; color: #ff0000; font-size: 20px");

    const CONFIG = {
        minWPM: 310,      // Minimum expected WPM
        maxWPM: 550,      // Maximum expected WPM
        errorRate: 0.05,  // 15% chance to make a mistake
        accuracy: 95,     // Target accuracy (affects error correction)
        startDelay: 50,   // Delay before starting to type
    };

    let isArmed = true;

    // EXECCOMMAND METHOD
    // This often bypasses "isTrusted" checks because it simulates a browser action (paste/insert)
    // rather than a raw key event.
    function typeChar(char) {
        const target = document.activeElement || document.body;
        const keyConfig = {
            key: char,
            code: char === ' ' ? 'Space' : `Key${char.toUpperCase()}`,
            bubbles: true,
            cancelable: true,
            view: window
        };

        // Dispatch keydown
        target.dispatchEvent(new KeyboardEvent('keydown', keyConfig));

        // Dispatch keypress (typical for character input)
        target.dispatchEvent(new KeyboardEvent('keypress', keyConfig));

        // We use insertText which is a powerful way to simulate user input
        document.execCommand('insertText', false, char);

        // Dispatch input event (execCommand usually triggers this, but to be safe)
        // target.dispatchEvent(new InputEvent('input', { data: char, inputType: 'insertText', bubbles: true }));

        // Dispatch keyup
        target.dispatchEvent(new KeyboardEvent('keyup', keyConfig));
    }

    // Helper to sleep for a random duration
    function sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }

    // Calculate dynamic delay based on WPM
    // Standard word length is 5 chars. WPM = (Chars / 5) / (Time_min)
    // Time_char_ms = (60000 / (WPM * 5))
    function getKeystrokeDelay() {
        // Pick a random WPM between min and max
        const currentWPM = Math.floor(Math.random() * (CONFIG.maxWPM - CONFIG.minWPM + 1)) + CONFIG.minWPM;
        const baseDelay = 60000 / (currentWPM * 5);

        // Add some noise: +/- 20% variance per keystroke
        const variance = baseDelay * 0.2;
        const noise = (Math.random() * variance * 2) - variance;

        return Math.max(10, baseDelay + noise); // Ensure delay is at least 10ms
    }

    async function simulateMistake(correctChar) {
        const possibleMistakes = "abcdefghijklmnopqrstuvwxyz";
        const distinctMistake = possibleMistakes.charAt(Math.floor(Math.random() * possibleMistakes.length));

        // Type wrong char
        typeChar(distinctMistake);

        // Realization reaction time (slower than typing)
        await sleep(getKeystrokeDelay() * 2.5);

        // Backspace - simulate by selecting and deleting or execCommand delete?
        // execCommand 'delete' works well for single char deletion
        // Dispatch Backspace events
        const target = document.activeElement || document.body;
        const bsConfig = { key: 'Backspace', code: 'Backspace', bubbles: true, cancelable: true, view: window };

        target.dispatchEvent(new KeyboardEvent('keydown', bsConfig));
        document.execCommand('delete', false, null);
        target.dispatchEvent(new KeyboardEvent('keyup', bsConfig));

        // Correction pause
        await sleep(getKeystrokeDelay() * 1.5);
    }

    // Get the current word text that needs to be typed (remaining letters)
    function getCurrentWordText() {
        const activeWord = document.querySelector('#words .word.active');
        if (!activeWord) return null;

        const letters = activeWord.querySelectorAll('letter');
        let text = "";
        let foundUntyped = false;

        for (const letter of letters) {
            // Check if this letter hasn't been typed yet (no 'correct' or 'incorrect' class)
            if (!letter.classList.contains('correct') && !letter.classList.contains('incorrect')) {
                foundUntyped = true;
            }
            if (foundUntyped) {
                text += letter.textContent;
            }
        }

        return text;
    }

    // Main typing loop - continuously fetches words from DOM
    async function autoTypeLoop() {
        console.log("Starting continuous auto-type loop...");

        let wordCount = 0;
        while (true) {
            // Get current word's remaining text
            const currentWordText = getCurrentWordText();

            if (currentWordText === null) {
                // No active word found - test might be complete
                console.log(`Auto-type complete! Typed ${wordCount} words.`);
                break;
            }

            if (currentWordText.length === 0) {
                // Current word is fully typed, need to press space
                // But first check if there's another word coming
                const activeWord = document.querySelector('#words .word.active');
                const nextWord = activeWord ? activeWord.nextElementSibling : null;

                if (!nextWord || !nextWord.classList.contains('word')) {
                    // Might be at the end, wait a bit and check again
                    await sleep(50);
                    const stillActive = document.querySelector('#words .word.active');
                    if (!stillActive) {
                        console.log(`Auto-type complete! Typed ${wordCount} words.`);
                        break;
                    }
                    continue;
                }

                // Type space to move to next word
                typeChar(' ');
                wordCount++;

                let delay = getKeystrokeDelay() * 1.3; // Longer pause between words
                await sleep(delay);
                continue;
            }

            // Type the next character
            const char = currentWordText[0];

            // Check for mistake opportunity (only on alpha characters)
            if (/[a-zA-Z]/.test(char) && Math.random() < CONFIG.errorRate) {
                await simulateMistake(char);
            }

            typeChar(char);

            let delay = getKeystrokeDelay();
            await sleep(delay);
        }
    }

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

        if (e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey) {

            const activeWord = document.querySelector('#words .word.active');
            if (!activeWord) return;

            const firstLetterElement = activeWord.querySelector('letter');
            const firstLetter = firstLetterElement ? firstLetterElement.textContent : null;

            if (firstLetter && e.key === firstLetter) {
                isArmed = false;
                window.removeEventListener('keydown', triggerHandler);

                console.log("Trigger detected. Starting Command Typer...");
                setTimeout(() => {
                    autoTypeLoop();
                }, CONFIG.startDelay);
            }
        }
    };

    window.addEventListener('keydown', triggerHandler);
    console.log("READY! Type the first letter to test Command Mode.");
})();