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.");
})();
|