Upload 41 files
Browse files- .gitattributes +2 -0
- .gitignore +8 -0
- 2026-02-08 13-03-16.mp4 +3 -0
- 2nd_version/2nd_version.js +461 -0
- 2nd_version/README_v2.md +99 -0
- 2nd_version/script_candidate.js +461 -0
- 2nd_version/script_final.js +402 -0
- 3rd_version (latest)/Dump/1.py +181 -0
- 3rd_version (latest)/Dump/2.py +195 -0
- 3rd_version (latest)/Dump/3.py +210 -0
- 3rd_version (latest)/Dump/4.py +221 -0
- 3rd_version (latest)/Dump/5.py +224 -0
- 3rd_version (latest)/Dump/injector.js +64 -0
- 3rd_version (latest)/Dump/requirements.txt +3 -0
- 3rd_version (latest)/Python/mnk_typer copy.py +228 -0
- 4th_version/0.js +367 -0
- Dump/image.png +3 -0
- LICENSE +21 -0
- README.md +70 -0
- STRUCTURE.md +52 -0
- TECHSTACK.md +14 -0
- injector.js +64 -0
- javascript/0_candidate.js +79 -0
- javascript/1_variant.js +88 -0
- javascript/2_variant.js +93 -0
- javascript/3_variant.js +117 -0
- javascript/4_variant.js +127 -0
- javascript/5_variant.js +98 -0
- javascript/6_variant.js +137 -0
- javascript/7_variant.js +153 -0
- javascript/candidate.js +79 -0
- javascript/monkeytype_advanced.js +77 -0
- javascript/monkeytype_auto_typer.js +153 -0
- javascript/monkeytype_cheat.js +137 -0
- javascript/monkeytype_custom_text.js +99 -0
- javascript/monkeytype_legacy.js +106 -0
- javascript/script_candidate copy.js +163 -0
- javascript/script_candidate copy1.js +190 -0
- javascript/script_candidate copy2.js +461 -0
- mnk_lightning_v3.js +285 -0
- mnk_typer.py +195 -0
- requirements.txt +3 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
2026-02-08[[:space:]]13-03-16.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
Dump/image.png filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
WARNING.md
|
| 2 |
+
.venv
|
| 3 |
+
.env
|
| 4 |
+
.vscode/
|
| 5 |
+
.gemini/
|
| 6 |
+
__pycache__/
|
| 7 |
+
*.pyc
|
| 8 |
+
.warning
|
2026-02-08 13-03-16.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:f4e570b89136c3ad69b063ee64255f371434c64cb08c19cfa39573f45824094b
|
| 3 |
+
size 1721926
|
2nd_version/2nd_version.js
ADDED
|
@@ -0,0 +1,461 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
(function () {
|
| 2 |
+
console.log("%c Monkeytype Command Typer (Human-Like) ", "background: #222; color: #ff0000; font-size: 20px");
|
| 3 |
+
|
| 4 |
+
const CONFIG = {
|
| 5 |
+
minWPM: 310, // Minimum expected WPM
|
| 6 |
+
maxWPM: 550, // Maximum expected WPM
|
| 7 |
+
startDelay: 50, // Delay before starting to type
|
| 8 |
+
|
| 9 |
+
// === HUMAN IMPERFECTION RATES ===
|
| 10 |
+
// Wrong character (random letter instead of correct one)
|
| 11 |
+
wrongCharRate: 0.025,
|
| 12 |
+
|
| 13 |
+
// Adjacent key typo (hit a nearby key on keyboard)
|
| 14 |
+
adjacentKeyRate: 0.02,
|
| 15 |
+
|
| 16 |
+
// Double/triple letter (accidentally press key multiple times)
|
| 17 |
+
doubleLetterRate: 0.015,
|
| 18 |
+
tripleLetterRate: 0.003,
|
| 19 |
+
|
| 20 |
+
// Skip letter (finger moved too fast, missed a key)
|
| 21 |
+
skipLetterRate: 0.01,
|
| 22 |
+
|
| 23 |
+
// Transposed letters (swap two adjacent letters like "teh" instead of "the")
|
| 24 |
+
transposeRate: 0.012,
|
| 25 |
+
|
| 26 |
+
// Ctrl+Backspace (delete whole word when frustrated)
|
| 27 |
+
ctrlBackspaceRate: 0.008,
|
| 28 |
+
|
| 29 |
+
// Hesitation/thinking pause (longer pause before difficult letters)
|
| 30 |
+
hesitationRate: 0.04,
|
| 31 |
+
hesitationMultiplier: 3.5, // How much longer the pause is
|
| 32 |
+
|
| 33 |
+
// Burst typing (fast typing followed by slowdown)
|
| 34 |
+
burstTypingRate: 0.08,
|
| 35 |
+
burstSpeedMultiplier: 0.5, // Faster during burst
|
| 36 |
+
burstLength: 5, // Characters in burst
|
| 37 |
+
|
| 38 |
+
// Slow start to words (first letter of word typed slower)
|
| 39 |
+
wordStartSlowdown: 1.8,
|
| 40 |
+
|
| 41 |
+
// Fatigue simulation (gradually slow down over time)
|
| 42 |
+
fatigueEnabled: true,
|
| 43 |
+
fatigueRate: 0.0001, // How much to slow down per character
|
| 44 |
+
|
| 45 |
+
// Recovery pause after mistakes (humans pause after making errors)
|
| 46 |
+
postMistakePauseMultiplier: 2.0,
|
| 47 |
+
};
|
| 48 |
+
|
| 49 |
+
// QWERTY keyboard adjacency map for realistic typos
|
| 50 |
+
const ADJACENT_KEYS = {
|
| 51 |
+
'a': ['q', 'w', 's', 'z'],
|
| 52 |
+
'b': ['v', 'g', 'h', 'n'],
|
| 53 |
+
'c': ['x', 'd', 'f', 'v'],
|
| 54 |
+
'd': ['s', 'e', 'r', 'f', 'c', 'x'],
|
| 55 |
+
'e': ['w', 's', 'd', 'r'],
|
| 56 |
+
'f': ['d', 'r', 't', 'g', 'v', 'c'],
|
| 57 |
+
'g': ['f', 't', 'y', 'h', 'b', 'v'],
|
| 58 |
+
'h': ['g', 'y', 'u', 'j', 'n', 'b'],
|
| 59 |
+
'i': ['u', 'j', 'k', 'o'],
|
| 60 |
+
'j': ['h', 'u', 'i', 'k', 'm', 'n'],
|
| 61 |
+
'k': ['j', 'i', 'o', 'l', 'm'],
|
| 62 |
+
'l': ['k', 'o', 'p'],
|
| 63 |
+
'm': ['n', 'j', 'k'],
|
| 64 |
+
'n': ['b', 'h', 'j', 'm'],
|
| 65 |
+
'o': ['i', 'k', 'l', 'p'],
|
| 66 |
+
'p': ['o', 'l'],
|
| 67 |
+
'q': ['w', 'a'],
|
| 68 |
+
'r': ['e', 'd', 'f', 't'],
|
| 69 |
+
's': ['a', 'w', 'e', 'd', 'x', 'z'],
|
| 70 |
+
't': ['r', 'f', 'g', 'y'],
|
| 71 |
+
'u': ['y', 'h', 'j', 'i'],
|
| 72 |
+
'v': ['c', 'f', 'g', 'b'],
|
| 73 |
+
'w': ['q', 'a', 's', 'e'],
|
| 74 |
+
'x': ['z', 's', 'd', 'c'],
|
| 75 |
+
'y': ['t', 'g', 'h', 'u'],
|
| 76 |
+
'z': ['a', 's', 'x'],
|
| 77 |
+
};
|
| 78 |
+
|
| 79 |
+
let isArmed = true;
|
| 80 |
+
let inBurstMode = false;
|
| 81 |
+
let burstCharsRemaining = 0;
|
| 82 |
+
let totalCharsTyped = 0;
|
| 83 |
+
let recentMistake = false;
|
| 84 |
+
|
| 85 |
+
// Type a single character
|
| 86 |
+
function typeChar(char) {
|
| 87 |
+
const target = document.activeElement || document.body;
|
| 88 |
+
const keyConfig = {
|
| 89 |
+
key: char,
|
| 90 |
+
code: char === ' ' ? 'Space' : `Key${char.toUpperCase()}`,
|
| 91 |
+
bubbles: true,
|
| 92 |
+
cancelable: true,
|
| 93 |
+
view: window
|
| 94 |
+
};
|
| 95 |
+
|
| 96 |
+
target.dispatchEvent(new KeyboardEvent('keydown', keyConfig));
|
| 97 |
+
target.dispatchEvent(new KeyboardEvent('keypress', keyConfig));
|
| 98 |
+
document.execCommand('insertText', false, char);
|
| 99 |
+
target.dispatchEvent(new KeyboardEvent('keyup', keyConfig));
|
| 100 |
+
|
| 101 |
+
totalCharsTyped++;
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
// Single backspace
|
| 105 |
+
function typeBackspace() {
|
| 106 |
+
const target = document.activeElement || document.body;
|
| 107 |
+
const bsConfig = { key: 'Backspace', code: 'Backspace', bubbles: true, cancelable: true, view: window };
|
| 108 |
+
target.dispatchEvent(new KeyboardEvent('keydown', bsConfig));
|
| 109 |
+
document.execCommand('delete', false, null);
|
| 110 |
+
target.dispatchEvent(new KeyboardEvent('keyup', bsConfig));
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
// Ctrl+Backspace to delete whole word
|
| 114 |
+
function typeCtrlBackspace() {
|
| 115 |
+
const target = document.activeElement || document.body;
|
| 116 |
+
const ctrlBsConfig = {
|
| 117 |
+
key: 'Backspace',
|
| 118 |
+
code: 'Backspace',
|
| 119 |
+
ctrlKey: true,
|
| 120 |
+
bubbles: true,
|
| 121 |
+
cancelable: true,
|
| 122 |
+
view: window
|
| 123 |
+
};
|
| 124 |
+
|
| 125 |
+
target.dispatchEvent(new KeyboardEvent('keydown', ctrlBsConfig));
|
| 126 |
+
|
| 127 |
+
// Delete characters until we hit a space or beginning
|
| 128 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 129 |
+
if (activeWord) {
|
| 130 |
+
const incorrectLetters = activeWord.querySelectorAll('letter.incorrect, letter.extra');
|
| 131 |
+
incorrectLetters.forEach(() => {
|
| 132 |
+
document.execCommand('delete', false, null);
|
| 133 |
+
});
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
target.dispatchEvent(new KeyboardEvent('keyup', ctrlBsConfig));
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
function sleep(ms) {
|
| 140 |
+
return new Promise(resolve => setTimeout(resolve, ms));
|
| 141 |
+
}
|
| 142 |
+
|
| 143 |
+
// Get adjacent key for realistic typo
|
| 144 |
+
function getAdjacentKey(char) {
|
| 145 |
+
const lowerChar = char.toLowerCase();
|
| 146 |
+
const adjacent = ADJACENT_KEYS[lowerChar];
|
| 147 |
+
if (adjacent && adjacent.length > 0) {
|
| 148 |
+
const randomAdj = adjacent[Math.floor(Math.random() * adjacent.length)];
|
| 149 |
+
return char === char.toUpperCase() ? randomAdj.toUpperCase() : randomAdj;
|
| 150 |
+
}
|
| 151 |
+
return char; // Fallback to same char if no adjacent found
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
// Get random wrong character
|
| 155 |
+
function getRandomChar() {
|
| 156 |
+
const chars = "abcdefghijklmnopqrstuvwxyz";
|
| 157 |
+
return chars.charAt(Math.floor(Math.random() * chars.length));
|
| 158 |
+
}
|
| 159 |
+
|
| 160 |
+
// Calculate keystroke delay with fatigue and burst mode
|
| 161 |
+
function getKeystrokeDelay() {
|
| 162 |
+
const currentWPM = Math.floor(Math.random() * (CONFIG.maxWPM - CONFIG.minWPM + 1)) + CONFIG.minWPM;
|
| 163 |
+
let baseDelay = 60000 / (currentWPM * 5);
|
| 164 |
+
|
| 165 |
+
// Apply fatigue (gradually slow down)
|
| 166 |
+
if (CONFIG.fatigueEnabled) {
|
| 167 |
+
baseDelay *= (1 + totalCharsTyped * CONFIG.fatigueRate);
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
// Apply burst mode (faster typing)
|
| 171 |
+
if (inBurstMode && burstCharsRemaining > 0) {
|
| 172 |
+
baseDelay *= CONFIG.burstSpeedMultiplier;
|
| 173 |
+
burstCharsRemaining--;
|
| 174 |
+
if (burstCharsRemaining === 0) {
|
| 175 |
+
inBurstMode = false;
|
| 176 |
+
}
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
// Add variance
|
| 180 |
+
const variance = baseDelay * 0.25;
|
| 181 |
+
const noise = (Math.random() * variance * 2) - variance;
|
| 182 |
+
|
| 183 |
+
return Math.max(8, baseDelay + noise);
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
// Get current word's remaining untyped text
|
| 187 |
+
function getCurrentWordText() {
|
| 188 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 189 |
+
if (!activeWord) return null;
|
| 190 |
+
|
| 191 |
+
const letters = activeWord.querySelectorAll('letter');
|
| 192 |
+
let text = "";
|
| 193 |
+
let foundUntyped = false;
|
| 194 |
+
|
| 195 |
+
for (const letter of letters) {
|
| 196 |
+
if (!letter.classList.contains('correct') && !letter.classList.contains('incorrect')) {
|
| 197 |
+
foundUntyped = true;
|
| 198 |
+
}
|
| 199 |
+
if (foundUntyped) {
|
| 200 |
+
text += letter.textContent;
|
| 201 |
+
}
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
return text;
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
// Count how many incorrect letters we've typed in current word
|
| 208 |
+
function getIncorrectCount() {
|
| 209 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 210 |
+
if (!activeWord) return 0;
|
| 211 |
+
return activeWord.querySelectorAll('letter.incorrect, letter.extra').length;
|
| 212 |
+
}
|
| 213 |
+
|
| 214 |
+
// Check if we're at the start of a word
|
| 215 |
+
function isWordStart() {
|
| 216 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 217 |
+
if (!activeWord) return false;
|
| 218 |
+
const typed = activeWord.querySelectorAll('letter.correct, letter.incorrect');
|
| 219 |
+
return typed.length === 0;
|
| 220 |
+
}
|
| 221 |
+
|
| 222 |
+
// === MISTAKE SIMULATION FUNCTIONS ===
|
| 223 |
+
|
| 224 |
+
// Type wrong character and correct it
|
| 225 |
+
async function simulateWrongChar(correctChar) {
|
| 226 |
+
const wrongChar = getRandomChar();
|
| 227 |
+
typeChar(wrongChar);
|
| 228 |
+
await sleep(getKeystrokeDelay() * 2.5);
|
| 229 |
+
typeBackspace();
|
| 230 |
+
await sleep(getKeystrokeDelay() * 1.5);
|
| 231 |
+
recentMistake = true;
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
// Type adjacent key typo and correct it
|
| 235 |
+
async function simulateAdjacentKeyTypo(correctChar) {
|
| 236 |
+
const adjacentChar = getAdjacentKey(correctChar);
|
| 237 |
+
if (adjacentChar !== correctChar) {
|
| 238 |
+
typeChar(adjacentChar);
|
| 239 |
+
await sleep(getKeystrokeDelay() * 2.2);
|
| 240 |
+
typeBackspace();
|
| 241 |
+
await sleep(getKeystrokeDelay() * 1.3);
|
| 242 |
+
recentMistake = true;
|
| 243 |
+
}
|
| 244 |
+
}
|
| 245 |
+
|
| 246 |
+
// Double or triple letter mistake
|
| 247 |
+
async function simulateDoubleLetter(char, count = 2) {
|
| 248 |
+
// Type the correct char first, then extra(s)
|
| 249 |
+
for (let i = 1; i < count; i++) {
|
| 250 |
+
typeChar(char);
|
| 251 |
+
await sleep(getKeystrokeDelay() * 0.3); // Very fast double tap
|
| 252 |
+
}
|
| 253 |
+
// Pause to realize mistake
|
| 254 |
+
await sleep(getKeystrokeDelay() * 2.0);
|
| 255 |
+
// Delete the extras
|
| 256 |
+
for (let i = 1; i < count; i++) {
|
| 257 |
+
typeBackspace();
|
| 258 |
+
await sleep(getKeystrokeDelay() * 0.5);
|
| 259 |
+
}
|
| 260 |
+
await sleep(getKeystrokeDelay() * 1.2);
|
| 261 |
+
recentMistake = true;
|
| 262 |
+
}
|
| 263 |
+
|
| 264 |
+
// Skip a letter (will be detected as wrong, then backspace and fix)
|
| 265 |
+
async function simulateSkipLetter() {
|
| 266 |
+
// The letter gets skipped - we don't type it
|
| 267 |
+
// The next letter will be typed in its place
|
| 268 |
+
// This creates a natural error that gets corrected
|
| 269 |
+
return true; // Signal that we should skip
|
| 270 |
+
}
|
| 271 |
+
|
| 272 |
+
// Transpose two letters (type in wrong order, then fix)
|
| 273 |
+
async function simulateTranspose(char1, char2) {
|
| 274 |
+
// Type second char first
|
| 275 |
+
typeChar(char2);
|
| 276 |
+
await sleep(getKeystrokeDelay() * 0.4);
|
| 277 |
+
// Type first char second
|
| 278 |
+
typeChar(char1);
|
| 279 |
+
await sleep(getKeystrokeDelay() * 2.5);
|
| 280 |
+
// Delete both
|
| 281 |
+
typeBackspace();
|
| 282 |
+
await sleep(getKeystrokeDelay() * 0.4);
|
| 283 |
+
typeBackspace();
|
| 284 |
+
await sleep(getKeystrokeDelay() * 1.5);
|
| 285 |
+
recentMistake = true;
|
| 286 |
+
// Return true so main loop knows we handled these chars
|
| 287 |
+
return true;
|
| 288 |
+
}
|
| 289 |
+
|
| 290 |
+
// Use Ctrl+Backspace to clear word and retype
|
| 291 |
+
async function simulateCtrlBackspace() {
|
| 292 |
+
const incorrectCount = getIncorrectCount();
|
| 293 |
+
if (incorrectCount > 2) {
|
| 294 |
+
await sleep(getKeystrokeDelay() * 3); // Frustration pause
|
| 295 |
+
typeCtrlBackspace();
|
| 296 |
+
await sleep(getKeystrokeDelay() * 2);
|
| 297 |
+
recentMistake = true;
|
| 298 |
+
return true;
|
| 299 |
+
}
|
| 300 |
+
return false;
|
| 301 |
+
}
|
| 302 |
+
|
| 303 |
+
// Main typing loop with all human imperfections
|
| 304 |
+
async function autoTypeLoop() {
|
| 305 |
+
console.log("Starting human-like auto-type loop...");
|
| 306 |
+
console.log("Active imperfections: wrong char, adjacent key, double/triple letter, skip, transpose, Ctrl+Backspace, hesitation, burst typing, fatigue");
|
| 307 |
+
|
| 308 |
+
let wordCount = 0;
|
| 309 |
+
let skipNext = false;
|
| 310 |
+
|
| 311 |
+
while (true) {
|
| 312 |
+
const currentWordText = getCurrentWordText();
|
| 313 |
+
|
| 314 |
+
if (currentWordText === null) {
|
| 315 |
+
console.log(`Auto-type complete! Typed ${wordCount} words, ${totalCharsTyped} characters.`);
|
| 316 |
+
break;
|
| 317 |
+
}
|
| 318 |
+
|
| 319 |
+
// Check if we should use Ctrl+Backspace (when frustrated with errors)
|
| 320 |
+
if (Math.random() < CONFIG.ctrlBackspaceRate) {
|
| 321 |
+
const didCtrlBackspace = await simulateCtrlBackspace();
|
| 322 |
+
if (didCtrlBackspace) continue;
|
| 323 |
+
}
|
| 324 |
+
|
| 325 |
+
if (currentWordText.length === 0) {
|
| 326 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 327 |
+
const nextWord = activeWord ? activeWord.nextElementSibling : null;
|
| 328 |
+
|
| 329 |
+
if (!nextWord || !nextWord.classList.contains('word')) {
|
| 330 |
+
await sleep(50);
|
| 331 |
+
const stillActive = document.querySelector('#words .word.active');
|
| 332 |
+
if (!stillActive) {
|
| 333 |
+
console.log(`Auto-type complete! Typed ${wordCount} words.`);
|
| 334 |
+
break;
|
| 335 |
+
}
|
| 336 |
+
continue;
|
| 337 |
+
}
|
| 338 |
+
|
| 339 |
+
typeChar(' ');
|
| 340 |
+
wordCount++;
|
| 341 |
+
|
| 342 |
+
// Longer pause between words
|
| 343 |
+
let delay = getKeystrokeDelay() * 1.4;
|
| 344 |
+
await sleep(delay);
|
| 345 |
+
continue;
|
| 346 |
+
}
|
| 347 |
+
|
| 348 |
+
const char = currentWordText[0];
|
| 349 |
+
const nextChar = currentWordText.length > 1 ? currentWordText[1] : null;
|
| 350 |
+
let delay = getKeystrokeDelay();
|
| 351 |
+
|
| 352 |
+
// === APPLY HUMAN IMPERFECTIONS ===
|
| 353 |
+
|
| 354 |
+
// Slow start to words
|
| 355 |
+
if (isWordStart()) {
|
| 356 |
+
delay *= CONFIG.wordStartSlowdown;
|
| 357 |
+
}
|
| 358 |
+
|
| 359 |
+
// Random hesitation (thinking pause)
|
| 360 |
+
if (Math.random() < CONFIG.hesitationRate) {
|
| 361 |
+
delay *= CONFIG.hesitationMultiplier;
|
| 362 |
+
}
|
| 363 |
+
|
| 364 |
+
// Post-mistake recovery pause
|
| 365 |
+
if (recentMistake) {
|
| 366 |
+
delay *= CONFIG.postMistakePauseMultiplier;
|
| 367 |
+
recentMistake = false;
|
| 368 |
+
}
|
| 369 |
+
|
| 370 |
+
// Trigger burst mode randomly
|
| 371 |
+
if (!inBurstMode && Math.random() < CONFIG.burstTypingRate) {
|
| 372 |
+
inBurstMode = true;
|
| 373 |
+
burstCharsRemaining = CONFIG.burstLength;
|
| 374 |
+
}
|
| 375 |
+
|
| 376 |
+
// Skip letter imperfection (handled by typing next char instead, creating error)
|
| 377 |
+
if (/[a-zA-Z]/.test(char) && Math.random() < CONFIG.skipLetterRate && nextChar) {
|
| 378 |
+
// Skip this char - type next char instead (creates transposition-like error)
|
| 379 |
+
typeChar(nextChar);
|
| 380 |
+
await sleep(getKeystrokeDelay() * 2.5);
|
| 381 |
+
typeBackspace();
|
| 382 |
+
await sleep(getKeystrokeDelay() * 1.3);
|
| 383 |
+
recentMistake = true;
|
| 384 |
+
// Now type correct char
|
| 385 |
+
typeChar(char);
|
| 386 |
+
await sleep(delay);
|
| 387 |
+
continue;
|
| 388 |
+
}
|
| 389 |
+
|
| 390 |
+
// Transpose letters
|
| 391 |
+
if (/[a-zA-Z]/.test(char) && nextChar && /[a-zA-Z]/.test(nextChar) && Math.random() < CONFIG.transposeRate) {
|
| 392 |
+
await simulateTranspose(char, nextChar);
|
| 393 |
+
// Type both chars correctly now
|
| 394 |
+
typeChar(char);
|
| 395 |
+
await sleep(getKeystrokeDelay());
|
| 396 |
+
typeChar(nextChar);
|
| 397 |
+
await sleep(delay);
|
| 398 |
+
// Skip the next character in main loop since we already typed it
|
| 399 |
+
skipNext = true;
|
| 400 |
+
continue;
|
| 401 |
+
}
|
| 402 |
+
|
| 403 |
+
// Triple letter (rarer)
|
| 404 |
+
if (/[a-zA-Z]/.test(char) && Math.random() < CONFIG.tripleLetterRate) {
|
| 405 |
+
typeChar(char); // Type the correct one first
|
| 406 |
+
await simulateDoubleLetter(char, 3);
|
| 407 |
+
await sleep(delay);
|
| 408 |
+
continue;
|
| 409 |
+
}
|
| 410 |
+
|
| 411 |
+
// Double letter
|
| 412 |
+
if (/[a-zA-Z]/.test(char) && Math.random() < CONFIG.doubleLetterRate) {
|
| 413 |
+
typeChar(char); // Type the correct one first
|
| 414 |
+
await simulateDoubleLetter(char, 2);
|
| 415 |
+
await sleep(delay);
|
| 416 |
+
continue;
|
| 417 |
+
}
|
| 418 |
+
|
| 419 |
+
// Adjacent key typo
|
| 420 |
+
if (/[a-zA-Z]/.test(char) && Math.random() < CONFIG.adjacentKeyRate) {
|
| 421 |
+
await simulateAdjacentKeyTypo(char);
|
| 422 |
+
}
|
| 423 |
+
|
| 424 |
+
// Wrong character
|
| 425 |
+
if (/[a-zA-Z]/.test(char) && Math.random() < CONFIG.wrongCharRate) {
|
| 426 |
+
await simulateWrongChar(char);
|
| 427 |
+
}
|
| 428 |
+
|
| 429 |
+
// Type the correct character
|
| 430 |
+
typeChar(char);
|
| 431 |
+
await sleep(delay);
|
| 432 |
+
}
|
| 433 |
+
}
|
| 434 |
+
|
| 435 |
+
const triggerHandler = (e) => {
|
| 436 |
+
if (!isArmed) return;
|
| 437 |
+
|
| 438 |
+
if (e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey) {
|
| 439 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 440 |
+
if (!activeWord) return;
|
| 441 |
+
|
| 442 |
+
const firstLetterElement = activeWord.querySelector('letter');
|
| 443 |
+
const firstLetter = firstLetterElement ? firstLetterElement.textContent : null;
|
| 444 |
+
|
| 445 |
+
if (firstLetter && e.key === firstLetter) {
|
| 446 |
+
isArmed = false;
|
| 447 |
+
window.removeEventListener('keydown', triggerHandler);
|
| 448 |
+
|
| 449 |
+
console.log("Trigger detected. Starting Human-Like Command Typer...");
|
| 450 |
+
console.log("Config:", CONFIG);
|
| 451 |
+
setTimeout(() => {
|
| 452 |
+
autoTypeLoop();
|
| 453 |
+
}, CONFIG.startDelay);
|
| 454 |
+
}
|
| 455 |
+
}
|
| 456 |
+
};
|
| 457 |
+
|
| 458 |
+
window.addEventListener('keydown', triggerHandler);
|
| 459 |
+
console.log("READY! Type the first letter to activate Human-Like Mode.");
|
| 460 |
+
console.log("Imperfections enabled: wrong char, adjacent key typo, double/triple letter, skip, transpose, Ctrl+Backspace, hesitation, burst typing, fatigue, word-start slowdown");
|
| 461 |
+
})();
|
2nd_version/README_v2.md
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# MnkLightning
|
| 2 |
+
|
| 3 |
+
[](https://opensource.org/licenses/MIT)
|
| 4 |
+
[](https://developer.mozilla.org/en-US/docs/Web/JavaScript)
|
| 5 |
+
[](#)
|
| 6 |
+
[](https://monkeytype.com/)
|
| 7 |
+
|
| 8 |
+
MonkeyLightning is a performance-oriented automation script designed for Monkeytype. It implements sophisticated human-like typing behavior with extensive imperfection modeling to provide a natural, undetectable typing flow.
|
| 9 |
+
|
| 10 |
+
<img width="1358" height="648" alt="Interface Preview" src="https://github.com/user-attachments/assets/f42ba747-a9ca-4f2b-9244-cf60153eda99" />
|
| 11 |
+
|
| 12 |
+
## Demonstration
|
| 13 |
+
|
| 14 |
+
The following recording demonstrates the script in action, illustrating the variable typing speed and human-like errors.
|
| 15 |
+
|
| 16 |
+
https://github.com/user-attachments/assets/ec3fa997-6859-400e-8672-d164c526ba7a
|
| 17 |
+
|
| 18 |
+
## Technical Overview
|
| 19 |
+
|
| 20 |
+
This repository contains `script_candidate.js`, featuring:
|
| 21 |
+
- **Dynamic word fetching** - Continuously reads from DOM, works beyond 100 words
|
| 22 |
+
- **Human-like latency modeling** with randomized inter-keystroke intervals
|
| 23 |
+
- **12+ imperfection types** to emulate natural typing behavior
|
| 24 |
+
- **QWERTY keyboard adjacency map** for realistic typos
|
| 25 |
+
- **Fatigue simulation** that gradually slows typing over time
|
| 26 |
+
|
| 27 |
+
## Human-Like Imperfections
|
| 28 |
+
|
| 29 |
+
| Behavior | Default Rate | Description |
|
| 30 |
+
|----------|--------------|-------------|
|
| 31 |
+
| **Wrong Character** | 2.5% | Types a random letter instead of correct one |
|
| 32 |
+
| **Adjacent Key Typo** | 2% | Hits a nearby key on QWERTY keyboard (e.g., 'd' → 's') |
|
| 33 |
+
| **Double Letter** | 1.5% | Accidentally presses a key twice |
|
| 34 |
+
| **Triple Letter** | 0.3% | Accidentally presses a key three times |
|
| 35 |
+
| **Skip Letter** | 1% | Finger moves too fast, misses a key |
|
| 36 |
+
| **Transposed Letters** | 1.2% | Swaps two adjacent letters (e.g., "teh" → "the") |
|
| 37 |
+
| **Ctrl+Backspace** | 0.8% | Deletes whole word when frustrated with errors |
|
| 38 |
+
| **Hesitation Pause** | 4% | Random thinking pause (3.5x longer delay) |
|
| 39 |
+
| **Burst Typing** | 8% | Fast typing burst for 5 characters |
|
| 40 |
+
| **Word Start Slowdown** | Always | First letter of each word typed 1.8x slower |
|
| 41 |
+
| **Fatigue** | Gradual | Typing slowly gets slower over time |
|
| 42 |
+
| **Post-Mistake Pause** | After errors | 2x longer delay after making a mistake |
|
| 43 |
+
|
| 44 |
+
## Usage Instructions
|
| 45 |
+
|
| 46 |
+
1. Navigate to [Monkeytype](https://monkeytype.com/).
|
| 47 |
+
2. Open the browser's developer console (`F12` or `Ctrl+Shift+J`).
|
| 48 |
+
3. Copy the contents of [script_candidate.js](./script_candidate.js) and paste into the console.
|
| 49 |
+
4. Press Enter to execute.
|
| 50 |
+
5. Start a typing test — the automation triggers when you type the first character.
|
| 51 |
+
|
| 52 |
+
## Configuration
|
| 53 |
+
|
| 54 |
+
Customize the bot by modifying the `CONFIG` object in `script_candidate.js`:
|
| 55 |
+
|
| 56 |
+
```javascript
|
| 57 |
+
const CONFIG = {
|
| 58 |
+
minWPM: 310, // Minimum expected WPM
|
| 59 |
+
maxWPM: 550, // Maximum expected WPM
|
| 60 |
+
startDelay: 50, // Delay before starting to type
|
| 61 |
+
|
| 62 |
+
// === HUMAN IMPERFECTION RATES ===
|
| 63 |
+
wrongCharRate: 0.025, // Random wrong character
|
| 64 |
+
adjacentKeyRate: 0.02, // Nearby key on keyboard
|
| 65 |
+
doubleLetterRate: 0.015, // Double key press
|
| 66 |
+
tripleLetterRate: 0.003, // Triple key press
|
| 67 |
+
skipLetterRate: 0.01, // Missed key
|
| 68 |
+
transposeRate: 0.012, // Swapped adjacent letters
|
| 69 |
+
ctrlBackspaceRate: 0.008, // Delete whole word
|
| 70 |
+
hesitationRate: 0.04, // Random pause
|
| 71 |
+
hesitationMultiplier: 3.5,
|
| 72 |
+
burstTypingRate: 0.08, // Fast burst mode
|
| 73 |
+
burstSpeedMultiplier: 0.5,
|
| 74 |
+
burstLength: 5,
|
| 75 |
+
wordStartSlowdown: 1.8, // Slower first letter
|
| 76 |
+
fatigueEnabled: true,
|
| 77 |
+
fatigueRate: 0.0001,
|
| 78 |
+
postMistakePauseMultiplier: 2.0,
|
| 79 |
+
};
|
| 80 |
+
```
|
| 81 |
+
|
| 82 |
+
Set any rate to `0` to disable that imperfection type.
|
| 83 |
+
|
| 84 |
+
## Disclaimer
|
| 85 |
+
|
| 86 |
+
This software is provided for educational and research purposes only. The authors do not encourage or condone the use of automation scripts on competitive platforms. Use at your own risk.
|
| 87 |
+
|
| 88 |
+
## Citation
|
| 89 |
+
|
| 90 |
+
```bibtex
|
| 91 |
+
@software{MnkLightning2026,
|
| 92 |
+
author = {algorembrant},
|
| 93 |
+
title = {MnkLightning: Human-Like Typing Automation for Monkeytype},
|
| 94 |
+
year = {2026},
|
| 95 |
+
publisher = {GitHub},
|
| 96 |
+
journal = {GitHub Repository},
|
| 97 |
+
howpublished = {\url{https://github.com/algorembrant/MnkLightning}}
|
| 98 |
+
}
|
| 99 |
+
```
|
2nd_version/script_candidate.js
ADDED
|
@@ -0,0 +1,461 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
(function () {
|
| 2 |
+
console.log("%c Monkeytype Command Typer (Human-Like) ", "background: #222; color: #ff0000; font-size: 20px");
|
| 3 |
+
|
| 4 |
+
const CONFIG = {
|
| 5 |
+
minWPM: 310, // Minimum expected WPM
|
| 6 |
+
maxWPM: 550, // Maximum expected WPM
|
| 7 |
+
startDelay: 50, // Delay before starting to type
|
| 8 |
+
|
| 9 |
+
// === HUMAN IMPERFECTION RATES ===
|
| 10 |
+
// Wrong character (random letter instead of correct one)
|
| 11 |
+
wrongCharRate: 0.025,
|
| 12 |
+
|
| 13 |
+
// Adjacent key typo (hit a nearby key on keyboard)
|
| 14 |
+
adjacentKeyRate: 0.02,
|
| 15 |
+
|
| 16 |
+
// Double/triple letter (accidentally press key multiple times)
|
| 17 |
+
doubleLetterRate: 0.015,
|
| 18 |
+
tripleLetterRate: 0.003,
|
| 19 |
+
|
| 20 |
+
// Skip letter (finger moved too fast, missed a key)
|
| 21 |
+
skipLetterRate: 0.01,
|
| 22 |
+
|
| 23 |
+
// Transposed letters (swap two adjacent letters like "teh" instead of "the")
|
| 24 |
+
transposeRate: 0.012,
|
| 25 |
+
|
| 26 |
+
// Ctrl+Backspace (delete whole word when frustrated)
|
| 27 |
+
ctrlBackspaceRate: 0.008,
|
| 28 |
+
|
| 29 |
+
// Hesitation/thinking pause (longer pause before difficult letters)
|
| 30 |
+
hesitationRate: 0.04,
|
| 31 |
+
hesitationMultiplier: 3.5, // How much longer the pause is
|
| 32 |
+
|
| 33 |
+
// Burst typing (fast typing followed by slowdown)
|
| 34 |
+
burstTypingRate: 0.08,
|
| 35 |
+
burstSpeedMultiplier: 0.5, // Faster during burst
|
| 36 |
+
burstLength: 5, // Characters in burst
|
| 37 |
+
|
| 38 |
+
// Slow start to words (first letter of word typed slower)
|
| 39 |
+
wordStartSlowdown: 1.8,
|
| 40 |
+
|
| 41 |
+
// Fatigue simulation (gradually slow down over time)
|
| 42 |
+
fatigueEnabled: true,
|
| 43 |
+
fatigueRate: 0.0001, // How much to slow down per character
|
| 44 |
+
|
| 45 |
+
// Recovery pause after mistakes (humans pause after making errors)
|
| 46 |
+
postMistakePauseMultiplier: 2.0,
|
| 47 |
+
};
|
| 48 |
+
|
| 49 |
+
// QWERTY keyboard adjacency map for realistic typos
|
| 50 |
+
const ADJACENT_KEYS = {
|
| 51 |
+
'a': ['q', 'w', 's', 'z'],
|
| 52 |
+
'b': ['v', 'g', 'h', 'n'],
|
| 53 |
+
'c': ['x', 'd', 'f', 'v'],
|
| 54 |
+
'd': ['s', 'e', 'r', 'f', 'c', 'x'],
|
| 55 |
+
'e': ['w', 's', 'd', 'r'],
|
| 56 |
+
'f': ['d', 'r', 't', 'g', 'v', 'c'],
|
| 57 |
+
'g': ['f', 't', 'y', 'h', 'b', 'v'],
|
| 58 |
+
'h': ['g', 'y', 'u', 'j', 'n', 'b'],
|
| 59 |
+
'i': ['u', 'j', 'k', 'o'],
|
| 60 |
+
'j': ['h', 'u', 'i', 'k', 'm', 'n'],
|
| 61 |
+
'k': ['j', 'i', 'o', 'l', 'm'],
|
| 62 |
+
'l': ['k', 'o', 'p'],
|
| 63 |
+
'm': ['n', 'j', 'k'],
|
| 64 |
+
'n': ['b', 'h', 'j', 'm'],
|
| 65 |
+
'o': ['i', 'k', 'l', 'p'],
|
| 66 |
+
'p': ['o', 'l'],
|
| 67 |
+
'q': ['w', 'a'],
|
| 68 |
+
'r': ['e', 'd', 'f', 't'],
|
| 69 |
+
's': ['a', 'w', 'e', 'd', 'x', 'z'],
|
| 70 |
+
't': ['r', 'f', 'g', 'y'],
|
| 71 |
+
'u': ['y', 'h', 'j', 'i'],
|
| 72 |
+
'v': ['c', 'f', 'g', 'b'],
|
| 73 |
+
'w': ['q', 'a', 's', 'e'],
|
| 74 |
+
'x': ['z', 's', 'd', 'c'],
|
| 75 |
+
'y': ['t', 'g', 'h', 'u'],
|
| 76 |
+
'z': ['a', 's', 'x'],
|
| 77 |
+
};
|
| 78 |
+
|
| 79 |
+
let isArmed = true;
|
| 80 |
+
let inBurstMode = false;
|
| 81 |
+
let burstCharsRemaining = 0;
|
| 82 |
+
let totalCharsTyped = 0;
|
| 83 |
+
let recentMistake = false;
|
| 84 |
+
|
| 85 |
+
// Type a single character
|
| 86 |
+
function typeChar(char) {
|
| 87 |
+
const target = document.activeElement || document.body;
|
| 88 |
+
const keyConfig = {
|
| 89 |
+
key: char,
|
| 90 |
+
code: char === ' ' ? 'Space' : `Key${char.toUpperCase()}`,
|
| 91 |
+
bubbles: true,
|
| 92 |
+
cancelable: true,
|
| 93 |
+
view: window
|
| 94 |
+
};
|
| 95 |
+
|
| 96 |
+
target.dispatchEvent(new KeyboardEvent('keydown', keyConfig));
|
| 97 |
+
target.dispatchEvent(new KeyboardEvent('keypress', keyConfig));
|
| 98 |
+
document.execCommand('insertText', false, char);
|
| 99 |
+
target.dispatchEvent(new KeyboardEvent('keyup', keyConfig));
|
| 100 |
+
|
| 101 |
+
totalCharsTyped++;
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
// Single backspace
|
| 105 |
+
function typeBackspace() {
|
| 106 |
+
const target = document.activeElement || document.body;
|
| 107 |
+
const bsConfig = { key: 'Backspace', code: 'Backspace', bubbles: true, cancelable: true, view: window };
|
| 108 |
+
target.dispatchEvent(new KeyboardEvent('keydown', bsConfig));
|
| 109 |
+
document.execCommand('delete', false, null);
|
| 110 |
+
target.dispatchEvent(new KeyboardEvent('keyup', bsConfig));
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
// Ctrl+Backspace to delete whole word
|
| 114 |
+
function typeCtrlBackspace() {
|
| 115 |
+
const target = document.activeElement || document.body;
|
| 116 |
+
const ctrlBsConfig = {
|
| 117 |
+
key: 'Backspace',
|
| 118 |
+
code: 'Backspace',
|
| 119 |
+
ctrlKey: true,
|
| 120 |
+
bubbles: true,
|
| 121 |
+
cancelable: true,
|
| 122 |
+
view: window
|
| 123 |
+
};
|
| 124 |
+
|
| 125 |
+
target.dispatchEvent(new KeyboardEvent('keydown', ctrlBsConfig));
|
| 126 |
+
|
| 127 |
+
// Delete characters until we hit a space or beginning
|
| 128 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 129 |
+
if (activeWord) {
|
| 130 |
+
const incorrectLetters = activeWord.querySelectorAll('letter.incorrect, letter.extra');
|
| 131 |
+
incorrectLetters.forEach(() => {
|
| 132 |
+
document.execCommand('delete', false, null);
|
| 133 |
+
});
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
target.dispatchEvent(new KeyboardEvent('keyup', ctrlBsConfig));
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
function sleep(ms) {
|
| 140 |
+
return new Promise(resolve => setTimeout(resolve, ms));
|
| 141 |
+
}
|
| 142 |
+
|
| 143 |
+
// Get adjacent key for realistic typo
|
| 144 |
+
function getAdjacentKey(char) {
|
| 145 |
+
const lowerChar = char.toLowerCase();
|
| 146 |
+
const adjacent = ADJACENT_KEYS[lowerChar];
|
| 147 |
+
if (adjacent && adjacent.length > 0) {
|
| 148 |
+
const randomAdj = adjacent[Math.floor(Math.random() * adjacent.length)];
|
| 149 |
+
return char === char.toUpperCase() ? randomAdj.toUpperCase() : randomAdj;
|
| 150 |
+
}
|
| 151 |
+
return char; // Fallback to same char if no adjacent found
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
// Get random wrong character
|
| 155 |
+
function getRandomChar() {
|
| 156 |
+
const chars = "abcdefghijklmnopqrstuvwxyz";
|
| 157 |
+
return chars.charAt(Math.floor(Math.random() * chars.length));
|
| 158 |
+
}
|
| 159 |
+
|
| 160 |
+
// Calculate keystroke delay with fatigue and burst mode
|
| 161 |
+
function getKeystrokeDelay() {
|
| 162 |
+
const currentWPM = Math.floor(Math.random() * (CONFIG.maxWPM - CONFIG.minWPM + 1)) + CONFIG.minWPM;
|
| 163 |
+
let baseDelay = 60000 / (currentWPM * 5);
|
| 164 |
+
|
| 165 |
+
// Apply fatigue (gradually slow down)
|
| 166 |
+
if (CONFIG.fatigueEnabled) {
|
| 167 |
+
baseDelay *= (1 + totalCharsTyped * CONFIG.fatigueRate);
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
// Apply burst mode (faster typing)
|
| 171 |
+
if (inBurstMode && burstCharsRemaining > 0) {
|
| 172 |
+
baseDelay *= CONFIG.burstSpeedMultiplier;
|
| 173 |
+
burstCharsRemaining--;
|
| 174 |
+
if (burstCharsRemaining === 0) {
|
| 175 |
+
inBurstMode = false;
|
| 176 |
+
}
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
// Add variance
|
| 180 |
+
const variance = baseDelay * 0.25;
|
| 181 |
+
const noise = (Math.random() * variance * 2) - variance;
|
| 182 |
+
|
| 183 |
+
return Math.max(8, baseDelay + noise);
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
// Get current word's remaining untyped text
|
| 187 |
+
function getCurrentWordText() {
|
| 188 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 189 |
+
if (!activeWord) return null;
|
| 190 |
+
|
| 191 |
+
const letters = activeWord.querySelectorAll('letter');
|
| 192 |
+
let text = "";
|
| 193 |
+
let foundUntyped = false;
|
| 194 |
+
|
| 195 |
+
for (const letter of letters) {
|
| 196 |
+
if (!letter.classList.contains('correct') && !letter.classList.contains('incorrect')) {
|
| 197 |
+
foundUntyped = true;
|
| 198 |
+
}
|
| 199 |
+
if (foundUntyped) {
|
| 200 |
+
text += letter.textContent;
|
| 201 |
+
}
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
return text;
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
// Count how many incorrect letters we've typed in current word
|
| 208 |
+
function getIncorrectCount() {
|
| 209 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 210 |
+
if (!activeWord) return 0;
|
| 211 |
+
return activeWord.querySelectorAll('letter.incorrect, letter.extra').length;
|
| 212 |
+
}
|
| 213 |
+
|
| 214 |
+
// Check if we're at the start of a word
|
| 215 |
+
function isWordStart() {
|
| 216 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 217 |
+
if (!activeWord) return false;
|
| 218 |
+
const typed = activeWord.querySelectorAll('letter.correct, letter.incorrect');
|
| 219 |
+
return typed.length === 0;
|
| 220 |
+
}
|
| 221 |
+
|
| 222 |
+
// === MISTAKE SIMULATION FUNCTIONS ===
|
| 223 |
+
|
| 224 |
+
// Type wrong character and correct it
|
| 225 |
+
async function simulateWrongChar(correctChar) {
|
| 226 |
+
const wrongChar = getRandomChar();
|
| 227 |
+
typeChar(wrongChar);
|
| 228 |
+
await sleep(getKeystrokeDelay() * 2.5);
|
| 229 |
+
typeBackspace();
|
| 230 |
+
await sleep(getKeystrokeDelay() * 1.5);
|
| 231 |
+
recentMistake = true;
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
// Type adjacent key typo and correct it
|
| 235 |
+
async function simulateAdjacentKeyTypo(correctChar) {
|
| 236 |
+
const adjacentChar = getAdjacentKey(correctChar);
|
| 237 |
+
if (adjacentChar !== correctChar) {
|
| 238 |
+
typeChar(adjacentChar);
|
| 239 |
+
await sleep(getKeystrokeDelay() * 2.2);
|
| 240 |
+
typeBackspace();
|
| 241 |
+
await sleep(getKeystrokeDelay() * 1.3);
|
| 242 |
+
recentMistake = true;
|
| 243 |
+
}
|
| 244 |
+
}
|
| 245 |
+
|
| 246 |
+
// Double or triple letter mistake
|
| 247 |
+
async function simulateDoubleLetter(char, count = 2) {
|
| 248 |
+
// Type the correct char first, then extra(s)
|
| 249 |
+
for (let i = 1; i < count; i++) {
|
| 250 |
+
typeChar(char);
|
| 251 |
+
await sleep(getKeystrokeDelay() * 0.3); // Very fast double tap
|
| 252 |
+
}
|
| 253 |
+
// Pause to realize mistake
|
| 254 |
+
await sleep(getKeystrokeDelay() * 2.0);
|
| 255 |
+
// Delete the extras
|
| 256 |
+
for (let i = 1; i < count; i++) {
|
| 257 |
+
typeBackspace();
|
| 258 |
+
await sleep(getKeystrokeDelay() * 0.5);
|
| 259 |
+
}
|
| 260 |
+
await sleep(getKeystrokeDelay() * 1.2);
|
| 261 |
+
recentMistake = true;
|
| 262 |
+
}
|
| 263 |
+
|
| 264 |
+
// Skip a letter (will be detected as wrong, then backspace and fix)
|
| 265 |
+
async function simulateSkipLetter() {
|
| 266 |
+
// The letter gets skipped - we don't type it
|
| 267 |
+
// The next letter will be typed in its place
|
| 268 |
+
// This creates a natural error that gets corrected
|
| 269 |
+
return true; // Signal that we should skip
|
| 270 |
+
}
|
| 271 |
+
|
| 272 |
+
// Transpose two letters (type in wrong order, then fix)
|
| 273 |
+
async function simulateTranspose(char1, char2) {
|
| 274 |
+
// Type second char first
|
| 275 |
+
typeChar(char2);
|
| 276 |
+
await sleep(getKeystrokeDelay() * 0.4);
|
| 277 |
+
// Type first char second
|
| 278 |
+
typeChar(char1);
|
| 279 |
+
await sleep(getKeystrokeDelay() * 2.5);
|
| 280 |
+
// Delete both
|
| 281 |
+
typeBackspace();
|
| 282 |
+
await sleep(getKeystrokeDelay() * 0.4);
|
| 283 |
+
typeBackspace();
|
| 284 |
+
await sleep(getKeystrokeDelay() * 1.5);
|
| 285 |
+
recentMistake = true;
|
| 286 |
+
// Return true so main loop knows we handled these chars
|
| 287 |
+
return true;
|
| 288 |
+
}
|
| 289 |
+
|
| 290 |
+
// Use Ctrl+Backspace to clear word and retype
|
| 291 |
+
async function simulateCtrlBackspace() {
|
| 292 |
+
const incorrectCount = getIncorrectCount();
|
| 293 |
+
if (incorrectCount > 2) {
|
| 294 |
+
await sleep(getKeystrokeDelay() * 3); // Frustration pause
|
| 295 |
+
typeCtrlBackspace();
|
| 296 |
+
await sleep(getKeystrokeDelay() * 2);
|
| 297 |
+
recentMistake = true;
|
| 298 |
+
return true;
|
| 299 |
+
}
|
| 300 |
+
return false;
|
| 301 |
+
}
|
| 302 |
+
|
| 303 |
+
// Main typing loop with all human imperfections
|
| 304 |
+
async function autoTypeLoop() {
|
| 305 |
+
console.log("Starting human-like auto-type loop...");
|
| 306 |
+
console.log("Active imperfections: wrong char, adjacent key, double/triple letter, skip, transpose, Ctrl+Backspace, hesitation, burst typing, fatigue");
|
| 307 |
+
|
| 308 |
+
let wordCount = 0;
|
| 309 |
+
let skipNext = false;
|
| 310 |
+
|
| 311 |
+
while (true) {
|
| 312 |
+
const currentWordText = getCurrentWordText();
|
| 313 |
+
|
| 314 |
+
if (currentWordText === null) {
|
| 315 |
+
console.log(`Auto-type complete! Typed ${wordCount} words, ${totalCharsTyped} characters.`);
|
| 316 |
+
break;
|
| 317 |
+
}
|
| 318 |
+
|
| 319 |
+
// Check if we should use Ctrl+Backspace (when frustrated with errors)
|
| 320 |
+
if (Math.random() < CONFIG.ctrlBackspaceRate) {
|
| 321 |
+
const didCtrlBackspace = await simulateCtrlBackspace();
|
| 322 |
+
if (didCtrlBackspace) continue;
|
| 323 |
+
}
|
| 324 |
+
|
| 325 |
+
if (currentWordText.length === 0) {
|
| 326 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 327 |
+
const nextWord = activeWord ? activeWord.nextElementSibling : null;
|
| 328 |
+
|
| 329 |
+
if (!nextWord || !nextWord.classList.contains('word')) {
|
| 330 |
+
await sleep(50);
|
| 331 |
+
const stillActive = document.querySelector('#words .word.active');
|
| 332 |
+
if (!stillActive) {
|
| 333 |
+
console.log(`Auto-type complete! Typed ${wordCount} words.`);
|
| 334 |
+
break;
|
| 335 |
+
}
|
| 336 |
+
continue;
|
| 337 |
+
}
|
| 338 |
+
|
| 339 |
+
typeChar(' ');
|
| 340 |
+
wordCount++;
|
| 341 |
+
|
| 342 |
+
// Longer pause between words
|
| 343 |
+
let delay = getKeystrokeDelay() * 1.4;
|
| 344 |
+
await sleep(delay);
|
| 345 |
+
continue;
|
| 346 |
+
}
|
| 347 |
+
|
| 348 |
+
const char = currentWordText[0];
|
| 349 |
+
const nextChar = currentWordText.length > 1 ? currentWordText[1] : null;
|
| 350 |
+
let delay = getKeystrokeDelay();
|
| 351 |
+
|
| 352 |
+
// === APPLY HUMAN IMPERFECTIONS ===
|
| 353 |
+
|
| 354 |
+
// Slow start to words
|
| 355 |
+
if (isWordStart()) {
|
| 356 |
+
delay *= CONFIG.wordStartSlowdown;
|
| 357 |
+
}
|
| 358 |
+
|
| 359 |
+
// Random hesitation (thinking pause)
|
| 360 |
+
if (Math.random() < CONFIG.hesitationRate) {
|
| 361 |
+
delay *= CONFIG.hesitationMultiplier;
|
| 362 |
+
}
|
| 363 |
+
|
| 364 |
+
// Post-mistake recovery pause
|
| 365 |
+
if (recentMistake) {
|
| 366 |
+
delay *= CONFIG.postMistakePauseMultiplier;
|
| 367 |
+
recentMistake = false;
|
| 368 |
+
}
|
| 369 |
+
|
| 370 |
+
// Trigger burst mode randomly
|
| 371 |
+
if (!inBurstMode && Math.random() < CONFIG.burstTypingRate) {
|
| 372 |
+
inBurstMode = true;
|
| 373 |
+
burstCharsRemaining = CONFIG.burstLength;
|
| 374 |
+
}
|
| 375 |
+
|
| 376 |
+
// Skip letter imperfection (handled by typing next char instead, creating error)
|
| 377 |
+
if (/[a-zA-Z]/.test(char) && Math.random() < CONFIG.skipLetterRate && nextChar) {
|
| 378 |
+
// Skip this char - type next char instead (creates transposition-like error)
|
| 379 |
+
typeChar(nextChar);
|
| 380 |
+
await sleep(getKeystrokeDelay() * 2.5);
|
| 381 |
+
typeBackspace();
|
| 382 |
+
await sleep(getKeystrokeDelay() * 1.3);
|
| 383 |
+
recentMistake = true;
|
| 384 |
+
// Now type correct char
|
| 385 |
+
typeChar(char);
|
| 386 |
+
await sleep(delay);
|
| 387 |
+
continue;
|
| 388 |
+
}
|
| 389 |
+
|
| 390 |
+
// Transpose letters
|
| 391 |
+
if (/[a-zA-Z]/.test(char) && nextChar && /[a-zA-Z]/.test(nextChar) && Math.random() < CONFIG.transposeRate) {
|
| 392 |
+
await simulateTranspose(char, nextChar);
|
| 393 |
+
// Type both chars correctly now
|
| 394 |
+
typeChar(char);
|
| 395 |
+
await sleep(getKeystrokeDelay());
|
| 396 |
+
typeChar(nextChar);
|
| 397 |
+
await sleep(delay);
|
| 398 |
+
// Skip the next character in main loop since we already typed it
|
| 399 |
+
skipNext = true;
|
| 400 |
+
continue;
|
| 401 |
+
}
|
| 402 |
+
|
| 403 |
+
// Triple letter (rarer)
|
| 404 |
+
if (/[a-zA-Z]/.test(char) && Math.random() < CONFIG.tripleLetterRate) {
|
| 405 |
+
typeChar(char); // Type the correct one first
|
| 406 |
+
await simulateDoubleLetter(char, 3);
|
| 407 |
+
await sleep(delay);
|
| 408 |
+
continue;
|
| 409 |
+
}
|
| 410 |
+
|
| 411 |
+
// Double letter
|
| 412 |
+
if (/[a-zA-Z]/.test(char) && Math.random() < CONFIG.doubleLetterRate) {
|
| 413 |
+
typeChar(char); // Type the correct one first
|
| 414 |
+
await simulateDoubleLetter(char, 2);
|
| 415 |
+
await sleep(delay);
|
| 416 |
+
continue;
|
| 417 |
+
}
|
| 418 |
+
|
| 419 |
+
// Adjacent key typo
|
| 420 |
+
if (/[a-zA-Z]/.test(char) && Math.random() < CONFIG.adjacentKeyRate) {
|
| 421 |
+
await simulateAdjacentKeyTypo(char);
|
| 422 |
+
}
|
| 423 |
+
|
| 424 |
+
// Wrong character
|
| 425 |
+
if (/[a-zA-Z]/.test(char) && Math.random() < CONFIG.wrongCharRate) {
|
| 426 |
+
await simulateWrongChar(char);
|
| 427 |
+
}
|
| 428 |
+
|
| 429 |
+
// Type the correct character
|
| 430 |
+
typeChar(char);
|
| 431 |
+
await sleep(delay);
|
| 432 |
+
}
|
| 433 |
+
}
|
| 434 |
+
|
| 435 |
+
const triggerHandler = (e) => {
|
| 436 |
+
if (!isArmed) return;
|
| 437 |
+
|
| 438 |
+
if (e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey) {
|
| 439 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 440 |
+
if (!activeWord) return;
|
| 441 |
+
|
| 442 |
+
const firstLetterElement = activeWord.querySelector('letter');
|
| 443 |
+
const firstLetter = firstLetterElement ? firstLetterElement.textContent : null;
|
| 444 |
+
|
| 445 |
+
if (firstLetter && e.key === firstLetter) {
|
| 446 |
+
isArmed = false;
|
| 447 |
+
window.removeEventListener('keydown', triggerHandler);
|
| 448 |
+
|
| 449 |
+
console.log("Trigger detected. Starting Human-Like Command Typer...");
|
| 450 |
+
console.log("Config:", CONFIG);
|
| 451 |
+
setTimeout(() => {
|
| 452 |
+
autoTypeLoop();
|
| 453 |
+
}, CONFIG.startDelay);
|
| 454 |
+
}
|
| 455 |
+
}
|
| 456 |
+
};
|
| 457 |
+
|
| 458 |
+
window.addEventListener('keydown', triggerHandler);
|
| 459 |
+
console.log("READY! Type the first letter to activate Human-Like Mode.");
|
| 460 |
+
console.log("Imperfections enabled: wrong char, adjacent key typo, double/triple letter, skip, transpose, Ctrl+Backspace, hesitation, burst typing, fatigue, word-start slowdown");
|
| 461 |
+
})();
|
2nd_version/script_final.js
ADDED
|
@@ -0,0 +1,402 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
(function () {
|
| 2 |
+
console.log("%c Monkeytype Command Typer (Human-Like/Anti-Detect) v4 ", "background: #222; color: #00ff00; font-size: 20px");
|
| 3 |
+
|
| 4 |
+
// === CONFIGURATION ===
|
| 5 |
+
// Lowered WPM to realistic human levels to avoid server-side flagging.
|
| 6 |
+
const CONFIG = {
|
| 7 |
+
min_wpm: 120, // Reduced from 300
|
| 8 |
+
max_wpm: 160, // Reduced from 340
|
| 9 |
+
// Key Hold Time (Seconds)
|
| 10 |
+
min_key_hold: 0.02,
|
| 11 |
+
max_key_hold: 0.05,
|
| 12 |
+
|
| 13 |
+
// Imperfection Rates (0.0 to 1.0)
|
| 14 |
+
wrong_char_rate: 0.015, // Slightly higher for realism
|
| 15 |
+
adjacent_key_rate: 0.01,
|
| 16 |
+
double_letter_rate: 0.005,
|
| 17 |
+
skip_letter_rate: 0.002,
|
| 18 |
+
|
| 19 |
+
hesitation_rate: 0.05, // More frequent small hesitations
|
| 20 |
+
burst_rate: 0.1,
|
| 21 |
+
insane_burst_rate: 0.005,
|
| 22 |
+
|
| 23 |
+
// Timing Multipliers
|
| 24 |
+
hesitation_multiplier: 2.0,
|
| 25 |
+
burst_speed_multiplier: 0.7,
|
| 26 |
+
post_mistake_pause: 0.5, // Seconds
|
| 27 |
+
word_start_slowdown: 1.3,
|
| 28 |
+
};
|
| 29 |
+
|
| 30 |
+
// QWERTY Adjacency Map
|
| 31 |
+
const ADJACENT_KEYS = {
|
| 32 |
+
'a': ['q', 'w', 's', 'z'], 'b': ['v', 'g', 'h', 'n'], 'c': ['x', 'd', 'f', 'v'],
|
| 33 |
+
'd': ['s', 'e', 'r', 'f', 'c', 'x'], 'e': ['w', 's', 'd', 'r'], 'f': ['d', 'r', 't', 'g', 'v', 'c'],
|
| 34 |
+
'g': ['f', 't', 'y', 'h', 'b', 'v'], 'h': ['g', 'y', 'u', 'j', 'n', 'b'], 'i': ['u', 'j', 'k', 'o'],
|
| 35 |
+
'j': ['h', 'u', 'i', 'k', 'm', 'n'], 'k': ['j', 'i', 'o', 'l', 'm'], 'l': ['k', 'o', 'p'],
|
| 36 |
+
'm': ['n', 'j', 'k'], 'n': ['b', 'h', 'j', 'm'], 'o': ['i', 'k', 'l', 'p'], 'p': ['o', 'l'],
|
| 37 |
+
'q': ['w', 'a'], 'r': ['e', 'd', 'f', 't'], 's': ['a', 'w', 'e', 'd', 'x', 'z'],
|
| 38 |
+
't': ['r', 'f', 'g', 'y'], 'u': ['y', 'h', 'j', 'i'], 'v': ['c', 'f', 'g', 'b'],
|
| 39 |
+
'w': ['q', 'a', 's', 'e'], 'x': ['z', 's', 'd', 'c'], 'y': ['t', 'g', 'h', 'u'],
|
| 40 |
+
'z': ['a', 's', 'x'],
|
| 41 |
+
};
|
| 42 |
+
|
| 43 |
+
// Attempt to spoof isTrusted property (Best Effort, defensive)
|
| 44 |
+
try {
|
| 45 |
+
const originalDispatch = EventTarget.prototype.dispatchEvent;
|
| 46 |
+
// This might fail in strict environments or recent browsers, but worth a try
|
| 47 |
+
Object.defineProperty(KeyboardEvent.prototype, 'isTrusted', { get: () => true, configurable: true });
|
| 48 |
+
Object.defineProperty(InputEvent.prototype, 'isTrusted', { get: () => true, configurable: true });
|
| 49 |
+
Object.defineProperty(MouseEvent.prototype, 'isTrusted', { get: () => true, configurable: true });
|
| 50 |
+
} catch (e) {
|
| 51 |
+
// Silently fail if blocked
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
let isArmed = true;
|
| 55 |
+
let inBurstMode = false;
|
| 56 |
+
let inInsaneBurstMode = false;
|
| 57 |
+
let burstCharsRemaining = 0;
|
| 58 |
+
let totalCharsTyped = 0;
|
| 59 |
+
let recentMistake = false;
|
| 60 |
+
|
| 61 |
+
// Box-Muller transform for Gaussian distribution
|
| 62 |
+
function randomNormal(mean, stdev) {
|
| 63 |
+
let u = 0, v = 0;
|
| 64 |
+
while (u === 0) u = Math.random();
|
| 65 |
+
while (v === 0) v = Math.random();
|
| 66 |
+
let num = Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v);
|
| 67 |
+
num = num / 10.0 + 0.5; // Translate to 0 -> 1
|
| 68 |
+
if (num > 1 || num < 0) return gaussianRandom(mean, stdev); // resample between 0 and 1
|
| 69 |
+
// Simplified Logic:
|
| 70 |
+
return mean + (Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v)) * stdev;
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
function sleep(ms) {
|
| 74 |
+
return new Promise(resolve => setTimeout(resolve, ms));
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
const KEY_CODES = {
|
| 78 |
+
' ': 32, 'Enter': 13, 'Backspace': 8,
|
| 79 |
+
'a': 65, 'b': 66, 'c': 67, 'd': 68, 'e': 69, 'f': 70, 'g': 71, 'h': 72, 'i': 73, 'j': 74, 'k': 75, 'l': 76, 'm': 77,
|
| 80 |
+
'n': 78, 'o': 79, 'p': 80, 'q': 81, 'r': 82, 's': 83, 't': 84, 'u': 85, 'v': 86, 'w': 87, 'x': 88, 'y': 89, 'z': 90
|
| 81 |
+
};
|
| 82 |
+
|
| 83 |
+
function getKeyCode(char) {
|
| 84 |
+
const lower = char.toLowerCase();
|
| 85 |
+
return KEY_CODES[lower] || char.toUpperCase().charCodeAt(0);
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
// Type a single character with simulated events including legacy properties
|
| 89 |
+
async function typeChar(char) {
|
| 90 |
+
const target = document.activeElement || document.body;
|
| 91 |
+
const keyCode = getKeyCode(char);
|
| 92 |
+
const code = char === ' ' ? 'Space' : `Key${char.toUpperCase()}`;
|
| 93 |
+
|
| 94 |
+
const keyConfig = {
|
| 95 |
+
key: char,
|
| 96 |
+
code: code,
|
| 97 |
+
bubbles: true,
|
| 98 |
+
cancelable: true,
|
| 99 |
+
view: window,
|
| 100 |
+
which: keyCode,
|
| 101 |
+
keyCode: keyCode,
|
| 102 |
+
charCode: char.charCodeAt(0),
|
| 103 |
+
location: 0
|
| 104 |
+
};
|
| 105 |
+
|
| 106 |
+
// 1. Keydown
|
| 107 |
+
const keyDownEvent = new KeyboardEvent('keydown', keyConfig);
|
| 108 |
+
// Manually define legacy properties if constructor doesn't set them (browser dependent)
|
| 109 |
+
Object.defineProperty(keyDownEvent, 'keyCode', { get: () => keyCode });
|
| 110 |
+
Object.defineProperty(keyDownEvent, 'which', { get: () => keyCode });
|
| 111 |
+
target.dispatchEvent(keyDownEvent);
|
| 112 |
+
|
| 113 |
+
// 2. Keypress
|
| 114 |
+
const keyPressEvent = new KeyboardEvent('keypress', keyConfig);
|
| 115 |
+
Object.defineProperty(keyPressEvent, 'keyCode', { get: () => char.charCodeAt(0) }); // Keypress uses char code for printable
|
| 116 |
+
Object.defineProperty(keyPressEvent, 'which', { get: () => char.charCodeAt(0) });
|
| 117 |
+
target.dispatchEvent(keyPressEvent);
|
| 118 |
+
|
| 119 |
+
// 3. Input / execCommand or Text Insertion
|
| 120 |
+
// Using execCommand is sometimes safer if site blocks untrusted InputEvents
|
| 121 |
+
// But let's try dispatching InputEvent first as it's cleaner
|
| 122 |
+
const inputEvent = new InputEvent('input', {
|
| 123 |
+
data: char,
|
| 124 |
+
inputType: 'insertText',
|
| 125 |
+
isComposing: false,
|
| 126 |
+
bubbles: true,
|
| 127 |
+
cancelable: true,
|
| 128 |
+
view: window
|
| 129 |
+
});
|
| 130 |
+
target.dispatchEvent(inputEvent);
|
| 131 |
+
|
| 132 |
+
// Simulate key hold (Gaussian)
|
| 133 |
+
const meanHold = (CONFIG.min_key_hold + CONFIG.max_key_hold) / 2 * 1000;
|
| 134 |
+
const stdevHold = (CONFIG.max_key_hold - CONFIG.min_key_hold) * 1000 / 6;
|
| 135 |
+
const holdTime = Math.max(10, randomNormal(meanHold, stdevHold));
|
| 136 |
+
await sleep(holdTime);
|
| 137 |
+
|
| 138 |
+
// 4. Keyup
|
| 139 |
+
const keyUpEvent = new KeyboardEvent('keyup', keyConfig);
|
| 140 |
+
Object.defineProperty(keyUpEvent, 'keyCode', { get: () => keyCode });
|
| 141 |
+
Object.defineProperty(keyUpEvent, 'which', { get: () => keyCode });
|
| 142 |
+
target.dispatchEvent(keyUpEvent);
|
| 143 |
+
|
| 144 |
+
totalCharsTyped++;
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
async function typeBackspace() {
|
| 148 |
+
const target = document.activeElement || document.body;
|
| 149 |
+
const keyCode = 8;
|
| 150 |
+
const bsConfig = {
|
| 151 |
+
key: 'Backspace',
|
| 152 |
+
code: 'Backspace',
|
| 153 |
+
bubbles: true,
|
| 154 |
+
cancelable: true,
|
| 155 |
+
view: window,
|
| 156 |
+
which: keyCode,
|
| 157 |
+
keyCode: keyCode
|
| 158 |
+
};
|
| 159 |
+
|
| 160 |
+
const down = new KeyboardEvent('keydown', bsConfig);
|
| 161 |
+
Object.defineProperty(down, 'keyCode', { get: () => keyCode });
|
| 162 |
+
Object.defineProperty(down, 'which', { get: () => keyCode });
|
| 163 |
+
target.dispatchEvent(down);
|
| 164 |
+
|
| 165 |
+
// Backspace Input Event
|
| 166 |
+
const inputEvent = new InputEvent('input', {
|
| 167 |
+
inputType: 'deleteContentBackward',
|
| 168 |
+
bubbles: true,
|
| 169 |
+
cancelable: true,
|
| 170 |
+
view: window
|
| 171 |
+
});
|
| 172 |
+
target.dispatchEvent(inputEvent);
|
| 173 |
+
|
| 174 |
+
const holdTime = randomNormal(30, 5); // Short hold for backspace
|
| 175 |
+
await sleep(Math.max(10, holdTime));
|
| 176 |
+
|
| 177 |
+
const up = new KeyboardEvent('keyup', bsConfig);
|
| 178 |
+
Object.defineProperty(up, 'keyCode', { get: () => keyCode });
|
| 179 |
+
Object.defineProperty(up, 'which', { get: () => keyCode });
|
| 180 |
+
target.dispatchEvent(up);
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
+
function getAdjacentKey(char) {
|
| 184 |
+
const lowerChar = char.toLowerCase();
|
| 185 |
+
const adjacent = ADJACENT_KEYS[lowerChar];
|
| 186 |
+
if (adjacent && adjacent.length > 0) {
|
| 187 |
+
const randomAdj = adjacent[Math.floor(Math.random() * adjacent.length)];
|
| 188 |
+
return char === char.toUpperCase() ? randomAdj.toUpperCase() : randomAdj;
|
| 189 |
+
}
|
| 190 |
+
return char;
|
| 191 |
+
}
|
| 192 |
+
|
| 193 |
+
function getRandomChar() {
|
| 194 |
+
const chars = "abcdefghijklmnopqrstuvwxyz";
|
| 195 |
+
return chars.charAt(Math.floor(Math.random() * chars.length));
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
// New Gaussian Delay Calculation
|
| 199 |
+
function getKeystrokeDelay() {
|
| 200 |
+
// Calculate Target WPM for this keystroke (vary it per stroke slightly)
|
| 201 |
+
const meanWPM = (CONFIG.min_wpm + CONFIG.max_wpm) / 2;
|
| 202 |
+
// Use narrower range for consistency but still random
|
| 203 |
+
const currentTargetWPM = randomNormal(meanWPM, (CONFIG.max_wpm - CONFIG.min_wpm) / 6);
|
| 204 |
+
|
| 205 |
+
let baseDelay = 60000 / (Math.max(10, currentTargetWPM) * 5);
|
| 206 |
+
|
| 207 |
+
// Burst Mode
|
| 208 |
+
if (inBurstMode && burstCharsRemaining > 0) {
|
| 209 |
+
let multiplier = CONFIG.burst_speed_multiplier;
|
| 210 |
+
if (inInsaneBurstMode) multiplier *= 0.6;
|
| 211 |
+
baseDelay *= multiplier;
|
| 212 |
+
|
| 213 |
+
burstCharsRemaining--;
|
| 214 |
+
if (burstCharsRemaining === 0) {
|
| 215 |
+
inBurstMode = false;
|
| 216 |
+
inInsaneBurstMode = false;
|
| 217 |
+
}
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
// Add Gaussian Noise (Standard Deviation approx 15-18% of base delay)
|
| 221 |
+
const delay = randomNormal(baseDelay, baseDelay * 0.18);
|
| 222 |
+
return Math.max(10, delay);
|
| 223 |
+
}
|
| 224 |
+
|
| 225 |
+
function getCurrentWordText() {
|
| 226 |
+
// Try multiple selectors for robustness
|
| 227 |
+
const activeWord = document.querySelector('#words .word.active') || document.querySelector('.word.active');
|
| 228 |
+
if (!activeWord) return null;
|
| 229 |
+
|
| 230 |
+
const letters = activeWord.querySelectorAll('letter');
|
| 231 |
+
let text = "";
|
| 232 |
+
let foundUntyped = false;
|
| 233 |
+
|
| 234 |
+
for (const letter of letters) {
|
| 235 |
+
if (!letter.classList.contains('correct') && !letter.classList.contains('incorrect')) {
|
| 236 |
+
foundUntyped = true;
|
| 237 |
+
}
|
| 238 |
+
if (foundUntyped) {
|
| 239 |
+
text += letter.textContent;
|
| 240 |
+
}
|
| 241 |
+
}
|
| 242 |
+
return text;
|
| 243 |
+
}
|
| 244 |
+
|
| 245 |
+
function isWordStart() {
|
| 246 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 247 |
+
if (!activeWord) return false;
|
| 248 |
+
const typed = activeWord.querySelectorAll('letter.correct, letter.incorrect');
|
| 249 |
+
return typed.length === 0;
|
| 250 |
+
}
|
| 251 |
+
|
| 252 |
+
// === MISTAKE SIMULATION ===
|
| 253 |
+
async function simulateWrongChar(correctChar) {
|
| 254 |
+
const wrongChar = getRandomChar();
|
| 255 |
+
await typeChar(wrongChar);
|
| 256 |
+
await sleep(getKeystrokeDelay() * 2.5); // Pause to "realize" mistake
|
| 257 |
+
await typeBackspace();
|
| 258 |
+
await sleep(getKeystrokeDelay() * 1.5); // Recovery
|
| 259 |
+
recentMistake = true;
|
| 260 |
+
}
|
| 261 |
+
|
| 262 |
+
async function simulateAdjacentKeyTypo(correctChar) {
|
| 263 |
+
const adjacentChar = getAdjacentKey(correctChar);
|
| 264 |
+
if (adjacentChar !== correctChar) {
|
| 265 |
+
await typeChar(adjacentChar);
|
| 266 |
+
await sleep(getKeystrokeDelay() * 2.2);
|
| 267 |
+
await typeBackspace();
|
| 268 |
+
await sleep(getKeystrokeDelay() * 1.3);
|
| 269 |
+
recentMistake = true;
|
| 270 |
+
}
|
| 271 |
+
}
|
| 272 |
+
|
| 273 |
+
async function simulateDoubleLetter(char) {
|
| 274 |
+
await typeChar(char);
|
| 275 |
+
await sleep(getKeystrokeDelay() * 0.3); // Fast double tap
|
| 276 |
+
await typeChar(char);
|
| 277 |
+
await sleep(getKeystrokeDelay() * 2.0);
|
| 278 |
+
await typeBackspace();
|
| 279 |
+
await sleep(getKeystrokeDelay() * 1.2);
|
| 280 |
+
recentMistake = true;
|
| 281 |
+
}
|
| 282 |
+
|
| 283 |
+
async function autoTypeLoop() {
|
| 284 |
+
console.log("Starting human-like auto-type loop v4...");
|
| 285 |
+
let wordCount = 0;
|
| 286 |
+
|
| 287 |
+
while (true) {
|
| 288 |
+
const currentWordText = getCurrentWordText();
|
| 289 |
+
|
| 290 |
+
if (currentWordText === null) {
|
| 291 |
+
console.log(`Auto-type complete! Typed ${wordCount} words.`);
|
| 292 |
+
break;
|
| 293 |
+
}
|
| 294 |
+
|
| 295 |
+
if (currentWordText.length === 0) {
|
| 296 |
+
// Determine next word existence
|
| 297 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 298 |
+
if (!activeWord) {
|
| 299 |
+
// Try waiting briefly, maybe DOM update lag
|
| 300 |
+
await sleep(50);
|
| 301 |
+
if (!document.querySelector('#words .word.active')) {
|
| 302 |
+
break;
|
| 303 |
+
}
|
| 304 |
+
continue;
|
| 305 |
+
}
|
| 306 |
+
const nextWord = activeWord.nextElementSibling;
|
| 307 |
+
if (!nextWord || !nextWord.classList.contains('word')) {
|
| 308 |
+
// Check if there are words in a new line or block?
|
| 309 |
+
// If no next sibling, likely end of test or line break
|
| 310 |
+
// Monkeytype usually keeps all words in DOM or lazy loads
|
| 311 |
+
await sleep(100);
|
| 312 |
+
if (!document.querySelector('#words .word.active')) {
|
| 313 |
+
break;
|
| 314 |
+
}
|
| 315 |
+
// If still active word is empty and no next sibling, maybe just finished last word?
|
| 316 |
+
// Let's break to be safe
|
| 317 |
+
break;
|
| 318 |
+
}
|
| 319 |
+
|
| 320 |
+
await typeChar(' ');
|
| 321 |
+
wordCount++;
|
| 322 |
+
|
| 323 |
+
// Pause between words (Gaussian)
|
| 324 |
+
const wordPauseBase = getKeystrokeDelay() * 1.4;
|
| 325 |
+
const wordPause = Math.max(20, randomNormal(wordPauseBase, wordPauseBase * 0.3));
|
| 326 |
+
await sleep(wordPause);
|
| 327 |
+
continue;
|
| 328 |
+
}
|
| 329 |
+
|
| 330 |
+
const char = currentWordText[0];
|
| 331 |
+
const nextChar = currentWordText.length > 1 ? currentWordText[1] : null;
|
| 332 |
+
let delay = getKeystrokeDelay();
|
| 333 |
+
|
| 334 |
+
if (isWordStart()) delay *= CONFIG.word_start_slowdown;
|
| 335 |
+
if (Math.random() < CONFIG.hesitation_rate) delay *= CONFIG.hesitation_multiplier;
|
| 336 |
+
if (recentMistake) {
|
| 337 |
+
await sleep(CONFIG.post_mistake_pause * 1000);
|
| 338 |
+
recentMistake = false;
|
| 339 |
+
}
|
| 340 |
+
|
| 341 |
+
// Burst Logic
|
| 342 |
+
if (!inBurstMode && Math.random() < CONFIG.insane_burst_rate) {
|
| 343 |
+
inBurstMode = true;
|
| 344 |
+
inInsaneBurstMode = true;
|
| 345 |
+
burstCharsRemaining = 12;
|
| 346 |
+
} else if (!inBurstMode && Math.random() < CONFIG.burst_rate) {
|
| 347 |
+
inBurstMode = true;
|
| 348 |
+
burstCharsRemaining = 5;
|
| 349 |
+
}
|
| 350 |
+
|
| 351 |
+
// Imperfections
|
| 352 |
+
if (/[a-zA-Z]/.test(char) && Math.random() < CONFIG.skip_letter_rate && nextChar) {
|
| 353 |
+
await typeChar(nextChar);
|
| 354 |
+
await sleep(getKeystrokeDelay() * 2.5);
|
| 355 |
+
await typeBackspace();
|
| 356 |
+
await sleep(getKeystrokeDelay() * 1.3);
|
| 357 |
+
recentMistake = true;
|
| 358 |
+
await typeChar(char);
|
| 359 |
+
await sleep(delay);
|
| 360 |
+
continue;
|
| 361 |
+
}
|
| 362 |
+
if (/[a-zA-Z]/.test(char) && Math.random() < CONFIG.double_letter_rate) {
|
| 363 |
+
await simulateDoubleLetter(char);
|
| 364 |
+
await sleep(delay);
|
| 365 |
+
continue;
|
| 366 |
+
}
|
| 367 |
+
if (/[a-zA-Z]/.test(char) && Math.random() < CONFIG.adjacent_key_rate) {
|
| 368 |
+
await simulateAdjacentKeyTypo(char);
|
| 369 |
+
// After typo logic, we still need to type the correct char?
|
| 370 |
+
// Logic: simulateAdjacentKeyTypo types wrong char then backspaces.
|
| 371 |
+
// So now we fall through to type correct char.
|
| 372 |
+
} else if (/[a-zA-Z]/.test(char) && Math.random() < CONFIG.wrong_char_rate) {
|
| 373 |
+
await simulateWrongChar(char);
|
| 374 |
+
// Fall through to type correct char
|
| 375 |
+
}
|
| 376 |
+
|
| 377 |
+
await typeChar(char);
|
| 378 |
+
await sleep(delay);
|
| 379 |
+
}
|
| 380 |
+
}
|
| 381 |
+
|
| 382 |
+
const triggerHandler = (e) => {
|
| 383 |
+
if (!isArmed) return;
|
| 384 |
+
// Trigger on single letter key press (no modifiers)
|
| 385 |
+
if (e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey) {
|
| 386 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 387 |
+
if (activeWord) {
|
| 388 |
+
const firstLetter = activeWord.querySelector('letter')?.textContent;
|
| 389 |
+
if (firstLetter && e.key === firstLetter) {
|
| 390 |
+
isArmed = false;
|
| 391 |
+
window.removeEventListener('keydown', triggerHandler);
|
| 392 |
+
console.log("Trigger detected. Starting...");
|
| 393 |
+
// Small delay to let the first real keypress register naturally
|
| 394 |
+
setTimeout(autoTypeLoop, 150);
|
| 395 |
+
}
|
| 396 |
+
}
|
| 397 |
+
}
|
| 398 |
+
};
|
| 399 |
+
|
| 400 |
+
window.addEventListener('keydown', triggerHandler);
|
| 401 |
+
console.log("READY! Type the first letter to activate Human-Like Mode v4 (Low WPM).");
|
| 402 |
+
})();
|
3rd_version (latest)/Dump/1.py
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pyautogui
|
| 2 |
+
import keyboard
|
| 3 |
+
import time
|
| 4 |
+
import random
|
| 5 |
+
import pyperclip
|
| 6 |
+
import sys
|
| 7 |
+
|
| 8 |
+
# === CONFIGURATION ===
|
| 9 |
+
CONFIG = {
|
| 10 |
+
"min_wpm": 310,
|
| 11 |
+
"max_wpm": 550,
|
| 12 |
+
"start_delay": 0.05, # Seconds
|
| 13 |
+
|
| 14 |
+
# Imperfection Rates (0.0 to 1.0)
|
| 15 |
+
"wrong_char_rate": 0.025,
|
| 16 |
+
"adjacent_key_rate": 0.02,
|
| 17 |
+
"double_letter_rate": 0.015,
|
| 18 |
+
"skip_letter_rate": 0.01,
|
| 19 |
+
"transpose_rate": 0.012,
|
| 20 |
+
"hesitation_rate": 0.04,
|
| 21 |
+
"burst_rate": 0.08,
|
| 22 |
+
|
| 23 |
+
# Timing Multipliers
|
| 24 |
+
"hesitation_multiplier": 3.5,
|
| 25 |
+
"burst_speed_multiplier": 0.5,
|
| 26 |
+
"post_mistake_pause": 2.0,
|
| 27 |
+
"word_start_slowdown": 1.5,
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
# QWERTY Adjacency Map
|
| 31 |
+
ADJACENT_KEYS = {
|
| 32 |
+
'a': 'qwsz', 'b': 'vghn', 'c': 'xdfv', 'd': 'serfcx', 'e': 'wsdr',
|
| 33 |
+
'f': 'drtgvc', 'g': 'ftyhbv', 'h': 'gyujnb', 'i': 'ujko', 'j': 'huikmn',
|
| 34 |
+
'k': 'jiolm', 'l': 'kop', 'm': 'njk', 'n': 'bhjm', 'o': 'iklp',
|
| 35 |
+
'p': 'ol', 'q': 'wa', 'r': 'edft', 's': 'awedxz', 't': 'rfgy',
|
| 36 |
+
'u': 'yhji', 'v': 'cfgb', 'w': 'qase', 'x': 'zsdc', 'y': 'tghu',
|
| 37 |
+
'z': 'asx'
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
def get_keystroke_delay(wpm, in_burst=False):
|
| 41 |
+
"""Calculates delay between keystrokes based on WPM."""
|
| 42 |
+
cpm = wpm * 5
|
| 43 |
+
base_delay = 60 / cpm
|
| 44 |
+
|
| 45 |
+
if in_burst:
|
| 46 |
+
base_delay *= CONFIG["burst_speed_multiplier"]
|
| 47 |
+
|
| 48 |
+
# Add noise (+/- 25%)
|
| 49 |
+
variance = base_delay * 0.25
|
| 50 |
+
noise = random.uniform(-variance, variance)
|
| 51 |
+
return max(0.008, base_delay + noise)
|
| 52 |
+
|
| 53 |
+
def get_adjacent_key(char):
|
| 54 |
+
"""Returns a key adjacent to the given char on QWERTY layout."""
|
| 55 |
+
char_lower = char.lower()
|
| 56 |
+
if char_lower in ADJACENT_KEYS:
|
| 57 |
+
adj = random.choice(ADJACENT_KEYS[char_lower])
|
| 58 |
+
return adj.upper() if char.isupper() else adj
|
| 59 |
+
return char
|
| 60 |
+
|
| 61 |
+
def type_char(char):
|
| 62 |
+
"""Types a single character using PyAutoGUI."""
|
| 63 |
+
pyautogui.write(char)
|
| 64 |
+
|
| 65 |
+
def simulate_backspace(count=1):
|
| 66 |
+
"""Simulates pressing backspace."""
|
| 67 |
+
for _ in range(count):
|
| 68 |
+
pyautogui.press('backspace')
|
| 69 |
+
time.sleep(random.uniform(0.05, 0.1))
|
| 70 |
+
|
| 71 |
+
def mnk_typer():
|
| 72 |
+
print("=== MnkLightning Python Automation ===")
|
| 73 |
+
print("1. Copy text from Monkeytype using injector.js (Press Insert in browser)")
|
| 74 |
+
print("2. Focus the browser window")
|
| 75 |
+
print("3. Press 'Insert' to START typing")
|
| 76 |
+
print("4. Press 'Esc' to STOP")
|
| 77 |
+
print("Waiting for trigger...")
|
| 78 |
+
|
| 79 |
+
while True:
|
| 80 |
+
if keyboard.is_pressed('esc'):
|
| 81 |
+
print("\nExiting...")
|
| 82 |
+
sys.exit()
|
| 83 |
+
|
| 84 |
+
if keyboard.is_pressed('insert'):
|
| 85 |
+
# Debounce
|
| 86 |
+
time.sleep(0.5)
|
| 87 |
+
|
| 88 |
+
# Get text from clipboard
|
| 89 |
+
text = pyperclip.paste()
|
| 90 |
+
if not text:
|
| 91 |
+
print("Clipboard empty! extraction failed?")
|
| 92 |
+
continue
|
| 93 |
+
|
| 94 |
+
print(f"Typing {len(text)} characters...")
|
| 95 |
+
|
| 96 |
+
wpm = random.randint(CONFIG["min_wpm"], CONFIG["max_wpm"])
|
| 97 |
+
print(f"Target WPM: {wpm}")
|
| 98 |
+
|
| 99 |
+
# State
|
| 100 |
+
idx = 0
|
| 101 |
+
burst_remaining = 0
|
| 102 |
+
|
| 103 |
+
try:
|
| 104 |
+
while idx < len(text):
|
| 105 |
+
if keyboard.is_pressed('esc'):
|
| 106 |
+
return
|
| 107 |
+
|
| 108 |
+
char = text[idx]
|
| 109 |
+
delay = get_keystroke_delay(wpm, burst_remaining > 0)
|
| 110 |
+
|
| 111 |
+
if burst_remaining > 0:
|
| 112 |
+
burst_remaining -= 1
|
| 113 |
+
|
| 114 |
+
# === IMPERFECTIONS ===
|
| 115 |
+
|
| 116 |
+
# 1. Hesitation
|
| 117 |
+
if random.random() < CONFIG["hesitation_rate"]:
|
| 118 |
+
delay *= CONFIG["hesitation_multiplier"]
|
| 119 |
+
|
| 120 |
+
# 2. Burst Mode
|
| 121 |
+
if burst_remaining == 0 and random.random() < CONFIG["burst_rate"]:
|
| 122 |
+
burst_remaining = 5
|
| 123 |
+
|
| 124 |
+
# 3. Wrong Character (Type random, then fix)
|
| 125 |
+
if random.random() < CONFIG["wrong_char_rate"] and char.isalnum():
|
| 126 |
+
wrong = random.choice("abcdefghijklmnopqrstuvwxyz")
|
| 127 |
+
pyautogui.write(wrong)
|
| 128 |
+
time.sleep(delay * 2)
|
| 129 |
+
pyautogui.press('backspace')
|
| 130 |
+
time.sleep(delay)
|
| 131 |
+
# Don't increment idx, we need to type correct char
|
| 132 |
+
|
| 133 |
+
# 4. Adjacent Key (Type neighbor, then fix)
|
| 134 |
+
elif random.random() < CONFIG["adjacent_key_rate"] and char.isalpha():
|
| 135 |
+
adj = get_adjacent_key(char)
|
| 136 |
+
pyautogui.write(adj)
|
| 137 |
+
time.sleep(delay * 1.5)
|
| 138 |
+
pyautogui.press('backspace')
|
| 139 |
+
time.sleep(delay)
|
| 140 |
+
|
| 141 |
+
# 5. Skip Letter (Type next char, realize, backspace 2, type current)
|
| 142 |
+
elif random.random() < CONFIG["skip_letter_rate"] and idx + 1 < len(text):
|
| 143 |
+
next_char = text[idx+1]
|
| 144 |
+
pyautogui.write(next_char)
|
| 145 |
+
time.sleep(delay * 2.5)
|
| 146 |
+
pyautogui.press('backspace')
|
| 147 |
+
time.sleep(delay)
|
| 148 |
+
# Now continue loop to type 'char'
|
| 149 |
+
|
| 150 |
+
# 6. Double Letter (Type char twice, delete one)
|
| 151 |
+
elif random.random() < CONFIG["double_letter_rate"] and char.isalpha():
|
| 152 |
+
pyautogui.write(char)
|
| 153 |
+
time.sleep(0.05)
|
| 154 |
+
pyautogui.write(char) # Double
|
| 155 |
+
time.sleep(delay * 2)
|
| 156 |
+
pyautogui.press('backspace')
|
| 157 |
+
idx += 1 # We kept one valid char
|
| 158 |
+
time.sleep(delay)
|
| 159 |
+
continue
|
| 160 |
+
|
| 161 |
+
# === TYPING ===
|
| 162 |
+
type_char(char)
|
| 163 |
+
idx += 1
|
| 164 |
+
|
| 165 |
+
# Word boundary pause
|
| 166 |
+
if char == ' ':
|
| 167 |
+
delay *= CONFIG["word_start_slowdown"]
|
| 168 |
+
|
| 169 |
+
time.sleep(delay)
|
| 170 |
+
|
| 171 |
+
except KeyboardInterrupt:
|
| 172 |
+
pass
|
| 173 |
+
|
| 174 |
+
print("\nTyping complete.")
|
| 175 |
+
time.sleep(1) # Prevent double trigger
|
| 176 |
+
|
| 177 |
+
if __name__ == "__main__":
|
| 178 |
+
try:
|
| 179 |
+
mnk_typer()
|
| 180 |
+
except KeyboardInterrupt:
|
| 181 |
+
sys.exit()
|
3rd_version (latest)/Dump/2.py
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pyautogui
|
| 2 |
+
import keyboard
|
| 3 |
+
import time
|
| 4 |
+
import random
|
| 5 |
+
import pyperclip
|
| 6 |
+
import sys
|
| 7 |
+
|
| 8 |
+
# Remove default 0.1s pause after every PyAutoGUI call
|
| 9 |
+
pyautogui.PAUSE = 0
|
| 10 |
+
|
| 11 |
+
# === CONFIGURATION ===
|
| 12 |
+
CONFIG = {
|
| 13 |
+
"min_wpm": 310,
|
| 14 |
+
"max_wpm": 550,
|
| 15 |
+
# Key Hold Time (Seconds)
|
| 16 |
+
"min_key_hold": 0.02,
|
| 17 |
+
"max_key_hold": 0.06,
|
| 18 |
+
|
| 19 |
+
# Imperfection Rates (0.0 to 1.0)
|
| 20 |
+
"wrong_char_rate": 0.025,
|
| 21 |
+
"adjacent_key_rate": 0.02,
|
| 22 |
+
"double_letter_rate": 0.015,
|
| 23 |
+
"skip_letter_rate": 0.01,
|
| 24 |
+
"transpose_rate": 0.012,
|
| 25 |
+
"hesitation_rate": 0.04,
|
| 26 |
+
"burst_rate": 0.08,
|
| 27 |
+
|
| 28 |
+
# Timing Multipliers
|
| 29 |
+
"hesitation_multiplier": 3.5,
|
| 30 |
+
"burst_speed_multiplier": 0.5,
|
| 31 |
+
"post_mistake_pause": 2.0,
|
| 32 |
+
"word_start_slowdown": 1.5,
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
# QWERTY Adjacency Map
|
| 36 |
+
ADJACENT_KEYS = {
|
| 37 |
+
'a': 'qwsz', 'b': 'vghn', 'c': 'xdfv', 'd': 'serfcx', 'e': 'wsdr',
|
| 38 |
+
'f': 'drtgvc', 'g': 'ftyhbv', 'h': 'gyujnb', 'i': 'ujko', 'j': 'huikmn',
|
| 39 |
+
'k': 'jiolm', 'l': 'kop', 'm': 'njk', 'n': 'bhjm', 'o': 'iklp',
|
| 40 |
+
'p': 'ol', 'q': 'wa', 'r': 'edft', 's': 'awedxz', 't': 'rfgy',
|
| 41 |
+
'u': 'yhji', 'v': 'cfgb', 'w': 'qase', 'x': 'zsdc', 'y': 'tghu',
|
| 42 |
+
'z': 'asx'
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
def get_keystroke_delay(wpm, in_burst=False):
|
| 46 |
+
"""Calculates delay between keystrokes based on WPM."""
|
| 47 |
+
cpm = wpm * 5
|
| 48 |
+
base_delay = 10 / cpm
|
| 49 |
+
|
| 50 |
+
if in_burst:
|
| 51 |
+
base_delay *= CONFIG["burst_speed_multiplier"]
|
| 52 |
+
|
| 53 |
+
# Add noise (+/- 25%)
|
| 54 |
+
variance = base_delay * 0.25
|
| 55 |
+
noise = random.uniform(-variance, variance)
|
| 56 |
+
return max(0.008, base_delay + noise)
|
| 57 |
+
|
| 58 |
+
def get_adjacent_key(char):
|
| 59 |
+
"""Returns a key adjacent to the given char on QWERTY layout."""
|
| 60 |
+
char_lower = char.lower()
|
| 61 |
+
if char_lower in ADJACENT_KEYS:
|
| 62 |
+
adj = random.choice(ADJACENT_KEYS[char_lower])
|
| 63 |
+
return adj.upper() if char.isupper() else adj
|
| 64 |
+
return char
|
| 65 |
+
|
| 66 |
+
def type_char(char):
|
| 67 |
+
"""Types a single character with human-like key hold duration."""
|
| 68 |
+
# Handle special characters or shift needs
|
| 69 |
+
try:
|
| 70 |
+
pyautogui.keyDown(char)
|
| 71 |
+
time.sleep(random.uniform(CONFIG["min_key_hold"], CONFIG["max_key_hold"]))
|
| 72 |
+
pyautogui.keyUp(char)
|
| 73 |
+
except:
|
| 74 |
+
# Fallback for complex chars
|
| 75 |
+
pyautogui.write(char)
|
| 76 |
+
|
| 77 |
+
def simulate_backspace(count=1):
|
| 78 |
+
"""Simulates pressing backspace with hold time."""
|
| 79 |
+
for _ in range(count):
|
| 80 |
+
pyautogui.keyDown('backspace')
|
| 81 |
+
time.sleep(random.uniform(CONFIG["min_key_hold"], CONFIG["max_key_hold"]))
|
| 82 |
+
pyautogui.keyUp('backspace')
|
| 83 |
+
time.sleep(random.uniform(0.05, 0.1))
|
| 84 |
+
|
| 85 |
+
def mnk_typer():
|
| 86 |
+
print("=== MnkLightning Python Automation ===")
|
| 87 |
+
print("1. Copy text from Monkeytype using injector.js (Press Insert in browser)")
|
| 88 |
+
print("2. Focus the browser window")
|
| 89 |
+
print("3. Press 'Insert' to START typing")
|
| 90 |
+
print("4. Press 'Esc' to STOP")
|
| 91 |
+
print("Waiting for trigger...")
|
| 92 |
+
|
| 93 |
+
while True:
|
| 94 |
+
if keyboard.is_pressed('esc'):
|
| 95 |
+
print("\nExiting...")
|
| 96 |
+
sys.exit()
|
| 97 |
+
|
| 98 |
+
if keyboard.is_pressed('insert'):
|
| 99 |
+
# Debounce
|
| 100 |
+
time.sleep(0.5)
|
| 101 |
+
|
| 102 |
+
# Get text from clipboard
|
| 103 |
+
text = pyperclip.paste()
|
| 104 |
+
if not text:
|
| 105 |
+
print("Clipboard empty! extraction failed?")
|
| 106 |
+
continue
|
| 107 |
+
|
| 108 |
+
print(f"Typing {len(text)} characters...")
|
| 109 |
+
|
| 110 |
+
wpm = random.randint(CONFIG["min_wpm"], CONFIG["max_wpm"])
|
| 111 |
+
print(f"Target WPM: {wpm}")
|
| 112 |
+
|
| 113 |
+
# State
|
| 114 |
+
idx = 0
|
| 115 |
+
burst_remaining = 0
|
| 116 |
+
|
| 117 |
+
try:
|
| 118 |
+
while idx < len(text):
|
| 119 |
+
if keyboard.is_pressed('esc'):
|
| 120 |
+
return
|
| 121 |
+
|
| 122 |
+
char = text[idx]
|
| 123 |
+
delay = get_keystroke_delay(wpm, burst_remaining > 0)
|
| 124 |
+
|
| 125 |
+
if burst_remaining > 0:
|
| 126 |
+
burst_remaining -= 1
|
| 127 |
+
|
| 128 |
+
# === IMPERFECTIONS ===
|
| 129 |
+
|
| 130 |
+
# 1. Hesitation
|
| 131 |
+
if random.random() < CONFIG["hesitation_rate"]:
|
| 132 |
+
delay *= CONFIG["hesitation_multiplier"]
|
| 133 |
+
|
| 134 |
+
# 2. Burst Mode
|
| 135 |
+
if burst_remaining == 0 and random.random() < CONFIG["burst_rate"]:
|
| 136 |
+
burst_remaining = 5
|
| 137 |
+
|
| 138 |
+
# 3. Wrong Character (Type random, then fix)
|
| 139 |
+
if random.random() < CONFIG["wrong_char_rate"] and char.isalnum():
|
| 140 |
+
wrong = random.choice("abcdefghijklmnopqrstuvwxyz")
|
| 141 |
+
type_char(wrong)
|
| 142 |
+
time.sleep(delay * 2)
|
| 143 |
+
simulate_backspace(1)
|
| 144 |
+
time.sleep(delay)
|
| 145 |
+
# Don't increment idx, we need to type correct char
|
| 146 |
+
|
| 147 |
+
# 4. Adjacent Key (Type neighbor, then fix)
|
| 148 |
+
elif random.random() < CONFIG["adjacent_key_rate"] and char.isalpha():
|
| 149 |
+
adj = get_adjacent_key(char)
|
| 150 |
+
type_char(adj)
|
| 151 |
+
time.sleep(delay * 1.5)
|
| 152 |
+
simulate_backspace(1)
|
| 153 |
+
time.sleep(delay)
|
| 154 |
+
|
| 155 |
+
# 5. Skip Letter (Type next char, realize, backspace 2, type current)
|
| 156 |
+
elif random.random() < CONFIG["skip_letter_rate"] and idx + 1 < len(text):
|
| 157 |
+
next_char = text[idx+1]
|
| 158 |
+
type_char(next_char)
|
| 159 |
+
time.sleep(delay * 2.5)
|
| 160 |
+
simulate_backspace(1)
|
| 161 |
+
time.sleep(delay)
|
| 162 |
+
# Now continue loop to type 'char'
|
| 163 |
+
|
| 164 |
+
# 6. Double Letter (Type char twice, delete one)
|
| 165 |
+
elif random.random() < CONFIG["double_letter_rate"] and char.isalpha():
|
| 166 |
+
type_char(char)
|
| 167 |
+
time.sleep(0.05)
|
| 168 |
+
type_char(char) # Double
|
| 169 |
+
time.sleep(delay * 2)
|
| 170 |
+
simulate_backspace(1)
|
| 171 |
+
idx += 1 # We kept one valid char
|
| 172 |
+
time.sleep(delay)
|
| 173 |
+
continue
|
| 174 |
+
|
| 175 |
+
# === TYPING ===
|
| 176 |
+
type_char(char)
|
| 177 |
+
idx += 1
|
| 178 |
+
|
| 179 |
+
# Word boundary pause
|
| 180 |
+
if char == ' ':
|
| 181 |
+
delay *= CONFIG["word_start_slowdown"]
|
| 182 |
+
|
| 183 |
+
time.sleep(delay)
|
| 184 |
+
|
| 185 |
+
except KeyboardInterrupt:
|
| 186 |
+
pass
|
| 187 |
+
|
| 188 |
+
print("\nTyping complete.")
|
| 189 |
+
time.sleep(1) # Prevent double trigger
|
| 190 |
+
|
| 191 |
+
if __name__ == "__main__":
|
| 192 |
+
try:
|
| 193 |
+
mnk_typer()
|
| 194 |
+
except KeyboardInterrupt:
|
| 195 |
+
sys.exit()
|
3rd_version (latest)/Dump/3.py
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pyautogui
|
| 2 |
+
import keyboard
|
| 3 |
+
import time
|
| 4 |
+
import random
|
| 5 |
+
import pyperclip
|
| 6 |
+
import sys
|
| 7 |
+
|
| 8 |
+
# Remove default 0.1s pause after every PyAutoGUI call
|
| 9 |
+
pyautogui.PAUSE = 0
|
| 10 |
+
|
| 11 |
+
# === CONFIGURATION ===
|
| 12 |
+
CONFIG = {
|
| 13 |
+
"min_wpm": 410,
|
| 14 |
+
"max_wpm": 550,
|
| 15 |
+
# Key Hold Time (Seconds)
|
| 16 |
+
"min_key_hold": 0.02,
|
| 17 |
+
"max_key_hold": 0.06,
|
| 18 |
+
|
| 19 |
+
# Imperfection Rates (0.0 to 1.0)
|
| 20 |
+
"wrong_char_rate": 0.025,
|
| 21 |
+
"adjacent_key_rate": 0.02,
|
| 22 |
+
"double_letter_rate": 0.015,
|
| 23 |
+
"skip_letter_rate": 0.01,
|
| 24 |
+
"transpose_rate": 0.012,
|
| 25 |
+
"hesitation_rate": 0.04,
|
| 26 |
+
"burst_rate": 10.88,
|
| 27 |
+
"permanent_skip_rate": 0.005, # Skip 1 char (leaves it red)
|
| 28 |
+
"permanent_multi_skip_rate": 0.005, # Skip 2-3 chars (leaves them red)
|
| 29 |
+
|
| 30 |
+
# Timing Multipliers
|
| 31 |
+
"hesitation_multiplier": 3.5,
|
| 32 |
+
"burst_speed_multiplier": 0.5,
|
| 33 |
+
"post_mistake_pause": 2.0,
|
| 34 |
+
"word_start_slowdown": 1.5,
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
# QWERTY Adjacency Map
|
| 38 |
+
ADJACENT_KEYS = {
|
| 39 |
+
'a': 'qwsz', 'b': 'vghn', 'c': 'xdfv', 'd': 'serfcx', 'e': 'wsdr',
|
| 40 |
+
'f': 'drtgvc', 'g': 'ftyhbv', 'h': 'gyujnb', 'i': 'ujko', 'j': 'huikmn',
|
| 41 |
+
'k': 'jiolm', 'l': 'kop', 'm': 'njk', 'n': 'bhjm', 'o': 'iklp',
|
| 42 |
+
'p': 'ol', 'q': 'wa', 'r': 'edft', 's': 'awedxz', 't': 'rfgy',
|
| 43 |
+
'u': 'yhji', 'v': 'cfgb', 'w': 'qase', 'x': 'zsdc', 'y': 'tghu',
|
| 44 |
+
'z': 'asx'
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
def get_keystroke_delay(wpm, in_burst=False):
|
| 48 |
+
"""Calculates delay between keystrokes based on WPM."""
|
| 49 |
+
cpm = wpm * 5
|
| 50 |
+
base_delay = 10 / cpm
|
| 51 |
+
|
| 52 |
+
if in_burst:
|
| 53 |
+
base_delay *= CONFIG["burst_speed_multiplier"]
|
| 54 |
+
|
| 55 |
+
# Add noise (+/- 25%)
|
| 56 |
+
variance = base_delay * 0.25
|
| 57 |
+
noise = random.uniform(-variance, variance)
|
| 58 |
+
return max(0.008, base_delay + noise)
|
| 59 |
+
|
| 60 |
+
def get_adjacent_key(char):
|
| 61 |
+
"""Returns a key adjacent to the given char on QWERTY layout."""
|
| 62 |
+
char_lower = char.lower()
|
| 63 |
+
if char_lower in ADJACENT_KEYS:
|
| 64 |
+
adj = random.choice(ADJACENT_KEYS[char_lower])
|
| 65 |
+
return adj.upper() if char.isupper() else adj
|
| 66 |
+
return char
|
| 67 |
+
|
| 68 |
+
def type_char(char):
|
| 69 |
+
"""Types a single character with human-like key hold duration."""
|
| 70 |
+
# Handle special characters or shift needs
|
| 71 |
+
try:
|
| 72 |
+
pyautogui.keyDown(char)
|
| 73 |
+
time.sleep(random.uniform(CONFIG["min_key_hold"], CONFIG["max_key_hold"]))
|
| 74 |
+
pyautogui.keyUp(char)
|
| 75 |
+
except:
|
| 76 |
+
# Fallback for complex chars
|
| 77 |
+
pyautogui.write(char)
|
| 78 |
+
|
| 79 |
+
def simulate_backspace(count=1):
|
| 80 |
+
"""Simulates pressing backspace with hold time."""
|
| 81 |
+
for _ in range(count):
|
| 82 |
+
pyautogui.keyDown('backspace')
|
| 83 |
+
time.sleep(random.uniform(CONFIG["min_key_hold"], CONFIG["max_key_hold"]))
|
| 84 |
+
pyautogui.keyUp('backspace')
|
| 85 |
+
time.sleep(random.uniform(0.05, 0.1))
|
| 86 |
+
|
| 87 |
+
def mnk_typer():
|
| 88 |
+
print("=== MnkLightning Python Automation ===")
|
| 89 |
+
print("1. Copy text from Monkeytype using injector.js (Press Insert in browser)")
|
| 90 |
+
print("2. Focus the browser window")
|
| 91 |
+
print("3. Press 'Insert' to START typing")
|
| 92 |
+
print("4. Press 'Esc' to STOP")
|
| 93 |
+
print("Waiting for trigger...")
|
| 94 |
+
|
| 95 |
+
while True:
|
| 96 |
+
if keyboard.is_pressed('esc'):
|
| 97 |
+
print("\nExiting...")
|
| 98 |
+
sys.exit()
|
| 99 |
+
|
| 100 |
+
if keyboard.is_pressed('insert'):
|
| 101 |
+
# Debounce
|
| 102 |
+
time.sleep(0.5)
|
| 103 |
+
|
| 104 |
+
# Get text from clipboard
|
| 105 |
+
text = pyperclip.paste()
|
| 106 |
+
if not text:
|
| 107 |
+
print("Clipboard empty! extraction failed?")
|
| 108 |
+
continue
|
| 109 |
+
|
| 110 |
+
print(f"Typing {len(text)} characters...")
|
| 111 |
+
|
| 112 |
+
wpm = random.randint(CONFIG["min_wpm"], CONFIG["max_wpm"])
|
| 113 |
+
print(f"Target WPM: {wpm}")
|
| 114 |
+
|
| 115 |
+
# State
|
| 116 |
+
idx = 0
|
| 117 |
+
burst_remaining = 0
|
| 118 |
+
|
| 119 |
+
try:
|
| 120 |
+
while idx < len(text):
|
| 121 |
+
if keyboard.is_pressed('esc'):
|
| 122 |
+
return
|
| 123 |
+
|
| 124 |
+
char = text[idx]
|
| 125 |
+
delay = get_keystroke_delay(wpm, burst_remaining > 0)
|
| 126 |
+
|
| 127 |
+
if burst_remaining > 0:
|
| 128 |
+
burst_remaining -= 1
|
| 129 |
+
|
| 130 |
+
# === IMPERFECTIONS ===
|
| 131 |
+
|
| 132 |
+
# 1. Hesitation
|
| 133 |
+
if random.random() < CONFIG["hesitation_rate"]:
|
| 134 |
+
delay *= CONFIG["hesitation_multiplier"]
|
| 135 |
+
|
| 136 |
+
# 2. Burst Mode
|
| 137 |
+
if burst_remaining == 0 and random.random() < CONFIG["burst_rate"]:
|
| 138 |
+
burst_remaining = 5
|
| 139 |
+
|
| 140 |
+
# 3. Permanent Skip (Type nothing, effectively skipping the char)
|
| 141 |
+
if random.random() < CONFIG["permanent_skip_rate"]:
|
| 142 |
+
idx += 1
|
| 143 |
+
time.sleep(delay)
|
| 144 |
+
continue
|
| 145 |
+
|
| 146 |
+
# 4. Permanent Multi-Skip (Skip 2-3 chars)
|
| 147 |
+
if random.random() < CONFIG["permanent_multi_skip_rate"]:
|
| 148 |
+
skip_count = random.randint(2, 3)
|
| 149 |
+
idx += skip_count
|
| 150 |
+
time.sleep(delay)
|
| 151 |
+
continue
|
| 152 |
+
|
| 153 |
+
# 5. Wrong Character (Type random, then fix)
|
| 154 |
+
if random.random() < CONFIG["wrong_char_rate"] and char.isalnum():
|
| 155 |
+
wrong = random.choice("abcdefghijklmnopqrstuvwxyz")
|
| 156 |
+
type_char(wrong)
|
| 157 |
+
time.sleep(delay * 2)
|
| 158 |
+
simulate_backspace(1)
|
| 159 |
+
time.sleep(delay)
|
| 160 |
+
# Don't increment idx, we need to type correct char
|
| 161 |
+
|
| 162 |
+
# 6. Adjacent Key (Type neighbor, then fix)
|
| 163 |
+
elif random.random() < CONFIG["adjacent_key_rate"] and char.isalpha():
|
| 164 |
+
adj = get_adjacent_key(char)
|
| 165 |
+
type_char(adj)
|
| 166 |
+
time.sleep(delay * 1.5)
|
| 167 |
+
simulate_backspace(1)
|
| 168 |
+
time.sleep(delay)
|
| 169 |
+
|
| 170 |
+
# 7. Skip Letter (Type next char, realize, backspace 2, type current)
|
| 171 |
+
elif random.random() < CONFIG["skip_letter_rate"] and idx + 1 < len(text):
|
| 172 |
+
next_char = text[idx+1]
|
| 173 |
+
type_char(next_char)
|
| 174 |
+
time.sleep(delay * 2.5)
|
| 175 |
+
simulate_backspace(1)
|
| 176 |
+
time.sleep(delay)
|
| 177 |
+
# Now continue loop to type 'char'
|
| 178 |
+
|
| 179 |
+
# 8. Double Letter (Type char twice, delete one)
|
| 180 |
+
elif random.random() < CONFIG["double_letter_rate"] and char.isalpha():
|
| 181 |
+
type_char(char)
|
| 182 |
+
time.sleep(0.05)
|
| 183 |
+
type_char(char) # Double
|
| 184 |
+
time.sleep(delay * 2)
|
| 185 |
+
simulate_backspace(1)
|
| 186 |
+
idx += 1 # We kept one valid char
|
| 187 |
+
time.sleep(delay)
|
| 188 |
+
continue
|
| 189 |
+
|
| 190 |
+
# === TYPING ===
|
| 191 |
+
type_char(char)
|
| 192 |
+
idx += 1
|
| 193 |
+
|
| 194 |
+
# Word boundary pause
|
| 195 |
+
if char == ' ':
|
| 196 |
+
delay *= CONFIG["word_start_slowdown"]
|
| 197 |
+
|
| 198 |
+
time.sleep(delay)
|
| 199 |
+
|
| 200 |
+
except KeyboardInterrupt:
|
| 201 |
+
pass
|
| 202 |
+
|
| 203 |
+
print("\nTyping complete.")
|
| 204 |
+
time.sleep(1) # Prevent double trigger
|
| 205 |
+
|
| 206 |
+
if __name__ == "__main__":
|
| 207 |
+
try:
|
| 208 |
+
mnk_typer()
|
| 209 |
+
except KeyboardInterrupt:
|
| 210 |
+
sys.exit()
|
3rd_version (latest)/Dump/4.py
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pyautogui
|
| 2 |
+
import keyboard
|
| 3 |
+
import time
|
| 4 |
+
import random
|
| 5 |
+
import pyperclip
|
| 6 |
+
import sys
|
| 7 |
+
|
| 8 |
+
# Remove default 0.1s pause after every PyAutoGUI call
|
| 9 |
+
pyautogui.PAUSE = 0
|
| 10 |
+
|
| 11 |
+
# === CONFIGURATION ===
|
| 12 |
+
CONFIG = {
|
| 13 |
+
"min_wpm": 200,
|
| 14 |
+
"max_wpm": 300,
|
| 15 |
+
# Key Hold Time (Seconds)
|
| 16 |
+
"min_key_hold": 0.02,
|
| 17 |
+
"max_key_hold": 0.06,
|
| 18 |
+
|
| 19 |
+
# Imperfection Rates (0.0 to 1.0)
|
| 20 |
+
"wrong_char_rate": 0.055,
|
| 21 |
+
"adjacent_key_rate": 0.02,
|
| 22 |
+
"double_letter_rate": 0.015,
|
| 23 |
+
"skip_letter_rate": 0.01,
|
| 24 |
+
"transpose_rate": 0.012,
|
| 25 |
+
"hesitation_rate": 0.04,
|
| 26 |
+
"burst_rate": 0.88,
|
| 27 |
+
"insane_burst_rate": 0.8, # Type 4-5 chars almost instantly
|
| 28 |
+
"permanent_skip_rate": 0, # Skip 1 char (leaves it red)
|
| 29 |
+
"permanent_multi_skip_rate": 0.000, # Skip 2-3 chars (leaves them red)
|
| 30 |
+
|
| 31 |
+
# Timing Multipliers
|
| 32 |
+
"hesitation_multiplier": 3.5,
|
| 33 |
+
"burst_speed_multiplier": 6.5,
|
| 34 |
+
"post_mistake_pause": 2.0,
|
| 35 |
+
"word_start_slowdown": 1.5,
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
# QWERTY Adjacency Map
|
| 39 |
+
ADJACENT_KEYS = {
|
| 40 |
+
'a': 'qwsz', 'b': 'vghn', 'c': 'xdfv', 'd': 'serfcx', 'e': 'wsdr',
|
| 41 |
+
'f': 'drtgvc', 'g': 'ftyhbv', 'h': 'gyujnb', 'i': 'ujko', 'j': 'huikmn',
|
| 42 |
+
'k': 'jiolm', 'l': 'kop', 'm': 'njk', 'n': 'bhjm', 'o': 'iklp',
|
| 43 |
+
'p': 'ol', 'q': 'wa', 'r': 'edft', 's': 'awedxz', 't': 'rfgy',
|
| 44 |
+
'u': 'yhji', 'v': 'cfgb', 'w': 'qase', 'x': 'zsdc', 'y': 'tghu',
|
| 45 |
+
'z': 'asx'
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
def get_keystroke_delay(wpm, in_burst=False):
|
| 49 |
+
"""Calculates delay between keystrokes based on WPM."""
|
| 50 |
+
cpm = wpm * 5
|
| 51 |
+
base_delay = 10 / cpm
|
| 52 |
+
|
| 53 |
+
if in_burst:
|
| 54 |
+
base_delay *= CONFIG["burst_speed_multiplier"]
|
| 55 |
+
|
| 56 |
+
# Add noise (+/- 25%)
|
| 57 |
+
variance = base_delay * 0.25
|
| 58 |
+
noise = random.uniform(-variance, variance)
|
| 59 |
+
return max(0.008, base_delay + noise)
|
| 60 |
+
|
| 61 |
+
def get_adjacent_key(char):
|
| 62 |
+
"""Returns a key adjacent to the given char on QWERTY layout."""
|
| 63 |
+
char_lower = char.lower()
|
| 64 |
+
if char_lower in ADJACENT_KEYS:
|
| 65 |
+
adj = random.choice(ADJACENT_KEYS[char_lower])
|
| 66 |
+
return adj.upper() if char.isupper() else adj
|
| 67 |
+
return char
|
| 68 |
+
|
| 69 |
+
def type_char(char):
|
| 70 |
+
"""Types a single character with human-like key hold duration."""
|
| 71 |
+
# Handle special characters or shift needs
|
| 72 |
+
try:
|
| 73 |
+
pyautogui.keyDown(char)
|
| 74 |
+
time.sleep(random.uniform(CONFIG["min_key_hold"], CONFIG["max_key_hold"]))
|
| 75 |
+
pyautogui.keyUp(char)
|
| 76 |
+
except:
|
| 77 |
+
# Fallback for complex chars
|
| 78 |
+
pyautogui.write(char)
|
| 79 |
+
|
| 80 |
+
def simulate_backspace(count=1):
|
| 81 |
+
"""Simulates pressing backspace with hold time."""
|
| 82 |
+
for _ in range(count):
|
| 83 |
+
pyautogui.keyDown('backspace')
|
| 84 |
+
time.sleep(random.uniform(CONFIG["min_key_hold"], CONFIG["max_key_hold"]))
|
| 85 |
+
pyautogui.keyUp('backspace')
|
| 86 |
+
time.sleep(random.uniform(0.05, 0.1))
|
| 87 |
+
|
| 88 |
+
def mnk_typer():
|
| 89 |
+
print("=== MnkLightning Python Automation ===")
|
| 90 |
+
print("1. Copy text from Monkeytype using injector.js (Press Insert in browser)")
|
| 91 |
+
print("2. Focus the browser window")
|
| 92 |
+
print("3. Press 'Insert' to START typing")
|
| 93 |
+
print("4. Press 'Esc' to STOP")
|
| 94 |
+
print("Waiting for trigger...")
|
| 95 |
+
|
| 96 |
+
while True:
|
| 97 |
+
if keyboard.is_pressed('esc'):
|
| 98 |
+
print("\nExiting...")
|
| 99 |
+
sys.exit()
|
| 100 |
+
|
| 101 |
+
if keyboard.is_pressed('insert'):
|
| 102 |
+
# Debounce
|
| 103 |
+
time.sleep(0.5)
|
| 104 |
+
|
| 105 |
+
# Get text from clipboard
|
| 106 |
+
text = pyperclip.paste()
|
| 107 |
+
if not text:
|
| 108 |
+
print("Clipboard empty! extraction failed?")
|
| 109 |
+
continue
|
| 110 |
+
|
| 111 |
+
print(f"Typing {len(text)} characters...")
|
| 112 |
+
|
| 113 |
+
wpm = random.randint(CONFIG["min_wpm"], CONFIG["max_wpm"])
|
| 114 |
+
print(f"Target WPM: {wpm}")
|
| 115 |
+
|
| 116 |
+
# State
|
| 117 |
+
idx = 0
|
| 118 |
+
burst_remaining = 0
|
| 119 |
+
|
| 120 |
+
try:
|
| 121 |
+
while idx < len(text):
|
| 122 |
+
if keyboard.is_pressed('esc'):
|
| 123 |
+
return
|
| 124 |
+
|
| 125 |
+
char = text[idx]
|
| 126 |
+
delay = get_keystroke_delay(wpm, burst_remaining > 0)
|
| 127 |
+
|
| 128 |
+
if burst_remaining > 0:
|
| 129 |
+
burst_remaining -= 1
|
| 130 |
+
|
| 131 |
+
# === IMPERFECTIONS ===
|
| 132 |
+
|
| 133 |
+
# 1. Hesitation
|
| 134 |
+
if random.random() < CONFIG["hesitation_rate"]:
|
| 135 |
+
delay *= CONFIG["hesitation_multiplier"]
|
| 136 |
+
|
| 137 |
+
# 2. Burst Mode
|
| 138 |
+
if burst_remaining == 0 and random.random() < CONFIG["burst_rate"]:
|
| 139 |
+
burst_remaining = 5
|
| 140 |
+
|
| 141 |
+
# 3. Insane Burst Mode (Type 4-5 chars instantly)
|
| 142 |
+
if random.random() < CONFIG["insane_burst_rate"]:
|
| 143 |
+
burst_len = random.randint(4, 5)
|
| 144 |
+
for _ in range(burst_len):
|
| 145 |
+
if idx >= len(text): break
|
| 146 |
+
pyautogui.write(text[idx])
|
| 147 |
+
idx += 1
|
| 148 |
+
time.sleep(0.002) # Near zero delay
|
| 149 |
+
continue
|
| 150 |
+
|
| 151 |
+
# 4. Permanent Skip (Type nothing, effectively skipping the char)
|
| 152 |
+
if random.random() < CONFIG["permanent_skip_rate"]:
|
| 153 |
+
idx += 1
|
| 154 |
+
time.sleep(delay)
|
| 155 |
+
continue
|
| 156 |
+
|
| 157 |
+
# 4. Permanent Multi-Skip (Skip 2-3 chars)
|
| 158 |
+
if random.random() < CONFIG["permanent_multi_skip_rate"]:
|
| 159 |
+
skip_count = random.randint(2, 3)
|
| 160 |
+
idx += skip_count
|
| 161 |
+
time.sleep(delay)
|
| 162 |
+
continue
|
| 163 |
+
|
| 164 |
+
# 5. Wrong Character (Type random, then fix)
|
| 165 |
+
if random.random() < CONFIG["wrong_char_rate"] and char.isalnum():
|
| 166 |
+
wrong = random.choice("abcdefghijklmnopqrstuvwxyz")
|
| 167 |
+
type_char(wrong)
|
| 168 |
+
time.sleep(delay * 2)
|
| 169 |
+
simulate_backspace(1)
|
| 170 |
+
time.sleep(delay)
|
| 171 |
+
# Don't increment idx, we need to type correct char
|
| 172 |
+
|
| 173 |
+
# 6. Adjacent Key (Type neighbor, then fix)
|
| 174 |
+
elif random.random() < CONFIG["adjacent_key_rate"] and char.isalpha():
|
| 175 |
+
adj = get_adjacent_key(char)
|
| 176 |
+
type_char(adj)
|
| 177 |
+
time.sleep(delay * 1.5)
|
| 178 |
+
simulate_backspace(1)
|
| 179 |
+
time.sleep(delay)
|
| 180 |
+
|
| 181 |
+
# 7. Skip Letter (Type next char, realize, backspace 2, type current)
|
| 182 |
+
elif random.random() < CONFIG["skip_letter_rate"] and idx + 1 < len(text):
|
| 183 |
+
next_char = text[idx+1]
|
| 184 |
+
type_char(next_char)
|
| 185 |
+
time.sleep(delay * 2.5)
|
| 186 |
+
simulate_backspace(1)
|
| 187 |
+
time.sleep(delay)
|
| 188 |
+
# Now continue loop to type 'char'
|
| 189 |
+
|
| 190 |
+
# 8. Double Letter (Type char twice, delete one)
|
| 191 |
+
elif random.random() < CONFIG["double_letter_rate"] and char.isalpha():
|
| 192 |
+
type_char(char)
|
| 193 |
+
time.sleep(0.05)
|
| 194 |
+
type_char(char) # Double
|
| 195 |
+
time.sleep(delay * 2)
|
| 196 |
+
simulate_backspace(1)
|
| 197 |
+
idx += 1 # We kept one valid char
|
| 198 |
+
time.sleep(delay)
|
| 199 |
+
continue
|
| 200 |
+
|
| 201 |
+
# === TYPING ===
|
| 202 |
+
type_char(char)
|
| 203 |
+
idx += 1
|
| 204 |
+
|
| 205 |
+
# Word boundary pause
|
| 206 |
+
if char == ' ':
|
| 207 |
+
delay *= CONFIG["word_start_slowdown"]
|
| 208 |
+
|
| 209 |
+
time.sleep(delay)
|
| 210 |
+
|
| 211 |
+
except KeyboardInterrupt:
|
| 212 |
+
pass
|
| 213 |
+
|
| 214 |
+
print("\nTyping complete.")
|
| 215 |
+
time.sleep(1) # Prevent double trigger
|
| 216 |
+
|
| 217 |
+
if __name__ == "__main__":
|
| 218 |
+
try:
|
| 219 |
+
mnk_typer()
|
| 220 |
+
except KeyboardInterrupt:
|
| 221 |
+
sys.exit()
|
3rd_version (latest)/Dump/5.py
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pyautogui
|
| 2 |
+
import keyboard
|
| 3 |
+
import time
|
| 4 |
+
import random
|
| 5 |
+
import pyperclip
|
| 6 |
+
import sys
|
| 7 |
+
|
| 8 |
+
# Remove default 0.1s pause after every PyAutoGUI call
|
| 9 |
+
pyautogui.PAUSE = 0
|
| 10 |
+
|
| 11 |
+
# === CONFIGURATION ===
|
| 12 |
+
CONFIG = {
|
| 13 |
+
"min_wpm": 100,
|
| 14 |
+
"max_wpm": 140,
|
| 15 |
+
# Key Hold Time (Seconds)
|
| 16 |
+
"min_key_hold": 0.01,
|
| 17 |
+
"max_key_hold": 0.04,
|
| 18 |
+
|
| 19 |
+
# Imperfection Rates (0.0 to 1.0)
|
| 20 |
+
"wrong_char_rate": 0.015, # 1.5% chance
|
| 21 |
+
"adjacent_key_rate": 0.01, # 1.0% chance
|
| 22 |
+
"double_letter_rate": 0.005, # 0.5% chance
|
| 23 |
+
"skip_letter_rate": 0.002, # 0.2% chance
|
| 24 |
+
"transpose_rate": 0.005, # 0.5% chance
|
| 25 |
+
|
| 26 |
+
"hesitation_rate": 0.02, # 2% chance to hesitate
|
| 27 |
+
"burst_rate": 0.08, # 8% chance to speed up (burst)
|
| 28 |
+
"insane_burst_rate": .5, # Rare 5-char instant burst (0.1%)
|
| 29 |
+
"permanent_skip_rate": 0, # Disabled (causes invalid mostly)
|
| 30 |
+
"permanent_multi_skip_rate": 0,
|
| 31 |
+
|
| 32 |
+
# Timing Multipliers
|
| 33 |
+
"hesitation_multiplier": 2.5, # 2.5x slower during hesitation
|
| 34 |
+
"burst_speed_multiplier": 0.6, # 0.6x delay (faster) during burst
|
| 35 |
+
"post_mistake_pause": 0.4, # Slight pause after fixing mistake
|
| 36 |
+
"word_start_slowdown": 1.2, # Slight slowdown at start of new words
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
# QWERTY Adjacency Map
|
| 40 |
+
ADJACENT_KEYS = {
|
| 41 |
+
'a': 'qwsz', 'b': 'vghn', 'c': 'xdfv', 'd': 'serfcx', 'e': 'wsdr',
|
| 42 |
+
'f': 'drtgvc', 'g': 'ftyhbv', 'h': 'gyujnb', 'i': 'ujko', 'j': 'huikmn',
|
| 43 |
+
'k': 'jiolm', 'l': 'kop', 'm': 'njk', 'n': 'bhjm', 'o': 'iklp',
|
| 44 |
+
'p': 'ol', 'q': 'wa', 'r': 'edft', 's': 'awedxz', 't': 'rfgy',
|
| 45 |
+
'u': 'yhji', 'v': 'cfgb', 'w': 'qase', 'x': 'zsdc', 'y': 'tghu',
|
| 46 |
+
'z': 'asx'
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
def get_keystroke_delay(wpm, in_burst=False):
|
| 50 |
+
"""Calculates delay between keystrokes based on WPM."""
|
| 51 |
+
cpm = wpm * 5
|
| 52 |
+
# Standard formula: 60 seconds / chars per minute = seconds per char
|
| 53 |
+
base_delay = 60 / cpm
|
| 54 |
+
|
| 55 |
+
if in_burst:
|
| 56 |
+
# Bursts should be FASTER (reduced delay)
|
| 57 |
+
base_delay *= CONFIG["burst_speed_multiplier"]
|
| 58 |
+
|
| 59 |
+
# Add noise (+/- 20%)
|
| 60 |
+
variance = base_delay * 0.20
|
| 61 |
+
noise = random.uniform(-variance, variance)
|
| 62 |
+
return max(0.005, base_delay + noise)
|
| 63 |
+
|
| 64 |
+
def get_adjacent_key(char):
|
| 65 |
+
"""Returns a key adjacent to the given char on QWERTY layout."""
|
| 66 |
+
char_lower = char.lower()
|
| 67 |
+
if char_lower in ADJACENT_KEYS:
|
| 68 |
+
adj = random.choice(ADJACENT_KEYS[char_lower])
|
| 69 |
+
return adj.upper() if char.isupper() else adj
|
| 70 |
+
return char
|
| 71 |
+
|
| 72 |
+
def type_char(char):
|
| 73 |
+
"""Types a single character with human-like key hold duration."""
|
| 74 |
+
# Handle special characters or shift needs
|
| 75 |
+
try:
|
| 76 |
+
pyautogui.keyDown(char)
|
| 77 |
+
time.sleep(random.uniform(CONFIG["min_key_hold"], CONFIG["max_key_hold"]))
|
| 78 |
+
pyautogui.keyUp(char)
|
| 79 |
+
except:
|
| 80 |
+
# Fallback for complex chars
|
| 81 |
+
pyautogui.write(char)
|
| 82 |
+
|
| 83 |
+
def simulate_backspace(count=1):
|
| 84 |
+
"""Simulates pressing backspace with hold time."""
|
| 85 |
+
for _ in range(count):
|
| 86 |
+
pyautogui.keyDown('backspace')
|
| 87 |
+
time.sleep(random.uniform(CONFIG["min_key_hold"], CONFIG["max_key_hold"]))
|
| 88 |
+
pyautogui.keyUp('backspace')
|
| 89 |
+
time.sleep(random.uniform(0.05, 0.1))
|
| 90 |
+
|
| 91 |
+
def mnk_typer():
|
| 92 |
+
print("=== MnkLightning Python Automation ===")
|
| 93 |
+
print("1. Copy text from Monkeytype using injector.js (Press Insert in browser)")
|
| 94 |
+
print("2. Focus the browser window")
|
| 95 |
+
print("3. Press 'Insert' to START typing")
|
| 96 |
+
print("4. Press 'Esc' to STOP")
|
| 97 |
+
print("Waiting for trigger...")
|
| 98 |
+
|
| 99 |
+
while True:
|
| 100 |
+
if keyboard.is_pressed('esc'):
|
| 101 |
+
print("\nExiting...")
|
| 102 |
+
sys.exit()
|
| 103 |
+
|
| 104 |
+
if keyboard.is_pressed('insert'):
|
| 105 |
+
# Debounce
|
| 106 |
+
time.sleep(0.5)
|
| 107 |
+
|
| 108 |
+
# Get text from clipboard
|
| 109 |
+
text = pyperclip.paste()
|
| 110 |
+
if not text:
|
| 111 |
+
print("Clipboard empty! extraction failed?")
|
| 112 |
+
continue
|
| 113 |
+
|
| 114 |
+
print(f"Typing {len(text)} characters...")
|
| 115 |
+
|
| 116 |
+
wpm = random.randint(CONFIG["min_wpm"], CONFIG["max_wpm"])
|
| 117 |
+
print(f"Target WPM: {wpm}")
|
| 118 |
+
|
| 119 |
+
# State
|
| 120 |
+
idx = 0
|
| 121 |
+
burst_remaining = 0
|
| 122 |
+
|
| 123 |
+
try:
|
| 124 |
+
while idx < len(text):
|
| 125 |
+
if keyboard.is_pressed('esc'):
|
| 126 |
+
return
|
| 127 |
+
|
| 128 |
+
char = text[idx]
|
| 129 |
+
delay = get_keystroke_delay(wpm, burst_remaining > 0)
|
| 130 |
+
|
| 131 |
+
if burst_remaining > 0:
|
| 132 |
+
burst_remaining -= 1
|
| 133 |
+
|
| 134 |
+
# === IMPERFECTIONS ===
|
| 135 |
+
|
| 136 |
+
# 1. Hesitation
|
| 137 |
+
if random.random() < CONFIG["hesitation_rate"]:
|
| 138 |
+
delay *= CONFIG["hesitation_multiplier"]
|
| 139 |
+
|
| 140 |
+
# 2. Burst Mode
|
| 141 |
+
if burst_remaining == 0 and random.random() < CONFIG["burst_rate"]:
|
| 142 |
+
burst_remaining = 5
|
| 143 |
+
|
| 144 |
+
# 3. Insane Burst Mode (Type 4-5 chars instantly)
|
| 145 |
+
if random.random() < CONFIG["insane_burst_rate"]:
|
| 146 |
+
burst_len = random.randint(4, 5)
|
| 147 |
+
for _ in range(burst_len):
|
| 148 |
+
if idx >= len(text): break
|
| 149 |
+
pyautogui.write(text[idx])
|
| 150 |
+
idx += 1
|
| 151 |
+
time.sleep(0.002) # Near zero delay
|
| 152 |
+
continue
|
| 153 |
+
|
| 154 |
+
# 4. Permanent Skip (Type nothing, effectively skipping the char)
|
| 155 |
+
if random.random() < CONFIG["permanent_skip_rate"]:
|
| 156 |
+
idx += 1
|
| 157 |
+
time.sleep(delay)
|
| 158 |
+
continue
|
| 159 |
+
|
| 160 |
+
# 4. Permanent Multi-Skip (Skip 2-3 chars)
|
| 161 |
+
if random.random() < CONFIG["permanent_multi_skip_rate"]:
|
| 162 |
+
skip_count = random.randint(2, 3)
|
| 163 |
+
idx += skip_count
|
| 164 |
+
time.sleep(delay)
|
| 165 |
+
continue
|
| 166 |
+
|
| 167 |
+
# 5. Wrong Character (Type random, then fix)
|
| 168 |
+
if random.random() < CONFIG["wrong_char_rate"] and char.isalnum():
|
| 169 |
+
wrong = random.choice("abcdefghijklmnopqrstuvwxyz")
|
| 170 |
+
type_char(wrong)
|
| 171 |
+
time.sleep(delay * 2)
|
| 172 |
+
simulate_backspace(1)
|
| 173 |
+
time.sleep(delay)
|
| 174 |
+
# Don't increment idx, we need to type correct char
|
| 175 |
+
|
| 176 |
+
# 6. Adjacent Key (Type neighbor, then fix)
|
| 177 |
+
elif random.random() < CONFIG["adjacent_key_rate"] and char.isalpha():
|
| 178 |
+
adj = get_adjacent_key(char)
|
| 179 |
+
type_char(adj)
|
| 180 |
+
time.sleep(delay * 1.5)
|
| 181 |
+
simulate_backspace(1)
|
| 182 |
+
time.sleep(delay)
|
| 183 |
+
|
| 184 |
+
# 7. Skip Letter (Type next char, realize, backspace 2, type current)
|
| 185 |
+
elif random.random() < CONFIG["skip_letter_rate"] and idx + 1 < len(text):
|
| 186 |
+
next_char = text[idx+1]
|
| 187 |
+
type_char(next_char)
|
| 188 |
+
time.sleep(delay * 2.5)
|
| 189 |
+
simulate_backspace(1)
|
| 190 |
+
time.sleep(delay)
|
| 191 |
+
# Now continue loop to type 'char'
|
| 192 |
+
|
| 193 |
+
# 8. Double Letter (Type char twice, delete one)
|
| 194 |
+
elif random.random() < CONFIG["double_letter_rate"] and char.isalpha():
|
| 195 |
+
type_char(char)
|
| 196 |
+
time.sleep(0.05)
|
| 197 |
+
type_char(char) # Double
|
| 198 |
+
time.sleep(delay * 2)
|
| 199 |
+
simulate_backspace(1)
|
| 200 |
+
idx += 1 # We kept one valid char
|
| 201 |
+
time.sleep(delay)
|
| 202 |
+
continue
|
| 203 |
+
|
| 204 |
+
# === TYPING ===
|
| 205 |
+
type_char(char)
|
| 206 |
+
idx += 1
|
| 207 |
+
|
| 208 |
+
# Word boundary pause
|
| 209 |
+
if char == ' ':
|
| 210 |
+
delay *= CONFIG["word_start_slowdown"]
|
| 211 |
+
|
| 212 |
+
time.sleep(delay)
|
| 213 |
+
|
| 214 |
+
except KeyboardInterrupt:
|
| 215 |
+
pass
|
| 216 |
+
|
| 217 |
+
print("\nTyping complete.")
|
| 218 |
+
time.sleep(1) # Prevent double trigger
|
| 219 |
+
|
| 220 |
+
if __name__ == "__main__":
|
| 221 |
+
try:
|
| 222 |
+
mnk_typer()
|
| 223 |
+
except KeyboardInterrupt:
|
| 224 |
+
sys.exit()
|
3rd_version (latest)/Dump/injector.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// MnkLightning Injector
|
| 2 |
+
// Run this in the browser console on Monkeytype.com
|
| 3 |
+
|
| 4 |
+
(function () {
|
| 5 |
+
console.log("%c MnkLightning Injector Active ", "background: #222; color: #00ff00; font-size: 16px");
|
| 6 |
+
console.log("Press 'Insert' key to copy current words to clipboard for the Python script.");
|
| 7 |
+
|
| 8 |
+
function getVisibleText() {
|
| 9 |
+
const words = document.querySelectorAll('.word');
|
| 10 |
+
let textBuffer = [];
|
| 11 |
+
|
| 12 |
+
words.forEach(word => {
|
| 13 |
+
let wordText = "";
|
| 14 |
+
word.querySelectorAll('letter').forEach(letter => {
|
| 15 |
+
wordText += letter.textContent;
|
| 16 |
+
});
|
| 17 |
+
textBuffer.push(wordText);
|
| 18 |
+
});
|
| 19 |
+
|
| 20 |
+
return textBuffer.join(' ');
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
window.addEventListener('keydown', (e) => {
|
| 24 |
+
if (e.key === 'Insert') {
|
| 25 |
+
e.preventDefault();
|
| 26 |
+
const text = getVisibleText();
|
| 27 |
+
|
| 28 |
+
// Modern clipboard API
|
| 29 |
+
navigator.clipboard.writeText(text).then(() => {
|
| 30 |
+
console.log(`%c Copied ${text.length} chars to clipboard! `, "color: #00ff00");
|
| 31 |
+
console.log("Now start the Python script and press the trigger key.");
|
| 32 |
+
|
| 33 |
+
// Visual feedback
|
| 34 |
+
const notification = document.createElement('div');
|
| 35 |
+
notification.textContent = "MnkLightning: Text Copied!";
|
| 36 |
+
notification.style.cssText = `
|
| 37 |
+
position: fixed;
|
| 38 |
+
top: 20px;
|
| 39 |
+
right: 20px;
|
| 40 |
+
background: #333;
|
| 41 |
+
color: #fff;
|
| 42 |
+
padding: 10px 20px;
|
| 43 |
+
border-radius: 5px;
|
| 44 |
+
z-index: 9999;
|
| 45 |
+
font-family: monospace;
|
| 46 |
+
transition: opacity 0.5s;
|
| 47 |
+
`;
|
| 48 |
+
document.body.appendChild(notification);
|
| 49 |
+
setTimeout(() => {
|
| 50 |
+
notification.style.opacity = '0';
|
| 51 |
+
setTimeout(() => notification.remove(), 500);
|
| 52 |
+
}, 2000);
|
| 53 |
+
}).catch(err => {
|
| 54 |
+
console.error("Failed to copy text: ", err);
|
| 55 |
+
});
|
| 56 |
+
}
|
| 57 |
+
});
|
| 58 |
+
|
| 59 |
+
// Optional: Auto-copy on load if words are present
|
| 60 |
+
// setTimeout(() => {
|
| 61 |
+
// if (document.querySelector('.word')) console.log("Ready. Press Insert.");
|
| 62 |
+
// }, 1000);
|
| 63 |
+
|
| 64 |
+
})();
|
3rd_version (latest)/Dump/requirements.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
pyautogui==0.9.54
|
| 2 |
+
keyboard==0.13.5
|
| 3 |
+
pyperclip==1.8.2
|
3rd_version (latest)/Python/mnk_typer copy.py
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pyautogui
|
| 2 |
+
import keyboard
|
| 3 |
+
import time
|
| 4 |
+
import random
|
| 5 |
+
import pyperclip
|
| 6 |
+
import sys
|
| 7 |
+
|
| 8 |
+
# Remove default 0.1s pause after every PyAutoGUI call
|
| 9 |
+
pyautogui.PAUSE = 0
|
| 10 |
+
|
| 11 |
+
# === CONFIGURATION ===
|
| 12 |
+
CONFIG = {
|
| 13 |
+
"min_wpm": 200,
|
| 14 |
+
"max_wpm": 240,
|
| 15 |
+
# Key Hold Time (Seconds)
|
| 16 |
+
"min_key_hold": 0.01,
|
| 17 |
+
"max_key_hold": 0.04,
|
| 18 |
+
|
| 19 |
+
# Imperfection Rates (0.0 to 1.0)
|
| 20 |
+
"wrong_char_rate": 0.015, # 1.5% chance
|
| 21 |
+
"adjacent_key_rate": 0.01, # 1.0% chance
|
| 22 |
+
"double_letter_rate": 0.005, # 0.5% chance
|
| 23 |
+
"skip_letter_rate": 0.002, # 0.2% chance
|
| 24 |
+
"transpose_rate": 0.005, # 0.5% chance
|
| 25 |
+
|
| 26 |
+
"hesitation_rate": 0.02, # 2% chance to hesitate
|
| 27 |
+
"burst_rate": 0.15, # 15% chance to speed up (burst)
|
| 28 |
+
"insane_burst_rate": 0.05, # 5% chance for fast burst (was causing issues at higher rates)
|
| 29 |
+
|
| 30 |
+
"permanent_skip_rate": 0, # Disabled (causes invalid mostly)
|
| 31 |
+
"permanent_multi_skip_rate": 0,
|
| 32 |
+
|
| 33 |
+
# Timing Multipliers
|
| 34 |
+
"hesitation_multiplier": 2.0, # Reduced from 2.5x to be less jarring
|
| 35 |
+
"burst_speed_multiplier": 0.5, # 0.5x delay (2x speed) during burst
|
| 36 |
+
"post_mistake_pause": 0.3, # Reduced pause
|
| 37 |
+
"word_start_slowdown": 1.1, # Subtle slowdown
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
# QWERTY Adjacency Map
|
| 41 |
+
ADJACENT_KEYS = {
|
| 42 |
+
'a': 'qwsz', 'b': 'vghn', 'c': 'xdfv', 'd': 'serfcx', 'e': 'wsdr',
|
| 43 |
+
'f': 'drtgvc', 'g': 'ftyhbv', 'h': 'gyujnb', 'i': 'ujko', 'j': 'huikmn',
|
| 44 |
+
'k': 'jiolm', 'l': 'kop', 'm': 'njk', 'n': 'bhjm', 'o': 'iklp',
|
| 45 |
+
'p': 'ol', 'q': 'wa', 'r': 'edft', 's': 'awedxz', 't': 'rfgy',
|
| 46 |
+
'u': 'yhji', 'v': 'cfgb', 'w': 'qase', 'x': 'zsdc', 'y': 'tghu',
|
| 47 |
+
'z': 'asx'
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
def get_keystroke_delay(wpm, in_burst=False):
|
| 51 |
+
"""Calculates delay between keystrokes based on WPM."""
|
| 52 |
+
cpm = wpm * 5
|
| 53 |
+
# Standard formula: 60 seconds / chars per minute = seconds per char
|
| 54 |
+
base_delay = 60 / cpm
|
| 55 |
+
|
| 56 |
+
if in_burst:
|
| 57 |
+
# Bursts should be FASTER (reduced delay)
|
| 58 |
+
base_delay *= CONFIG["burst_speed_multiplier"]
|
| 59 |
+
|
| 60 |
+
# Add noise (+/- 20%)
|
| 61 |
+
variance = base_delay * 0.20
|
| 62 |
+
noise = random.uniform(-variance, variance)
|
| 63 |
+
return max(0.005, base_delay + noise)
|
| 64 |
+
|
| 65 |
+
def get_adjacent_key(char):
|
| 66 |
+
"""Returns a key adjacent to the given char on QWERTY layout."""
|
| 67 |
+
char_lower = char.lower()
|
| 68 |
+
if char_lower in ADJACENT_KEYS:
|
| 69 |
+
adj = random.choice(ADJACENT_KEYS[char_lower])
|
| 70 |
+
return adj.upper() if char.isupper() else adj
|
| 71 |
+
return char
|
| 72 |
+
|
| 73 |
+
def type_char(char):
|
| 74 |
+
"""Types a single character with human-like key hold duration."""
|
| 75 |
+
# Handle special characters or shift needs
|
| 76 |
+
try:
|
| 77 |
+
pyautogui.keyDown(char)
|
| 78 |
+
time.sleep(random.uniform(CONFIG["min_key_hold"], CONFIG["max_key_hold"]))
|
| 79 |
+
pyautogui.keyUp(char)
|
| 80 |
+
except:
|
| 81 |
+
# Fallback for complex chars
|
| 82 |
+
pyautogui.write(char)
|
| 83 |
+
|
| 84 |
+
def simulate_backspace(count=1):
|
| 85 |
+
"""Simulates pressing backspace with hold time."""
|
| 86 |
+
for _ in range(count):
|
| 87 |
+
pyautogui.keyDown('backspace')
|
| 88 |
+
time.sleep(random.uniform(CONFIG["min_key_hold"], CONFIG["max_key_hold"]))
|
| 89 |
+
pyautogui.keyUp('backspace')
|
| 90 |
+
time.sleep(random.uniform(0.05, 0.1))
|
| 91 |
+
|
| 92 |
+
def mnk_typer():
|
| 93 |
+
print("=== MnkLightning Python Automation ===")
|
| 94 |
+
print("1. Copy text from Monkeytype using injector.js (Press Insert in browser)")
|
| 95 |
+
print("2. Focus the browser window")
|
| 96 |
+
print("3. Press 'Insert' to START typing")
|
| 97 |
+
print("4. Press 'Esc' to STOP")
|
| 98 |
+
print("Waiting for trigger...")
|
| 99 |
+
|
| 100 |
+
while True:
|
| 101 |
+
if keyboard.is_pressed('esc'):
|
| 102 |
+
print("\nExiting...")
|
| 103 |
+
sys.exit()
|
| 104 |
+
|
| 105 |
+
if keyboard.is_pressed('insert'):
|
| 106 |
+
# Debounce
|
| 107 |
+
time.sleep(0.5)
|
| 108 |
+
|
| 109 |
+
# Get text from clipboard
|
| 110 |
+
text = pyperclip.paste()
|
| 111 |
+
if not text:
|
| 112 |
+
print("Clipboard empty! extraction failed?")
|
| 113 |
+
continue
|
| 114 |
+
|
| 115 |
+
print(f"Typing {len(text)} characters...")
|
| 116 |
+
|
| 117 |
+
wpm = random.randint(CONFIG["min_wpm"], CONFIG["max_wpm"])
|
| 118 |
+
print(f"Target WPM: {wpm}")
|
| 119 |
+
|
| 120 |
+
# State
|
| 121 |
+
idx = 0
|
| 122 |
+
burst_remaining = 0
|
| 123 |
+
|
| 124 |
+
try:
|
| 125 |
+
while idx < len(text):
|
| 126 |
+
if keyboard.is_pressed('esc'):
|
| 127 |
+
return
|
| 128 |
+
|
| 129 |
+
char = text[idx]
|
| 130 |
+
delay = get_keystroke_delay(wpm, burst_remaining > 0)
|
| 131 |
+
|
| 132 |
+
if burst_remaining > 0:
|
| 133 |
+
burst_remaining -= 1
|
| 134 |
+
|
| 135 |
+
# === IMPERFECTIONS ===
|
| 136 |
+
|
| 137 |
+
# 1. Hesitation
|
| 138 |
+
if random.random() < CONFIG["hesitation_rate"]:
|
| 139 |
+
delay *= CONFIG["hesitation_multiplier"]
|
| 140 |
+
|
| 141 |
+
# 2. Burst Mode
|
| 142 |
+
if burst_remaining == 0 and random.random() < CONFIG["burst_rate"]:
|
| 143 |
+
burst_remaining = 5
|
| 144 |
+
|
| 145 |
+
# 3. Insane Burst Mode (Type 3-5 chars very quickly)
|
| 146 |
+
if random.random() < CONFIG["insane_burst_rate"]:
|
| 147 |
+
# Random 3-5 characters as requested
|
| 148 |
+
burst_len = random.randint(3, 5)
|
| 149 |
+
for _ in range(burst_len):
|
| 150 |
+
if idx >= len(text): break
|
| 151 |
+
pyautogui.write(text[idx])
|
| 152 |
+
idx += 1
|
| 153 |
+
# Delay increased from 0.002 to ~0.025s to smooth out graph
|
| 154 |
+
# (0.002 was causing "parabolic" spikes and invalid WPM)
|
| 155 |
+
time.sleep(random.uniform(0.020, 0.030))
|
| 156 |
+
continue
|
| 157 |
+
|
| 158 |
+
# 4. Permanent Skip (Type nothing, effectively skipping the char)
|
| 159 |
+
if random.random() < CONFIG["permanent_skip_rate"]:
|
| 160 |
+
idx += 1
|
| 161 |
+
time.sleep(delay)
|
| 162 |
+
continue
|
| 163 |
+
|
| 164 |
+
# 4. Permanent Multi-Skip (Skip 2-3 chars)
|
| 165 |
+
if random.random() < CONFIG["permanent_multi_skip_rate"]:
|
| 166 |
+
skip_count = random.randint(2, 3)
|
| 167 |
+
idx += skip_count
|
| 168 |
+
time.sleep(delay)
|
| 169 |
+
continue
|
| 170 |
+
|
| 171 |
+
# 5. Wrong Character (Type random, then fix)
|
| 172 |
+
if random.random() < CONFIG["wrong_char_rate"] and char.isalnum():
|
| 173 |
+
wrong = random.choice("abcdefghijklmnopqrstuvwxyz")
|
| 174 |
+
type_char(wrong)
|
| 175 |
+
time.sleep(delay * 2)
|
| 176 |
+
simulate_backspace(1)
|
| 177 |
+
time.sleep(delay)
|
| 178 |
+
# Don't increment idx, we need to type correct char
|
| 179 |
+
|
| 180 |
+
# 6. Adjacent Key (Type neighbor, then fix)
|
| 181 |
+
elif random.random() < CONFIG["adjacent_key_rate"] and char.isalpha():
|
| 182 |
+
adj = get_adjacent_key(char)
|
| 183 |
+
type_char(adj)
|
| 184 |
+
time.sleep(delay * 1.5)
|
| 185 |
+
simulate_backspace(1)
|
| 186 |
+
time.sleep(delay)
|
| 187 |
+
|
| 188 |
+
# 7. Skip Letter (Type next char, realize, backspace 2, type current)
|
| 189 |
+
elif random.random() < CONFIG["skip_letter_rate"] and idx + 1 < len(text):
|
| 190 |
+
next_char = text[idx+1]
|
| 191 |
+
type_char(next_char)
|
| 192 |
+
time.sleep(delay * 2.5)
|
| 193 |
+
simulate_backspace(1)
|
| 194 |
+
time.sleep(delay)
|
| 195 |
+
# Now continue loop to type 'char'
|
| 196 |
+
|
| 197 |
+
# 8. Double Letter (Type char twice, delete one)
|
| 198 |
+
elif random.random() < CONFIG["double_letter_rate"] and char.isalpha():
|
| 199 |
+
type_char(char)
|
| 200 |
+
time.sleep(0.05)
|
| 201 |
+
type_char(char) # Double
|
| 202 |
+
time.sleep(delay * 2)
|
| 203 |
+
simulate_backspace(1)
|
| 204 |
+
idx += 1 # We kept one valid char
|
| 205 |
+
time.sleep(delay)
|
| 206 |
+
continue
|
| 207 |
+
|
| 208 |
+
# === TYPING ===
|
| 209 |
+
type_char(char)
|
| 210 |
+
idx += 1
|
| 211 |
+
|
| 212 |
+
# Word boundary pause
|
| 213 |
+
if char == ' ':
|
| 214 |
+
delay *= CONFIG["word_start_slowdown"]
|
| 215 |
+
|
| 216 |
+
time.sleep(delay)
|
| 217 |
+
|
| 218 |
+
except KeyboardInterrupt:
|
| 219 |
+
pass
|
| 220 |
+
|
| 221 |
+
print("\nTyping complete.")
|
| 222 |
+
time.sleep(1) # Prevent double trigger
|
| 223 |
+
|
| 224 |
+
if __name__ == "__main__":
|
| 225 |
+
try:
|
| 226 |
+
mnk_typer()
|
| 227 |
+
except KeyboardInterrupt:
|
| 228 |
+
sys.exit()
|
4th_version/0.js
ADDED
|
@@ -0,0 +1,367 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
(function () {
|
| 2 |
+
console.log("%c Monkeytype Command Typer (Human-Like) v2 ", "background: #222; color: #00ff00; font-size: 20px");
|
| 3 |
+
|
| 4 |
+
const CONFIG = {
|
| 5 |
+
min_wpm: 300,
|
| 6 |
+
max_wpm: 340,
|
| 7 |
+
// Key Hold Time (Seconds)
|
| 8 |
+
min_key_hold: 0.01,
|
| 9 |
+
max_key_hold: 0.04,
|
| 10 |
+
|
| 11 |
+
// Imperfection Rates (0.0 to 1.0)
|
| 12 |
+
wrong_char_rate: 0.005,
|
| 13 |
+
adjacent_key_rate: 0.005,
|
| 14 |
+
double_letter_rate: 0.001,
|
| 15 |
+
skip_letter_rate: 0.001,
|
| 16 |
+
|
| 17 |
+
hesitation_rate: 0.02,
|
| 18 |
+
burst_rate: 0.08,
|
| 19 |
+
insane_burst_rate: 0.001,
|
| 20 |
+
|
| 21 |
+
// Timing Multipliers
|
| 22 |
+
hesitation_multiplier: 2.5,
|
| 23 |
+
burst_speed_multiplier: 0.6,
|
| 24 |
+
post_mistake_pause: 0.4, // Seconds
|
| 25 |
+
word_start_slowdown: 1.2,
|
| 26 |
+
};
|
| 27 |
+
|
| 28 |
+
// QWERTY keyboard adjacency map for realistic typos
|
| 29 |
+
const ADJACENT_KEYS = {
|
| 30 |
+
'a': ['q', 'w', 's', 'z'],
|
| 31 |
+
'b': ['v', 'g', 'h', 'n'],
|
| 32 |
+
'c': ['x', 'd', 'f', 'v'],
|
| 33 |
+
'd': ['s', 'e', 'r', 'f', 'c', 'x'],
|
| 34 |
+
'e': ['w', 's', 'd', 'r'],
|
| 35 |
+
'f': ['d', 'r', 't', 'g', 'v', 'c'],
|
| 36 |
+
'g': ['f', 't', 'y', 'h', 'b', 'v'],
|
| 37 |
+
'h': ['g', 'y', 'u', 'j', 'n', 'b'],
|
| 38 |
+
'i': ['u', 'j', 'k', 'o'],
|
| 39 |
+
'j': ['h', 'u', 'i', 'k', 'm', 'n'],
|
| 40 |
+
'k': ['j', 'i', 'o', 'l', 'm'],
|
| 41 |
+
'l': ['k', 'o', 'p'],
|
| 42 |
+
'm': ['n', 'j', 'k'],
|
| 43 |
+
'n': ['b', 'h', 'j', 'm'],
|
| 44 |
+
'o': ['i', 'k', 'l', 'p'],
|
| 45 |
+
'p': ['o', 'l'],
|
| 46 |
+
'q': ['w', 'a'],
|
| 47 |
+
'r': ['e', 'd', 'f', 't'],
|
| 48 |
+
's': ['a', 'w', 'e', 'd', 'x', 'z'],
|
| 49 |
+
't': ['r', 'f', 'g', 'y'],
|
| 50 |
+
'u': ['y', 'h', 'j', 'i'],
|
| 51 |
+
'v': ['c', 'f', 'g', 'b'],
|
| 52 |
+
'w': ['q', 'a', 's', 'e'],
|
| 53 |
+
'x': ['z', 's', 'd', 'c'],
|
| 54 |
+
'y': ['t', 'g', 'h', 'u'],
|
| 55 |
+
'z': ['a', 's', 'x'],
|
| 56 |
+
};
|
| 57 |
+
|
| 58 |
+
let isArmed = true;
|
| 59 |
+
let inBurstMode = false;
|
| 60 |
+
let inInsaneBurstMode = false;
|
| 61 |
+
let burstCharsRemaining = 0;
|
| 62 |
+
let totalCharsTyped = 0;
|
| 63 |
+
let recentMistake = false;
|
| 64 |
+
|
| 65 |
+
function randomRange(min, max) {
|
| 66 |
+
return Math.random() * (max - min) + min;
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
function sleep(ms) {
|
| 70 |
+
return new Promise(resolve => setTimeout(resolve, ms));
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
// Type a single character with key hold simulation
|
| 74 |
+
async function typeChar(char) {
|
| 75 |
+
const target = document.activeElement || document.body;
|
| 76 |
+
const keyConfig = {
|
| 77 |
+
key: char,
|
| 78 |
+
code: char === ' ' ? 'Space' : `Key${char.toUpperCase()}`,
|
| 79 |
+
bubbles: true,
|
| 80 |
+
cancelable: true,
|
| 81 |
+
view: window
|
| 82 |
+
};
|
| 83 |
+
|
| 84 |
+
target.dispatchEvent(new KeyboardEvent('keydown', keyConfig));
|
| 85 |
+
target.dispatchEvent(new KeyboardEvent('keypress', keyConfig));
|
| 86 |
+
document.execCommand('insertText', false, char);
|
| 87 |
+
|
| 88 |
+
// Simulate key hold
|
| 89 |
+
const holdTime = randomRange(CONFIG.min_key_hold, CONFIG.max_key_hold) * 1000;
|
| 90 |
+
await sleep(holdTime);
|
| 91 |
+
|
| 92 |
+
target.dispatchEvent(new KeyboardEvent('keyup', keyConfig));
|
| 93 |
+
|
| 94 |
+
totalCharsTyped++;
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
// Single backspace with key hold simulation
|
| 98 |
+
async function typeBackspace() {
|
| 99 |
+
const target = document.activeElement || document.body;
|
| 100 |
+
const bsConfig = { key: 'Backspace', code: 'Backspace', bubbles: true, cancelable: true, view: window };
|
| 101 |
+
|
| 102 |
+
target.dispatchEvent(new KeyboardEvent('keydown', bsConfig));
|
| 103 |
+
document.execCommand('delete', false, null);
|
| 104 |
+
|
| 105 |
+
const holdTime = randomRange(CONFIG.min_key_hold, CONFIG.max_key_hold) * 1000;
|
| 106 |
+
await sleep(holdTime);
|
| 107 |
+
|
| 108 |
+
target.dispatchEvent(new KeyboardEvent('keyup', bsConfig));
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
// Get adjacent key for realistic typo
|
| 112 |
+
function getAdjacentKey(char) {
|
| 113 |
+
const lowerChar = char.toLowerCase();
|
| 114 |
+
const adjacent = ADJACENT_KEYS[lowerChar];
|
| 115 |
+
if (adjacent && adjacent.length > 0) {
|
| 116 |
+
const randomAdj = adjacent[Math.floor(Math.random() * adjacent.length)];
|
| 117 |
+
return char === char.toUpperCase() ? randomAdj.toUpperCase() : randomAdj;
|
| 118 |
+
}
|
| 119 |
+
return char; // Fallback to same char if no adjacent found
|
| 120 |
+
}
|
| 121 |
+
|
| 122 |
+
// Get random wrong character
|
| 123 |
+
function getRandomChar() {
|
| 124 |
+
const chars = "abcdefghijklmnopqrstuvwxyz";
|
| 125 |
+
return chars.charAt(Math.floor(Math.random() * chars.length));
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
// Calculate keystroke delay
|
| 129 |
+
function getKeystrokeDelay() {
|
| 130 |
+
const currentWPM = Math.floor(Math.random() * (CONFIG.max_wpm - CONFIG.min_wpm + 1)) + CONFIG.min_wpm;
|
| 131 |
+
let baseDelay = 60000 / (currentWPM * 5);
|
| 132 |
+
|
| 133 |
+
// Apply burst mode (faster typing)
|
| 134 |
+
if (inBurstMode && burstCharsRemaining > 0) {
|
| 135 |
+
let multiplier = CONFIG.burst_speed_multiplier;
|
| 136 |
+
if (inInsaneBurstMode) {
|
| 137 |
+
multiplier *= 0.6; // Even faster for insane burst
|
| 138 |
+
}
|
| 139 |
+
baseDelay *= multiplier;
|
| 140 |
+
|
| 141 |
+
burstCharsRemaining--;
|
| 142 |
+
if (burstCharsRemaining === 0) {
|
| 143 |
+
inBurstMode = false;
|
| 144 |
+
inInsaneBurstMode = false;
|
| 145 |
+
}
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
// Add variance
|
| 149 |
+
const variance = baseDelay * 0.25;
|
| 150 |
+
const noise = (Math.random() * variance * 2) - variance;
|
| 151 |
+
|
| 152 |
+
return Math.max(8, baseDelay + noise);
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
// Get current word's remaining untyped text
|
| 156 |
+
function getCurrentWordText() {
|
| 157 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 158 |
+
if (!activeWord) return null;
|
| 159 |
+
|
| 160 |
+
const letters = activeWord.querySelectorAll('letter');
|
| 161 |
+
let text = "";
|
| 162 |
+
let foundUntyped = false;
|
| 163 |
+
|
| 164 |
+
for (const letter of letters) {
|
| 165 |
+
if (!letter.classList.contains('correct') && !letter.classList.contains('incorrect')) {
|
| 166 |
+
foundUntyped = true;
|
| 167 |
+
}
|
| 168 |
+
if (foundUntyped) {
|
| 169 |
+
text += letter.textContent;
|
| 170 |
+
}
|
| 171 |
+
}
|
| 172 |
+
|
| 173 |
+
return text;
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
// Check if we're at the start of a word
|
| 177 |
+
function isWordStart() {
|
| 178 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 179 |
+
if (!activeWord) return false;
|
| 180 |
+
const typed = activeWord.querySelectorAll('letter.correct, letter.incorrect');
|
| 181 |
+
return typed.length === 0;
|
| 182 |
+
}
|
| 183 |
+
|
| 184 |
+
// === MISTAKE SIMULATION FUNCTIONS ===
|
| 185 |
+
|
| 186 |
+
// Type wrong character and correct it
|
| 187 |
+
async function simulateWrongChar(correctChar) {
|
| 188 |
+
const wrongChar = getRandomChar();
|
| 189 |
+
await typeChar(wrongChar);
|
| 190 |
+
await sleep(getKeystrokeDelay() * 2.5);
|
| 191 |
+
await typeBackspace();
|
| 192 |
+
await sleep(getKeystrokeDelay() * 1.5);
|
| 193 |
+
recentMistake = true;
|
| 194 |
+
}
|
| 195 |
+
|
| 196 |
+
// Type adjacent key typo and correct it
|
| 197 |
+
async function simulateAdjacentKeyTypo(correctChar) {
|
| 198 |
+
const adjacentChar = getAdjacentKey(correctChar);
|
| 199 |
+
if (adjacentChar !== correctChar) {
|
| 200 |
+
await typeChar(adjacentChar);
|
| 201 |
+
await sleep(getKeystrokeDelay() * 2.2);
|
| 202 |
+
await typeBackspace();
|
| 203 |
+
await sleep(getKeystrokeDelay() * 1.3);
|
| 204 |
+
recentMistake = true;
|
| 205 |
+
}
|
| 206 |
+
}
|
| 207 |
+
|
| 208 |
+
// Double letter mistake
|
| 209 |
+
async function simulateDoubleLetter(char) {
|
| 210 |
+
// Type the correct char first (assumed done by caller loop usually, but here we do it)
|
| 211 |
+
// Actually, the main loop calls this INSTEAD of typing normally if it hits.
|
| 212 |
+
// But logic in main loop: if we match doubleLetterRate, we want to type char + char.
|
| 213 |
+
|
| 214 |
+
await typeChar(char);
|
| 215 |
+
await sleep(getKeystrokeDelay() * 0.3); // Very fast double tap
|
| 216 |
+
await typeChar(char);
|
| 217 |
+
|
| 218 |
+
// Pause to realize mistake
|
| 219 |
+
await sleep(getKeystrokeDelay() * 2.0);
|
| 220 |
+
// Delete the extra
|
| 221 |
+
await typeBackspace();
|
| 222 |
+
|
| 223 |
+
await sleep(getKeystrokeDelay() * 1.2);
|
| 224 |
+
recentMistake = true;
|
| 225 |
+
}
|
| 226 |
+
|
| 227 |
+
// Main typing loop with human imperfections
|
| 228 |
+
async function autoTypeLoop() {
|
| 229 |
+
console.log("Starting human-like auto-type loop v2...");
|
| 230 |
+
|
| 231 |
+
let wordCount = 0;
|
| 232 |
+
|
| 233 |
+
while (true) {
|
| 234 |
+
const currentWordText = getCurrentWordText();
|
| 235 |
+
|
| 236 |
+
if (currentWordText === null) {
|
| 237 |
+
console.log(`Auto-type complete! Typed ${wordCount} words, ${totalCharsTyped} characters.`);
|
| 238 |
+
break;
|
| 239 |
+
}
|
| 240 |
+
|
| 241 |
+
if (currentWordText.length === 0) {
|
| 242 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 243 |
+
const nextWord = activeWord ? activeWord.nextElementSibling : null;
|
| 244 |
+
|
| 245 |
+
if (!nextWord || !nextWord.classList.contains('word')) {
|
| 246 |
+
await sleep(50);
|
| 247 |
+
const stillActive = document.querySelector('#words .word.active');
|
| 248 |
+
if (!stillActive) {
|
| 249 |
+
console.log(`Auto-type complete! Typed ${wordCount} words.`);
|
| 250 |
+
break;
|
| 251 |
+
}
|
| 252 |
+
continue;
|
| 253 |
+
}
|
| 254 |
+
|
| 255 |
+
await typeChar(' ');
|
| 256 |
+
wordCount++;
|
| 257 |
+
|
| 258 |
+
// Longer pause between words
|
| 259 |
+
let delay = getKeystrokeDelay() * 1.4;
|
| 260 |
+
await sleep(delay);
|
| 261 |
+
continue;
|
| 262 |
+
}
|
| 263 |
+
|
| 264 |
+
const char = currentWordText[0];
|
| 265 |
+
const nextChar = currentWordText.length > 1 ? currentWordText[1] : null;
|
| 266 |
+
let delay = getKeystrokeDelay();
|
| 267 |
+
|
| 268 |
+
// === APPLY HUMAN IMPERFECTIONS ===
|
| 269 |
+
|
| 270 |
+
// Slow start to words
|
| 271 |
+
if (isWordStart()) {
|
| 272 |
+
delay *= CONFIG.word_start_slowdown;
|
| 273 |
+
}
|
| 274 |
+
|
| 275 |
+
// Random hesitation (thinking pause)
|
| 276 |
+
if (Math.random() < CONFIG.hesitation_rate) {
|
| 277 |
+
delay *= CONFIG.hesitation_multiplier;
|
| 278 |
+
}
|
| 279 |
+
|
| 280 |
+
// Post-mistake recovery pause
|
| 281 |
+
if (recentMistake) {
|
| 282 |
+
await sleep(CONFIG.post_mistake_pause * 1000); // Fixed pause in seconds
|
| 283 |
+
recentMistake = false;
|
| 284 |
+
}
|
| 285 |
+
|
| 286 |
+
// Trigger burst mode
|
| 287 |
+
// Insane Burst (Higher priority / check first or separate?)
|
| 288 |
+
if (!inBurstMode && Math.random() < CONFIG.insane_burst_rate) {
|
| 289 |
+
inBurstMode = true;
|
| 290 |
+
inInsaneBurstMode = true;
|
| 291 |
+
burstCharsRemaining = 12; // Longer burst
|
| 292 |
+
} else if (!inBurstMode && Math.random() < CONFIG.burst_rate) {
|
| 293 |
+
inBurstMode = true;
|
| 294 |
+
burstCharsRemaining = 5;
|
| 295 |
+
}
|
| 296 |
+
|
| 297 |
+
// Skip letter imperfection
|
| 298 |
+
if (/[a-zA-Z]/.test(char) && Math.random() < CONFIG.skip_letter_rate && nextChar) {
|
| 299 |
+
// Type next char instead
|
| 300 |
+
await typeChar(nextChar);
|
| 301 |
+
await sleep(getKeystrokeDelay() * 2.5);
|
| 302 |
+
await typeBackspace();
|
| 303 |
+
await sleep(getKeystrokeDelay() * 1.3);
|
| 304 |
+
recentMistake = true;
|
| 305 |
+
// Now type correct char
|
| 306 |
+
await typeChar(char);
|
| 307 |
+
await sleep(delay);
|
| 308 |
+
continue;
|
| 309 |
+
}
|
| 310 |
+
|
| 311 |
+
// Double letter
|
| 312 |
+
if (/[a-zA-Z]/.test(char) && Math.random() < CONFIG.double_letter_rate) {
|
| 313 |
+
await simulateDoubleLetter(char);
|
| 314 |
+
await sleep(delay);
|
| 315 |
+
continue;
|
| 316 |
+
}
|
| 317 |
+
|
| 318 |
+
// Adjacent key typo
|
| 319 |
+
if (/[a-zA-Z]/.test(char) && Math.random() < CONFIG.adjacent_key_rate) {
|
| 320 |
+
await simulateAdjacentKeyTypo(char);
|
| 321 |
+
// After fixing, we still need to type the correct char, which is handled at end of loop?
|
| 322 |
+
// Wait, simulateAdjacentKeyTypo fixes it but doesn't type the correct one?
|
| 323 |
+
// Let's check original logic.
|
| 324 |
+
// Original: simulateAdjacentKeyTypo types wrong, deletes. Main loop falls through to type correct char.
|
| 325 |
+
}
|
| 326 |
+
|
| 327 |
+
// Wrong character
|
| 328 |
+
if (/[a-zA-Z]/.test(char) && Math.random() < CONFIG.wrong_char_rate) {
|
| 329 |
+
await simulateWrongChar(char);
|
| 330 |
+
// Same pattern: types wrong, deletes. Main loop falls through.
|
| 331 |
+
}
|
| 332 |
+
|
| 333 |
+
// Type the correct character
|
| 334 |
+
await typeChar(char);
|
| 335 |
+
await sleep(delay);
|
| 336 |
+
}
|
| 337 |
+
}
|
| 338 |
+
|
| 339 |
+
const triggerHandler = (e) => {
|
| 340 |
+
if (!isArmed) return;
|
| 341 |
+
|
| 342 |
+
if (e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey) {
|
| 343 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 344 |
+
if (!activeWord) return;
|
| 345 |
+
|
| 346 |
+
const firstLetterElement = activeWord.querySelector('letter');
|
| 347 |
+
const firstLetter = firstLetterElement ? firstLetterElement.textContent : null;
|
| 348 |
+
|
| 349 |
+
if (firstLetter && e.key === firstLetter) {
|
| 350 |
+
isArmed = false;
|
| 351 |
+
window.removeEventListener('keydown', triggerHandler);
|
| 352 |
+
|
| 353 |
+
console.log("Trigger detected. Starting Human-Like Command Typer v2...");
|
| 354 |
+
console.log("Config:", CONFIG);
|
| 355 |
+
|
| 356 |
+
// Start delay? Original had CONFIG.startDelay. New config doesn't have it.
|
| 357 |
+
// We'll default to a small delay or 0.
|
| 358 |
+
setTimeout(() => {
|
| 359 |
+
autoTypeLoop();
|
| 360 |
+
}, 100);
|
| 361 |
+
}
|
| 362 |
+
}
|
| 363 |
+
};
|
| 364 |
+
|
| 365 |
+
window.addEventListener('keydown', triggerHandler);
|
| 366 |
+
console.log("READY! Type the first letter to activate Human-Like Mode v2.");
|
| 367 |
+
})();
|
Dump/image.png
ADDED
|
Git LFS Details
|
LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2026 callmerem
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# MnkLightning
|
| 2 |
+
|
| 3 |
+
[](https://opensource.org/licenses/MIT)
|
| 4 |
+
[](https://www.python.org/)
|
| 5 |
+
[](https://developer.mozilla.org/en-US/docs/Web/JavaScript)
|
| 6 |
+
[](#)
|
| 7 |
+
[](https://monkeytype.com/)
|
| 8 |
+
|
| 9 |
+
MonkeyLightning is a performance-oriented automation script designed for Monkeytype. It implements sophisticated human-like typing behavior with real OS-level keyboard events to bypass bot detection.
|
| 10 |
+
|
| 11 |
+
## Technical Overview
|
| 12 |
+
|
| 13 |
+
This v3.0 release shifts from client-side JavaScript to **Python-based automation (PyAutoGUI)**. This creates "trusted" keyboard events that are indistinguishable from real human input to the browser.
|
| 14 |
+
|
| 15 |
+
- **`mnk_typer.py`**: Python script that simulates real keyboard input.
|
| 16 |
+
- **`injector.js`**: Helper script to bridge text from browser to Python.
|
| 17 |
+
- **Human-like Imperfections**: Full suite of 12+ imperfection types (typos, hesitations, fatigue).
|
| 18 |
+
|
| 19 |
+
## Usage Instructions (Bypass Method)
|
| 20 |
+
|
| 21 |
+
The new bypass method uses a 2-step process:
|
| 22 |
+
|
| 23 |
+
### Step 1: Setup
|
| 24 |
+
|
| 25 |
+
1. Install Python (if not installed).
|
| 26 |
+
2. Install required packages:
|
| 27 |
+
```bash
|
| 28 |
+
pip install -r requirements.txt
|
| 29 |
+
```
|
| 30 |
+
|
| 31 |
+
### Step 2: Run the Bot
|
| 32 |
+
|
| 33 |
+
1. **Open Monkeytype** in your browser.
|
| 34 |
+
2. **Open Developer Console** (`F12` or `Ctrl+Shift+J`).
|
| 35 |
+
3. **Paste & Run** the contents of [`injector.js`](./injector.js) into the console.
|
| 36 |
+
- You should see a message: "MnkLightning Injector Active".
|
| 37 |
+
4. **Run the Python script** in a terminal:
|
| 38 |
+
```bash
|
| 39 |
+
python mnk_typer.py
|
| 40 |
+
```
|
| 41 |
+
5. **Trigger the Bot**:
|
| 42 |
+
- Focus the Monkeytype window.
|
| 43 |
+
- Press **`Insert`** key to copy current words to clipboard.
|
| 44 |
+
- Press **`Insert`** key again to START typing.
|
| 45 |
+
- Press **`Esc`** to stop at any time.
|
| 46 |
+
|
| 47 |
+
## Configuration
|
| 48 |
+
|
| 49 |
+
You can customize the bot's behavior in `mnk_typer.py`:
|
| 50 |
+
|
| 51 |
+
```python
|
| 52 |
+
CONFIG = {
|
| 53 |
+
"min_wpm": 310,
|
| 54 |
+
"max_wpm": 550,
|
| 55 |
+
|
| 56 |
+
# Imperfections (0.0 - 1.0)
|
| 57 |
+
"wrong_char_rate": 0.025,
|
| 58 |
+
"adjacent_key_rate": 0.02,
|
| 59 |
+
"hesitation_rate": 0.04,
|
| 60 |
+
"burst_rate": 0.08,
|
| 61 |
+
|
| 62 |
+
# Timing
|
| 63 |
+
"hesitation_multiplier": 3.5,
|
| 64 |
+
"burst_speed_multiplier": 0.5,
|
| 65 |
+
}
|
| 66 |
+
```
|
| 67 |
+
|
| 68 |
+
## Disclaimer
|
| 69 |
+
|
| 70 |
+
This software is provided for educational and research purposes only. The authors do not encourage or condone the use of automation scripts on competitive platforms. Use at your own risk.
|
STRUCTURE.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
## Project Structure
|
| 2 |
+
|
| 3 |
+
```text
|
| 4 |
+
MonkeyType-lightning/
|
| 5 |
+
├── 2nd_version/
|
| 6 |
+
│ ├── 2nd_version.js
|
| 7 |
+
│ ├── README_v2.md
|
| 8 |
+
│ ├── script_candidate.js
|
| 9 |
+
│ └── script_final.js
|
| 10 |
+
├── 3rd_version (latest)/
|
| 11 |
+
│ ├── Dump/
|
| 12 |
+
│ │ ├── 1.py
|
| 13 |
+
│ │ ├── 2.py
|
| 14 |
+
│ │ ├── 3.py
|
| 15 |
+
│ │ ├── 4.py
|
| 16 |
+
│ │ ├── 5.py
|
| 17 |
+
│ │ ├── injector.js
|
| 18 |
+
│ │ └── requirements.txt
|
| 19 |
+
│ └── Python/
|
| 20 |
+
│ └── mnk_typer copy.py
|
| 21 |
+
├── 4th_version/
|
| 22 |
+
│ └── 0.js
|
| 23 |
+
├── Dump/
|
| 24 |
+
│ └── image.png
|
| 25 |
+
├── javascript/
|
| 26 |
+
│ ├── 0_candidate.js
|
| 27 |
+
│ ├── 1_variant.js
|
| 28 |
+
│ ├── 2_variant.js
|
| 29 |
+
│ ├── 3_variant.js
|
| 30 |
+
│ ├── 4_variant.js
|
| 31 |
+
│ ├── 5_variant.js
|
| 32 |
+
│ ├── 6_variant.js
|
| 33 |
+
│ ├── 7_variant.js
|
| 34 |
+
│ ├── candidate.js
|
| 35 |
+
│ ├── monkeytype_advanced.js
|
| 36 |
+
│ ├── monkeytype_auto_typer.js
|
| 37 |
+
│ ├── monkeytype_cheat.js
|
| 38 |
+
│ ├── monkeytype_custom_text.js
|
| 39 |
+
│ ├── monkeytype_legacy.js
|
| 40 |
+
│ ├── script_candidate copy.js
|
| 41 |
+
│ ├── script_candidate copy1.js
|
| 42 |
+
│ └── script_candidate copy2.js
|
| 43 |
+
├── .gitignore
|
| 44 |
+
├── 2026-02-08 13-03-16.mp4
|
| 45 |
+
├── injector.js
|
| 46 |
+
├── LICENSE
|
| 47 |
+
├── mnk_lightning_v3.js
|
| 48 |
+
├── mnk_typer.py
|
| 49 |
+
├── README.md
|
| 50 |
+
├── requirements.txt
|
| 51 |
+
└── TECHSTACK.md
|
| 52 |
+
```
|
TECHSTACK.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
## Techstack
|
| 2 |
+
|
| 3 |
+
Audit of **MonkeyType-lightning** project files (excluding environment and cache):
|
| 4 |
+
|
| 5 |
+
| File Type | Count | Size (KB) |
|
| 6 |
+
| :--- | :--- | :--- |
|
| 7 |
+
| JavaScript (.js) | 24 | 164.1 |
|
| 8 |
+
| Python (.py) | 7 | 53.6 |
|
| 9 |
+
| (no extension) | 2 | 1.1 |
|
| 10 |
+
| Markdown (.md) | 2 | 7.0 |
|
| 11 |
+
| Plain Text (.txt) | 2 | 0.1 |
|
| 12 |
+
| MP4 Video (.mp4) | 1 | 1,681.6 |
|
| 13 |
+
| PNG Image (.png) | 1 | 150.5 |
|
| 14 |
+
| **Total** | **39** | **2,058.0** |
|
injector.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// MnkLightning Injector
|
| 2 |
+
// Run this in the browser console on Monkeytype.com
|
| 3 |
+
|
| 4 |
+
(function () {
|
| 5 |
+
console.log("%c MnkLightning Injector Active ", "background: #222; color: #00ff00; font-size: 16px");
|
| 6 |
+
console.log("Press 'Insert' key to copy current words to clipboard for the Python script.");
|
| 7 |
+
|
| 8 |
+
function getVisibleText() {
|
| 9 |
+
const words = document.querySelectorAll('.word');
|
| 10 |
+
let textBuffer = [];
|
| 11 |
+
|
| 12 |
+
words.forEach(word => {
|
| 13 |
+
let wordText = "";
|
| 14 |
+
word.querySelectorAll('letter').forEach(letter => {
|
| 15 |
+
wordText += letter.textContent;
|
| 16 |
+
});
|
| 17 |
+
textBuffer.push(wordText);
|
| 18 |
+
});
|
| 19 |
+
|
| 20 |
+
return textBuffer.join(' ');
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
window.addEventListener('keydown', (e) => {
|
| 24 |
+
if (e.key === 'Insert') {
|
| 25 |
+
e.preventDefault();
|
| 26 |
+
const text = getVisibleText();
|
| 27 |
+
|
| 28 |
+
// Modern clipboard API
|
| 29 |
+
navigator.clipboard.writeText(text).then(() => {
|
| 30 |
+
console.log(`%c Copied ${text.length} chars to clipboard! `, "color: #00ff00");
|
| 31 |
+
console.log("Now start the Python script and press the trigger key.");
|
| 32 |
+
|
| 33 |
+
// Visual feedback
|
| 34 |
+
const notification = document.createElement('div');
|
| 35 |
+
notification.textContent = "MnkLightning: Text Copied!";
|
| 36 |
+
notification.style.cssText = `
|
| 37 |
+
position: fixed;
|
| 38 |
+
top: 20px;
|
| 39 |
+
right: 20px;
|
| 40 |
+
background: #333;
|
| 41 |
+
color: #fff;
|
| 42 |
+
padding: 10px 20px;
|
| 43 |
+
border-radius: 5px;
|
| 44 |
+
z-index: 9999;
|
| 45 |
+
font-family: monospace;
|
| 46 |
+
transition: opacity 0.5s;
|
| 47 |
+
`;
|
| 48 |
+
document.body.appendChild(notification);
|
| 49 |
+
setTimeout(() => {
|
| 50 |
+
notification.style.opacity = '0';
|
| 51 |
+
setTimeout(() => notification.remove(), 500);
|
| 52 |
+
}, 2000);
|
| 53 |
+
}).catch(err => {
|
| 54 |
+
console.error("Failed to copy text: ", err);
|
| 55 |
+
});
|
| 56 |
+
}
|
| 57 |
+
});
|
| 58 |
+
|
| 59 |
+
// Optional: Auto-copy on load if words are present
|
| 60 |
+
// setTimeout(() => {
|
| 61 |
+
// if (document.querySelector('.word')) console.log("Ready. Press Insert.");
|
| 62 |
+
// }, 1000);
|
| 63 |
+
|
| 64 |
+
})();
|
javascript/0_candidate.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
(function () {
|
| 2 |
+
console.log("%c Monkeytype Command Typer (execCommand) ", "background: #222; color: #ff0000; font-size: 20px");
|
| 3 |
+
|
| 4 |
+
const CONFIG = {
|
| 5 |
+
startDelay: 50,
|
| 6 |
+
typingDelay: 50,
|
| 7 |
+
};
|
| 8 |
+
|
| 9 |
+
let isArmed = true;
|
| 10 |
+
|
| 11 |
+
// EXECCOMMAND METHOD
|
| 12 |
+
// This often bypasses "isTrusted" checks because it simulates a browser action (paste/insert)
|
| 13 |
+
// rather than a raw key event.
|
| 14 |
+
function typeChar(char) {
|
| 15 |
+
// We use insertText which is a powerful way to simulate user input
|
| 16 |
+
document.execCommand('insertText', false, char);
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
async function autoType(text) {
|
| 20 |
+
console.log(`Typing ${text.length} chars (Command Method)...`);
|
| 21 |
+
for (let i = 0; i < text.length; i++) {
|
| 22 |
+
typeChar(text[i]);
|
| 23 |
+
if (CONFIG.typingDelay > 0) {
|
| 24 |
+
await new Promise(r => setTimeout(r, CONFIG.typingDelay));
|
| 25 |
+
}
|
| 26 |
+
}
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
const triggerHandler = (e) => {
|
| 30 |
+
if (!isArmed) return;
|
| 31 |
+
|
| 32 |
+
if (e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey) {
|
| 33 |
+
|
| 34 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 35 |
+
if (!activeWord) return;
|
| 36 |
+
|
| 37 |
+
const firstLetterElement = activeWord.querySelector('letter');
|
| 38 |
+
const firstLetter = firstLetterElement ? firstLetterElement.textContent : null;
|
| 39 |
+
|
| 40 |
+
if (firstLetter && e.key === firstLetter) {
|
| 41 |
+
isArmed = false;
|
| 42 |
+
|
| 43 |
+
// Fetch text similar to before
|
| 44 |
+
const allWords = document.querySelectorAll('#words .word');
|
| 45 |
+
let fullBuffer = "";
|
| 46 |
+
let foundActive = false;
|
| 47 |
+
|
| 48 |
+
allWords.forEach(word => {
|
| 49 |
+
if (word === activeWord) {
|
| 50 |
+
foundActive = true;
|
| 51 |
+
const letters = word.querySelectorAll('letter');
|
| 52 |
+
for (let i = 1; i < letters.length; i++) {
|
| 53 |
+
fullBuffer += letters[i].textContent;
|
| 54 |
+
}
|
| 55 |
+
fullBuffer += " ";
|
| 56 |
+
} else if (foundActive) {
|
| 57 |
+
const letters = word.querySelectorAll('letter');
|
| 58 |
+
letters.forEach(l => fullBuffer += l.textContent);
|
| 59 |
+
fullBuffer += " ";
|
| 60 |
+
}
|
| 61 |
+
});
|
| 62 |
+
|
| 63 |
+
if (fullBuffer.endsWith(" ")) {
|
| 64 |
+
fullBuffer = fullBuffer.slice(0, -1);
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
window.removeEventListener('keydown', triggerHandler);
|
| 68 |
+
|
| 69 |
+
console.log("Trigger detected. Starting Command Typer...");
|
| 70 |
+
setTimeout(() => {
|
| 71 |
+
autoType(fullBuffer);
|
| 72 |
+
}, CONFIG.startDelay);
|
| 73 |
+
}
|
| 74 |
+
}
|
| 75 |
+
};
|
| 76 |
+
|
| 77 |
+
window.addEventListener('keydown', triggerHandler);
|
| 78 |
+
console.log("READY! Type the first letter to test Command Mode.");
|
| 79 |
+
})();
|
javascript/1_variant.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
(function () {
|
| 2 |
+
console.log("%c Monkeytype Cheat Initiated ", "background: #222; color: #bada55; font-size: 20px");
|
| 3 |
+
function typeChar(char) {
|
| 4 |
+
const target = document.activeElement || document.body;
|
| 5 |
+
const key = char;
|
| 6 |
+
const code = `Key${char.toUpperCase()}`;
|
| 7 |
+
const eventOptions = {
|
| 8 |
+
key: key,
|
| 9 |
+
code: code,
|
| 10 |
+
charCode: char.charCodeAt(0),
|
| 11 |
+
keyCode: char.toUpperCase().charCodeAt(0),
|
| 12 |
+
which: char.toUpperCase().charCodeAt(0),
|
| 13 |
+
bubbles: true,
|
| 14 |
+
cancelable: true,
|
| 15 |
+
isTrusted: true
|
| 16 |
+
};
|
| 17 |
+
target.dispatchEvent(new KeyboardEvent('keydown', eventOptions));
|
| 18 |
+
target.dispatchEvent(new KeyboardEvent('keypress', eventOptions));
|
| 19 |
+
|
| 20 |
+
// Input event is often required for modern frameworks (React/Vue/etc)
|
| 21 |
+
const inputEvent = new InputEvent('input', {
|
| 22 |
+
data: char,
|
| 23 |
+
inputType: 'insertText',
|
| 24 |
+
bubbles: true,
|
| 25 |
+
cancelable: true
|
| 26 |
+
});
|
| 27 |
+
target.dispatchEvent(inputEvent);
|
| 28 |
+
|
| 29 |
+
target.dispatchEvent(new KeyboardEvent('keyup', eventOptions));
|
| 30 |
+
}
|
| 31 |
+
function cheat() {
|
| 32 |
+
// Selector logic based on standard Monkeytype structure
|
| 33 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 34 |
+
const allWords = document.querySelectorAll('#words .word');
|
| 35 |
+
|
| 36 |
+
if (!activeWord) {
|
| 37 |
+
console.error("Could not find active word. Is the test started?");
|
| 38 |
+
return;
|
| 39 |
+
}
|
| 40 |
+
let distinctText = "";
|
| 41 |
+
let foundActive = false;
|
| 42 |
+
// Iterate through all words to build the text buffer starting from the current active word
|
| 43 |
+
allWords.forEach(word => {
|
| 44 |
+
if (word === activeWord) {
|
| 45 |
+
foundActive = true;
|
| 46 |
+
}
|
| 47 |
+
if (foundActive) {
|
| 48 |
+
// Extract letters
|
| 49 |
+
const letters = word.querySelectorAll('letter');
|
| 50 |
+
letters.forEach(l => distinctText += l.textContent);
|
| 51 |
+
// Add space between words, but check if it's the last word to avoid trailing space error
|
| 52 |
+
// (Monkeytype usually handles the extra space fine, but let's be safe)
|
| 53 |
+
distinctText += " ";
|
| 54 |
+
}
|
| 55 |
+
});
|
| 56 |
+
// The user has ALREADY typed the first letter to trigger this.
|
| 57 |
+
// So we remove the first character from our buffer.
|
| 58 |
+
const textToType = distinctText.substring(1);
|
| 59 |
+
console.log(`Typing ${textToType.length} characters... Buckle up!`);
|
| 60 |
+
// Synchronous loop for maximum blocking speed
|
| 61 |
+
// This will freeze the UI for a split second but will result in near-infinite WPM
|
| 62 |
+
for (let i = 0; i < textToType.length; i++) {
|
| 63 |
+
typeChar(textToType[i]);
|
| 64 |
+
}
|
| 65 |
+
}
|
| 66 |
+
// Arm the trigger
|
| 67 |
+
const triggerHandler = (e) => {
|
| 68 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 69 |
+
// Check if we are in a valid state to trigger
|
| 70 |
+
if (activeWord && e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey) {
|
| 71 |
+
const firstLetterElement = activeWord.querySelector('letter');
|
| 72 |
+
const firstLetter = firstLetterElement ? firstLetterElement.textContent : null;
|
| 73 |
+
|
| 74 |
+
// If the user types the CORRECT first letter, fire the cheat
|
| 75 |
+
if (firstLetter && e.key === firstLetter) {
|
| 76 |
+
// Remove listener so it doesn't fire again recursively or on next key
|
| 77 |
+
window.removeEventListener('keydown', triggerHandler);
|
| 78 |
+
|
| 79 |
+
// Small timeout to allow the browser to process the user's initial keypress naturally
|
| 80 |
+
// before we blast the rest of the text.
|
| 81 |
+
setTimeout(cheat, 10);
|
| 82 |
+
}
|
| 83 |
+
}
|
| 84 |
+
};
|
| 85 |
+
window.addEventListener('keydown', triggerHandler);
|
| 86 |
+
|
| 87 |
+
console.log("READY: Type the first correct letter of the current word to auto-finish.");
|
| 88 |
+
})();
|
javascript/2_variant.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
(function () {
|
| 2 |
+
console.log("%c Monkeytype Cheat Initiated (Human 100 WPM) ", "background: #222; color: #bada55; font-size: 20px");
|
| 3 |
+
|
| 4 |
+
function typeChar(char) {
|
| 5 |
+
const target = document.activeElement || document.body;
|
| 6 |
+
const key = char;
|
| 7 |
+
const code = `Key${char.toUpperCase()}`;
|
| 8 |
+
const eventOptions = {
|
| 9 |
+
key: key,
|
| 10 |
+
code: code,
|
| 11 |
+
charCode: char.charCodeAt(0),
|
| 12 |
+
keyCode: char.toUpperCase().charCodeAt(0),
|
| 13 |
+
which: char.toUpperCase().charCodeAt(0),
|
| 14 |
+
bubbles: true,
|
| 15 |
+
cancelable: true,
|
| 16 |
+
isTrusted: true
|
| 17 |
+
};
|
| 18 |
+
|
| 19 |
+
target.dispatchEvent(new KeyboardEvent('keydown', eventOptions));
|
| 20 |
+
target.dispatchEvent(new KeyboardEvent('keypress', eventOptions));
|
| 21 |
+
|
| 22 |
+
const inputEvent = new InputEvent('input', {
|
| 23 |
+
data: char,
|
| 24 |
+
inputType: 'insertText',
|
| 25 |
+
bubbles: true,
|
| 26 |
+
cancelable: true
|
| 27 |
+
});
|
| 28 |
+
target.dispatchEvent(inputEvent);
|
| 29 |
+
|
| 30 |
+
target.dispatchEvent(new KeyboardEvent('keyup', eventOptions));
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
// Standard WPM: 1 word = 5 chars. 100 WPM = 500 CPM.
|
| 34 |
+
// 60000ms / 500 = 120ms per char.
|
| 35 |
+
// We add randomness to make it look human.
|
| 36 |
+
function getDelay() {
|
| 37 |
+
// Base delay for 100 WPM
|
| 38 |
+
const baseDelay = 120;
|
| 39 |
+
// Random variance between -30ms and +30ms
|
| 40 |
+
const variance = (Math.random() * 60) - 30;
|
| 41 |
+
return baseDelay + variance;
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
async function cheat() {
|
| 45 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 46 |
+
const allWords = document.querySelectorAll('#words .word');
|
| 47 |
+
|
| 48 |
+
if (!activeWord) {
|
| 49 |
+
console.error("Could not find active word. Is the test started?");
|
| 50 |
+
return;
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
let distinctText = "";
|
| 54 |
+
let foundActive = false;
|
| 55 |
+
|
| 56 |
+
allWords.forEach(word => {
|
| 57 |
+
if (word === activeWord) {
|
| 58 |
+
foundActive = true;
|
| 59 |
+
}
|
| 60 |
+
if (foundActive) {
|
| 61 |
+
const letters = word.querySelectorAll('letter');
|
| 62 |
+
letters.forEach(l => distinctText += l.textContent);
|
| 63 |
+
distinctText += " ";
|
| 64 |
+
}
|
| 65 |
+
});
|
| 66 |
+
|
| 67 |
+
const textToType = distinctText.substring(1);
|
| 68 |
+
console.log(`Typing ${textToType.length} characters at ~100 WPM...`);
|
| 69 |
+
|
| 70 |
+
for (let i = 0; i < textToType.length; i++) {
|
| 71 |
+
typeChar(textToType[i]);
|
| 72 |
+
// Wait for a human-like delay
|
| 73 |
+
await new Promise(resolve => setTimeout(resolve, getDelay()));
|
| 74 |
+
}
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
const triggerHandler = (e) => {
|
| 78 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 79 |
+
if (activeWord && e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey) {
|
| 80 |
+
const firstLetterElement = activeWord.querySelector('letter');
|
| 81 |
+
const firstLetter = firstLetterElement ? firstLetterElement.textContent : null;
|
| 82 |
+
|
| 83 |
+
if (firstLetter && e.key === firstLetter) {
|
| 84 |
+
window.removeEventListener('keydown', triggerHandler);
|
| 85 |
+
setTimeout(cheat, 10);
|
| 86 |
+
}
|
| 87 |
+
}
|
| 88 |
+
};
|
| 89 |
+
|
| 90 |
+
window.addEventListener('keydown', triggerHandler);
|
| 91 |
+
|
| 92 |
+
console.log("READY: Type the first correct letter of the current word to start human-like typing.");
|
| 93 |
+
})();
|
javascript/3_variant.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
(function () {
|
| 2 |
+
console.log("%c Monkeytype Cheat Initiated (Human 100 WPM + Fixes) ", "background: #222; color: #bada55; font-size: 20px");
|
| 3 |
+
|
| 4 |
+
const keyMap = {
|
| 5 |
+
' ': { code: 'Space', keyCode: 32 },
|
| 6 |
+
'\n': { code: 'Enter', keyCode: 13 },
|
| 7 |
+
'.': { code: 'Period', keyCode: 190 },
|
| 8 |
+
',': { code: 'Comma', keyCode: 188 },
|
| 9 |
+
';': { code: 'Semicolon', keyCode: 186 },
|
| 10 |
+
'\'': { code: 'Quote', keyCode: 222 },
|
| 11 |
+
'/': { code: 'Slash', keyCode: 191 },
|
| 12 |
+
'\\': { code: 'Backslash', keyCode: 220 },
|
| 13 |
+
'-': { code: 'Minus', keyCode: 189 },
|
| 14 |
+
'=': { code: 'Equal', keyCode: 187 },
|
| 15 |
+
'[': { code: 'BracketLeft', keyCode: 219 },
|
| 16 |
+
']': { code: 'BracketRight', keyCode: 221 }
|
| 17 |
+
};
|
| 18 |
+
|
| 19 |
+
function typeChar(char) {
|
| 20 |
+
const target = document.activeElement || document.body;
|
| 21 |
+
|
| 22 |
+
// Determine properties
|
| 23 |
+
let key = char;
|
| 24 |
+
let code, keyCode;
|
| 25 |
+
|
| 26 |
+
if (keyMap[char]) {
|
| 27 |
+
code = keyMap[char].code;
|
| 28 |
+
keyCode = keyMap[char].keyCode;
|
| 29 |
+
} else {
|
| 30 |
+
// Fallback for letters/numbers
|
| 31 |
+
code = `Key${char.toUpperCase()}`;
|
| 32 |
+
keyCode = char.toUpperCase().charCodeAt(0);
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
const eventOptions = {
|
| 36 |
+
key: key,
|
| 37 |
+
code: code,
|
| 38 |
+
keyCode: keyCode, // Important for legacy checks
|
| 39 |
+
which: keyCode,
|
| 40 |
+
bubbles: true,
|
| 41 |
+
cancelable: true,
|
| 42 |
+
isTrusted: true // Ignored by browser but good for consistency
|
| 43 |
+
};
|
| 44 |
+
|
| 45 |
+
target.dispatchEvent(new KeyboardEvent('keydown', eventOptions));
|
| 46 |
+
target.dispatchEvent(new KeyboardEvent('keypress', eventOptions));
|
| 47 |
+
|
| 48 |
+
const inputEvent = new InputEvent('input', {
|
| 49 |
+
data: char,
|
| 50 |
+
inputType: 'insertText',
|
| 51 |
+
bubbles: true,
|
| 52 |
+
cancelable: true
|
| 53 |
+
});
|
| 54 |
+
target.dispatchEvent(inputEvent);
|
| 55 |
+
|
| 56 |
+
target.dispatchEvent(new KeyboardEvent('keyup', eventOptions));
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
function getDelay() {
|
| 60 |
+
// ~100 WPM
|
| 61 |
+
const baseDelay = 120;
|
| 62 |
+
const variance = (Math.random() * 60) - 30;
|
| 63 |
+
return baseDelay + variance;
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
async function cheat() {
|
| 67 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 68 |
+
const allWords = document.querySelectorAll('#words .word');
|
| 69 |
+
|
| 70 |
+
if (!activeWord) {
|
| 71 |
+
console.error("Could not find active word. Is the test running?");
|
| 72 |
+
return;
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
let distinctText = "";
|
| 76 |
+
let foundActive = false;
|
| 77 |
+
|
| 78 |
+
allWords.forEach(word => {
|
| 79 |
+
if (word === activeWord) {
|
| 80 |
+
foundActive = true;
|
| 81 |
+
}
|
| 82 |
+
if (foundActive) {
|
| 83 |
+
const letters = word.querySelectorAll('letter');
|
| 84 |
+
letters.forEach(l => distinctText += l.textContent);
|
| 85 |
+
distinctText += " ";
|
| 86 |
+
}
|
| 87 |
+
});
|
| 88 |
+
|
| 89 |
+
// The first char was typed by user.
|
| 90 |
+
// We trim it.
|
| 91 |
+
const textToType = distinctText.substring(1);
|
| 92 |
+
console.log(`Typing ${textToType.length} characters...`);
|
| 93 |
+
|
| 94 |
+
for (let i = 0; i < textToType.length; i++) {
|
| 95 |
+
typeChar(textToType[i]);
|
| 96 |
+
await new Promise(resolve => setTimeout(resolve, getDelay()));
|
| 97 |
+
}
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
const triggerHandler = (e) => {
|
| 101 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 102 |
+
if (activeWord && e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey) {
|
| 103 |
+
const firstLetterElement = activeWord.querySelector('letter');
|
| 104 |
+
const firstLetter = firstLetterElement ? firstLetterElement.textContent : null;
|
| 105 |
+
|
| 106 |
+
if (firstLetter && e.key === firstLetter) {
|
| 107 |
+
window.removeEventListener('keydown', triggerHandler);
|
| 108 |
+
// Increased delay to 150ms to prevent race condition with React state updates
|
| 109 |
+
console.log("Trigger detected. Starting in 150ms...");
|
| 110 |
+
setTimeout(cheat, 150);
|
| 111 |
+
}
|
| 112 |
+
}
|
| 113 |
+
};
|
| 114 |
+
|
| 115 |
+
window.addEventListener('keydown', triggerHandler);
|
| 116 |
+
console.log("READY: Type the first letter to start.");
|
| 117 |
+
})();
|
javascript/4_variant.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
(function () {
|
| 2 |
+
console.log("%c Monkeytype Cheat Initiated (Reactive/Smart Mode) ", "background: #222; color: #bada55; font-size: 20px");
|
| 3 |
+
|
| 4 |
+
const keyMap = {
|
| 5 |
+
' ': { code: 'Space', keyCode: 32 },
|
| 6 |
+
'\n': { code: 'Enter', keyCode: 13 },
|
| 7 |
+
'.': { code: 'Period', keyCode: 190 },
|
| 8 |
+
',': { code: 'Comma', keyCode: 188 },
|
| 9 |
+
';': { code: 'Semicolon', keyCode: 186 },
|
| 10 |
+
'\'': { code: 'Quote', keyCode: 222 },
|
| 11 |
+
'/': { code: 'Slash', keyCode: 191 },
|
| 12 |
+
'\\': { code: 'Backslash', keyCode: 220 },
|
| 13 |
+
'-': { code: 'Minus', keyCode: 189 },
|
| 14 |
+
'=': { code: 'Equal', keyCode: 187 },
|
| 15 |
+
'[': { code: 'BracketLeft', keyCode: 219 },
|
| 16 |
+
']': { code: 'BracketRight', keyCode: 221 }
|
| 17 |
+
};
|
| 18 |
+
|
| 19 |
+
function typeChar(char) {
|
| 20 |
+
const target = document.activeElement || document.body;
|
| 21 |
+
let key = char;
|
| 22 |
+
let code, keyCode;
|
| 23 |
+
|
| 24 |
+
if (keyMap[char]) {
|
| 25 |
+
code = keyMap[char].code;
|
| 26 |
+
keyCode = keyMap[char].keyCode;
|
| 27 |
+
} else {
|
| 28 |
+
code = `Key${char.toUpperCase()}`;
|
| 29 |
+
keyCode = char.toUpperCase().charCodeAt(0);
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
const eventOptions = {
|
| 33 |
+
key: key,
|
| 34 |
+
code: code,
|
| 35 |
+
keyCode: keyCode,
|
| 36 |
+
which: keyCode,
|
| 37 |
+
bubbles: true,
|
| 38 |
+
cancelable: true,
|
| 39 |
+
isTrusted: true
|
| 40 |
+
};
|
| 41 |
+
|
| 42 |
+
target.dispatchEvent(new KeyboardEvent('keydown', eventOptions));
|
| 43 |
+
target.dispatchEvent(new KeyboardEvent('keypress', eventOptions));
|
| 44 |
+
|
| 45 |
+
const inputEvent = new InputEvent('input', {
|
| 46 |
+
data: char,
|
| 47 |
+
inputType: 'insertText',
|
| 48 |
+
bubbles: true,
|
| 49 |
+
cancelable: true
|
| 50 |
+
});
|
| 51 |
+
target.dispatchEvent(inputEvent);
|
| 52 |
+
|
| 53 |
+
target.dispatchEvent(new KeyboardEvent('keyup', eventOptions));
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
function getDelay() {
|
| 57 |
+
return 100 + (Math.random() * 60 - 30); // ~100-120ms average
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
async function cheat() {
|
| 61 |
+
console.log("Cheat running... Press Escape to stop.");
|
| 62 |
+
|
| 63 |
+
while (true) {
|
| 64 |
+
// 1. Find the active word
|
| 65 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 66 |
+
|
| 67 |
+
// If no active word, we might be done or loading.
|
| 68 |
+
if (!activeWord) {
|
| 69 |
+
// Check if test is over (result page usually covers #words or removes .active)
|
| 70 |
+
const isResult = document.querySelector('#result');
|
| 71 |
+
if (isResult && isResult.checkVisibility && isResult.checkVisibility()) {
|
| 72 |
+
console.log("Test finished.");
|
| 73 |
+
break;
|
| 74 |
+
}
|
| 75 |
+
// Check if we just haven't started (shouldn't happen since we trigger on key)
|
| 76 |
+
// Safety break
|
| 77 |
+
await new Promise(r => setTimeout(r, 500));
|
| 78 |
+
continue;
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
// 2. Find the next pending letter in this word
|
| 82 |
+
// Monkeytype uses classes 'correct'/'incorrect' for typed letters.
|
| 83 |
+
// We want the first letter that DOES NOT have these classes.
|
| 84 |
+
const nextLetterNode = activeWord.querySelector('letter:not(.correct):not(.incorrect)');
|
| 85 |
+
|
| 86 |
+
if (nextLetterNode) {
|
| 87 |
+
// We have a letter to type
|
| 88 |
+
typeChar(nextLetterNode.textContent);
|
| 89 |
+
} else {
|
| 90 |
+
// No letters left in this word. It's done.
|
| 91 |
+
// We need to type SPACE to move to next word.
|
| 92 |
+
// UNLESS it's the very last word.
|
| 93 |
+
const nextWord = activeWord.nextElementSibling;
|
| 94 |
+
if (nextWord && nextWord.classList.contains('word')) {
|
| 95 |
+
typeChar(' ');
|
| 96 |
+
} else {
|
| 97 |
+
console.log("Last word finished.");
|
| 98 |
+
break;
|
| 99 |
+
}
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
// 3. Wait human delay
|
| 103 |
+
await new Promise(r => setTimeout(r, getDelay()));
|
| 104 |
+
}
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
// Trigger Logic
|
| 108 |
+
const triggerHandler = (e) => {
|
| 109 |
+
// Only trigger on single char keys, no modifiers
|
| 110 |
+
if (e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey) {
|
| 111 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 112 |
+
if (activeWord) {
|
| 113 |
+
const firstLetter = activeWord.querySelector('letter');
|
| 114 |
+
// If user types correct first letter
|
| 115 |
+
if (firstLetter && e.key === firstLetter.textContent) {
|
| 116 |
+
window.removeEventListener('keydown', triggerHandler);
|
| 117 |
+
console.log("Triggered! Taking over in 100ms...");
|
| 118 |
+
// Small delay to let the user's key register fully
|
| 119 |
+
setTimeout(cheat, 100);
|
| 120 |
+
}
|
| 121 |
+
}
|
| 122 |
+
}
|
| 123 |
+
};
|
| 124 |
+
|
| 125 |
+
window.addEventListener('keydown', triggerHandler);
|
| 126 |
+
console.log("READY: Reactive Mode. Type the first letter.");
|
| 127 |
+
})();
|
javascript/5_variant.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
(function () {
|
| 2 |
+
console.log("%c Monkeytype Cheat Initiated (Static Buffer Mode) ", "background: #222; color: #bada55; font-size: 20px");
|
| 3 |
+
|
| 4 |
+
const keyMap = {
|
| 5 |
+
' ': { code: 'Space', keyCode: 32 },
|
| 6 |
+
'\n': { code: 'Enter', keyCode: 13 },
|
| 7 |
+
};
|
| 8 |
+
|
| 9 |
+
function typeChar(char) {
|
| 10 |
+
const target = document.activeElement || document.body;
|
| 11 |
+
let key = char;
|
| 12 |
+
let code, keyCode;
|
| 13 |
+
|
| 14 |
+
// Basic char code fallback
|
| 15 |
+
if (keyMap[char]) {
|
| 16 |
+
code = keyMap[char].code;
|
| 17 |
+
keyCode = keyMap[char].keyCode;
|
| 18 |
+
} else {
|
| 19 |
+
code = `Key${char.toUpperCase()}`;
|
| 20 |
+
keyCode = char.toUpperCase().charCodeAt(0);
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
const eventOptions = {
|
| 24 |
+
key: key,
|
| 25 |
+
code: code,
|
| 26 |
+
keyCode: keyCode,
|
| 27 |
+
which: keyCode,
|
| 28 |
+
bubbles: true,
|
| 29 |
+
cancelable: true,
|
| 30 |
+
isTrusted: true
|
| 31 |
+
};
|
| 32 |
+
|
| 33 |
+
target.dispatchEvent(new KeyboardEvent('keydown', eventOptions));
|
| 34 |
+
target.dispatchEvent(new KeyboardEvent('keypress', eventOptions));
|
| 35 |
+
|
| 36 |
+
const inputEvent = new InputEvent('input', {
|
| 37 |
+
data: char,
|
| 38 |
+
inputType: 'insertText',
|
| 39 |
+
bubbles: true,
|
| 40 |
+
cancelable: true
|
| 41 |
+
});
|
| 42 |
+
target.dispatchEvent(inputEvent);
|
| 43 |
+
|
| 44 |
+
target.dispatchEvent(new KeyboardEvent('keyup', eventOptions));
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
function getDelay() {
|
| 48 |
+
return 100 + (Math.random() * 60 - 30); // ~100-120ms
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
async function cheat(textToType) {
|
| 52 |
+
console.log(`Cheat triggered. Typing ${textToType.length} chars...`);
|
| 53 |
+
|
| 54 |
+
for (let i = 0; i < textToType.length; i++) {
|
| 55 |
+
typeChar(textToType[i]);
|
| 56 |
+
await new Promise(r => setTimeout(r, getDelay()));
|
| 57 |
+
}
|
| 58 |
+
console.log("Done.");
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
// 1. Identify whole words FIRST (as requested)
|
| 62 |
+
function getFullText() {
|
| 63 |
+
const words = document.querySelectorAll('#words .word');
|
| 64 |
+
let fullBuffer = "";
|
| 65 |
+
|
| 66 |
+
words.forEach((word, index) => {
|
| 67 |
+
const letters = word.querySelectorAll('letter');
|
| 68 |
+
letters.forEach(l => fullBuffer += l.textContent);
|
| 69 |
+
|
| 70 |
+
// Add space between words, but NOT after the last word
|
| 71 |
+
if (index < words.length - 1) {
|
| 72 |
+
fullBuffer += " ";
|
| 73 |
+
}
|
| 74 |
+
});
|
| 75 |
+
return fullBuffer;
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
const triggerHandler = (e) => {
|
| 79 |
+
// Only trigger on single char keys
|
| 80 |
+
if (e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey) {
|
| 81 |
+
const targetText = getFullText();
|
| 82 |
+
const firstChar = targetText[0];
|
| 83 |
+
|
| 84 |
+
if (firstChar && e.key === firstChar) {
|
| 85 |
+
window.removeEventListener('keydown', triggerHandler);
|
| 86 |
+
|
| 87 |
+
// User typed the first char. We type the rest.
|
| 88 |
+
const remainingText = targetText.substring(1);
|
| 89 |
+
|
| 90 |
+
console.log("Triggered! Taking over in 150ms...");
|
| 91 |
+
setTimeout(() => cheat(remainingText), 150);
|
| 92 |
+
}
|
| 93 |
+
}
|
| 94 |
+
};
|
| 95 |
+
|
| 96 |
+
window.addEventListener('keydown', triggerHandler);
|
| 97 |
+
console.log("READY: Static Buffer Mode. Words identified. Type first letter.");
|
| 98 |
+
})();
|
javascript/6_variant.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
(function () {
|
| 2 |
+
console.log("%c Monkeytype Cheat Initiated (Persistent Mode) ", "background: #222; color: #bada55; font-size: 20px");
|
| 3 |
+
|
| 4 |
+
const keyMap = {
|
| 5 |
+
' ': { code: 'Space', keyCode: 32 },
|
| 6 |
+
'\n': { code: 'Enter', keyCode: 13 },
|
| 7 |
+
};
|
| 8 |
+
|
| 9 |
+
let isArmed = false;
|
| 10 |
+
|
| 11 |
+
function typeChar(char) {
|
| 12 |
+
const target = document.activeElement || document.body;
|
| 13 |
+
let key = char;
|
| 14 |
+
let code, keyCode;
|
| 15 |
+
|
| 16 |
+
if (keyMap[char]) {
|
| 17 |
+
code = keyMap[char].code;
|
| 18 |
+
keyCode = keyMap[char].keyCode;
|
| 19 |
+
} else {
|
| 20 |
+
code = `Key${char.toUpperCase()}`;
|
| 21 |
+
keyCode = char.toUpperCase().charCodeAt(0);
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
const eventOptions = {
|
| 25 |
+
key: key,
|
| 26 |
+
code: code,
|
| 27 |
+
keyCode: keyCode,
|
| 28 |
+
which: keyCode,
|
| 29 |
+
bubbles: true,
|
| 30 |
+
cancelable: true,
|
| 31 |
+
isTrusted: true
|
| 32 |
+
};
|
| 33 |
+
|
| 34 |
+
target.dispatchEvent(new KeyboardEvent('keydown', eventOptions));
|
| 35 |
+
target.dispatchEvent(new KeyboardEvent('keypress', eventOptions));
|
| 36 |
+
|
| 37 |
+
const inputEvent = new InputEvent('input', {
|
| 38 |
+
data: char,
|
| 39 |
+
inputType: 'insertText',
|
| 40 |
+
bubbles: true,
|
| 41 |
+
cancelable: true
|
| 42 |
+
});
|
| 43 |
+
target.dispatchEvent(inputEvent);
|
| 44 |
+
|
| 45 |
+
target.dispatchEvent(new KeyboardEvent('keyup', eventOptions));
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
function getDelay() {
|
| 49 |
+
return 100 + (Math.random() * 60 - 30);
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
async function cheat(textToType) {
|
| 53 |
+
console.log(`Typing ${textToType.length} chars...`);
|
| 54 |
+
for (let i = 0; i < textToType.length; i++) {
|
| 55 |
+
// Check if test was reset mid-run
|
| 56 |
+
if (!document.querySelector('#words .word.active')) {
|
| 57 |
+
console.log("Test reset detected. Stopping current run.");
|
| 58 |
+
return;
|
| 59 |
+
}
|
| 60 |
+
typeChar(textToType[i]);
|
| 61 |
+
await new Promise(r => setTimeout(r, getDelay()));
|
| 62 |
+
}
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
function getFullText() {
|
| 66 |
+
const words = document.querySelectorAll('#words .word');
|
| 67 |
+
let fullBuffer = "";
|
| 68 |
+
words.forEach((word, index) => {
|
| 69 |
+
const letters = word.querySelectorAll('letter');
|
| 70 |
+
letters.forEach(l => fullBuffer += l.textContent);
|
| 71 |
+
if (index < words.length - 1) fullBuffer += " ";
|
| 72 |
+
});
|
| 73 |
+
return fullBuffer;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
const triggerHandler = (e) => {
|
| 77 |
+
if (!isArmed) return;
|
| 78 |
+
|
| 79 |
+
if (e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey) {
|
| 80 |
+
const targetText = getFullText();
|
| 81 |
+
if (!targetText) return;
|
| 82 |
+
|
| 83 |
+
const firstChar = targetText[0];
|
| 84 |
+
if (firstChar && e.key === firstChar) {
|
| 85 |
+
isArmed = false; // Disarm to prevent double trigger
|
| 86 |
+
const remainingText = targetText.substring(1);
|
| 87 |
+
console.log("Triggered! Starting...");
|
| 88 |
+
setTimeout(() => cheat(remainingText), 150);
|
| 89 |
+
}
|
| 90 |
+
}
|
| 91 |
+
};
|
| 92 |
+
|
| 93 |
+
function armCheat() {
|
| 94 |
+
// Debounce slightly to ensure DOM is ready
|
| 95 |
+
setTimeout(() => {
|
| 96 |
+
const text = getFullText();
|
| 97 |
+
if (text.length > 0) {
|
| 98 |
+
isArmed = true;
|
| 99 |
+
console.log("Cheat RE-ARMED. Waiting for first key...");
|
| 100 |
+
} else {
|
| 101 |
+
console.log("Training ended or no words found.");
|
| 102 |
+
}
|
| 103 |
+
}, 500);
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
// LISTENER: Watch for Keydown (Trigger)
|
| 107 |
+
// We add this ONCE and keep it capable of firing whenever 'isArmed' is true.
|
| 108 |
+
window.addEventListener('keydown', triggerHandler);
|
| 109 |
+
|
| 110 |
+
// MUTATION OBSERVER: Watch for "Restart Test"
|
| 111 |
+
// When #words changes (new words added), we re-arm.
|
| 112 |
+
const wordsContainer = document.querySelector('#words');
|
| 113 |
+
if (wordsContainer) {
|
| 114 |
+
const observer = new MutationObserver((mutations) => {
|
| 115 |
+
for (const mutation of mutations) {
|
| 116 |
+
// If words are added/removed, it means test reset/changed
|
| 117 |
+
if (mutation.type === 'childList') {
|
| 118 |
+
// Check if we have new words
|
| 119 |
+
const words = document.querySelectorAll('#words .word');
|
| 120 |
+
if (words.length > 5) { // Arbitrary threshold to ensure it's a real set of words
|
| 121 |
+
armCheat();
|
| 122 |
+
// We break to avoid calling armCheat multiple times per batch update
|
| 123 |
+
break;
|
| 124 |
+
}
|
| 125 |
+
}
|
| 126 |
+
}
|
| 127 |
+
});
|
| 128 |
+
|
| 129 |
+
observer.observe(wordsContainer, { childList: true });
|
| 130 |
+
console.log("Observer attached. Auto-restart enabled.");
|
| 131 |
+
|
| 132 |
+
// Initial Arm
|
| 133 |
+
armCheat();
|
| 134 |
+
} else {
|
| 135 |
+
console.error("Container #words not found. Is the page loaded?");
|
| 136 |
+
}
|
| 137 |
+
})();
|
javascript/7_variant.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
(function () {
|
| 2 |
+
console.log("%c Monkeytype Auto-Typer (Anti-Cheat Bypass) Initiated ", "background: #222; color: #00ff00; font-size: 20px");
|
| 3 |
+
|
| 4 |
+
// CONFIGURATION
|
| 5 |
+
const CONFIG = {
|
| 6 |
+
// Delay after you type the first character before the bot takes over (ms)
|
| 7 |
+
startDelay: 50,
|
| 8 |
+
// Delay between characters (ms).
|
| 9 |
+
// 0 = Instant (but risky for some anti-cheats).
|
| 10 |
+
// 10-30 = Super fast but slightly safer.
|
| 11 |
+
typingDelay: 10,
|
| 12 |
+
// If true, types spaces between words.
|
| 13 |
+
typeSpaces: true
|
| 14 |
+
};
|
| 15 |
+
|
| 16 |
+
let isArmed = true;
|
| 17 |
+
|
| 18 |
+
// Helper: Create and dispatch events that look "real"
|
| 19 |
+
function typeChar(char) {
|
| 20 |
+
const target = document.activeElement || document.body;
|
| 21 |
+
|
| 22 |
+
let key = char;
|
| 23 |
+
let code, keyCode;
|
| 24 |
+
|
| 25 |
+
// Handle Space specifically
|
| 26 |
+
if (char === ' ') {
|
| 27 |
+
code = 'Space';
|
| 28 |
+
keyCode = 32;
|
| 29 |
+
}
|
| 30 |
+
// Handle common punctuation to ensure correct codes
|
| 31 |
+
else if (char === '\n') {
|
| 32 |
+
code = 'Enter';
|
| 33 |
+
keyCode = 13;
|
| 34 |
+
}
|
| 35 |
+
else {
|
| 36 |
+
// Very basic mapping. For complex symbols, this might be generic (which usually passes).
|
| 37 |
+
code = `Key${char.toUpperCase()}`;
|
| 38 |
+
keyCode = char.charCodeAt(0);
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
const eventOptions = {
|
| 42 |
+
key: key,
|
| 43 |
+
code: code,
|
| 44 |
+
keyCode: keyCode,
|
| 45 |
+
which: keyCode,
|
| 46 |
+
bubbles: true,
|
| 47 |
+
cancelable: true,
|
| 48 |
+
isTrusted: true // Browser ignores this for script-generated events, but we set it anyway.
|
| 49 |
+
};
|
| 50 |
+
|
| 51 |
+
// 1. Keydown
|
| 52 |
+
target.dispatchEvent(new KeyboardEvent('keydown', eventOptions));
|
| 53 |
+
|
| 54 |
+
// 2. Keypress (Deprecated but some sites check it)
|
| 55 |
+
target.dispatchEvent(new KeyboardEvent('keypress', eventOptions));
|
| 56 |
+
|
| 57 |
+
// 3. Input (Essential for modern frameworks like React/Vue used in Monkeytype)
|
| 58 |
+
const inputEvent = new InputEvent('input', {
|
| 59 |
+
data: char,
|
| 60 |
+
inputType: 'insertText',
|
| 61 |
+
bubbles: true,
|
| 62 |
+
cancelable: true
|
| 63 |
+
});
|
| 64 |
+
target.dispatchEvent(inputEvent);
|
| 65 |
+
|
| 66 |
+
// 4. Keyup
|
| 67 |
+
target.dispatchEvent(new KeyboardEvent('keyup', eventOptions));
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
async function autoType(text) {
|
| 71 |
+
console.log(`Taking over! Typing ${text.length} characters...`);
|
| 72 |
+
|
| 73 |
+
for (let i = 0; i < text.length; i++) {
|
| 74 |
+
typeChar(text[i]);
|
| 75 |
+
// Small delay to prevent freezing the browser and mimic extremely fast typing
|
| 76 |
+
if (CONFIG.typingDelay > 0) {
|
| 77 |
+
await new Promise(r => setTimeout(r, CONFIG.typingDelay));
|
| 78 |
+
}
|
| 79 |
+
}
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
// MAIN LOGIC
|
| 83 |
+
const triggerHandler = (e) => {
|
| 84 |
+
if (!isArmed) return;
|
| 85 |
+
|
| 86 |
+
// We only care about single key presses (no Ctrl/Alt commands)
|
| 87 |
+
// We also ignore if the user is just navigating menus.
|
| 88 |
+
// We assume the user is "starting" the test.
|
| 89 |
+
if (e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey) {
|
| 90 |
+
|
| 91 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 92 |
+
if (!activeWord) return;
|
| 93 |
+
|
| 94 |
+
const firstLetterElement = activeWord.querySelector('letter');
|
| 95 |
+
// Monkeytype sometimes puts the first letter in a slightly different state
|
| 96 |
+
// or we might need to be careful about 'correct' class.
|
| 97 |
+
// But generally, the first letter of the active word is what we need.
|
| 98 |
+
|
| 99 |
+
const firstLetter = firstLetterElement ? firstLetterElement.textContent : null;
|
| 100 |
+
|
| 101 |
+
// CHECK: Did the user type the CORRECT first key?
|
| 102 |
+
if (firstLetter && e.key === firstLetter) {
|
| 103 |
+
isArmed = false; // Disarm immediately
|
| 104 |
+
|
| 105 |
+
// Get ALL remaining text
|
| 106 |
+
const allWords = document.querySelectorAll('#words .word');
|
| 107 |
+
let fullBuffer = "";
|
| 108 |
+
let foundActive = false;
|
| 109 |
+
|
| 110 |
+
allWords.forEach(word => {
|
| 111 |
+
if (word === activeWord) {
|
| 112 |
+
foundActive = true;
|
| 113 |
+
// For the active word, we need to skip the first letter (user just typed it)
|
| 114 |
+
// But wait! If we type too fast, we might conflict with the user's input event processing.
|
| 115 |
+
// So we rebuild the string *including* the rest of this word.
|
| 116 |
+
|
| 117 |
+
const letters = word.querySelectorAll('letter');
|
| 118 |
+
// Start from index 1 (second letter)
|
| 119 |
+
for (let i = 1; i < letters.length; i++) {
|
| 120 |
+
fullBuffer += letters[i].textContent;
|
| 121 |
+
}
|
| 122 |
+
if (CONFIG.typeSpaces) fullBuffer += " ";
|
| 123 |
+
} else if (foundActive) {
|
| 124 |
+
// Future words
|
| 125 |
+
const letters = word.querySelectorAll('letter');
|
| 126 |
+
letters.forEach(l => fullBuffer += l.textContent);
|
| 127 |
+
if (CONFIG.typeSpaces) fullBuffer += " "; // Add space between words
|
| 128 |
+
}
|
| 129 |
+
});
|
| 130 |
+
|
| 131 |
+
// Remove the very last trailing space if it exists (Monkeytype hates extra spaces at end)
|
| 132 |
+
if (fullBuffer.endsWith(" ")) {
|
| 133 |
+
fullBuffer = fullBuffer.slice(0, -1);
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
// Remove listener to prevent checking every single key stroke from now on
|
| 137 |
+
window.removeEventListener('keydown', triggerHandler);
|
| 138 |
+
|
| 139 |
+
console.log("Trigger detected. Typer starting in " + CONFIG.startDelay + "ms");
|
| 140 |
+
|
| 141 |
+
setTimeout(() => {
|
| 142 |
+
autoType(fullBuffer);
|
| 143 |
+
}, CONFIG.startDelay);
|
| 144 |
+
}
|
| 145 |
+
}
|
| 146 |
+
};
|
| 147 |
+
|
| 148 |
+
// Auto-rearm logic (Optional, simple reload usually safer)
|
| 149 |
+
// For now, we just run once per page load to ensure stability.
|
| 150 |
+
window.addEventListener('keydown', triggerHandler);
|
| 151 |
+
|
| 152 |
+
console.log("READY! Start the test by typing the first letter manually.");
|
| 153 |
+
})();
|
javascript/candidate.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
(function () {
|
| 2 |
+
console.log("%c Monkeytype Command Typer (execCommand) ", "background: #222; color: #ff0000; font-size: 20px");
|
| 3 |
+
|
| 4 |
+
const CONFIG = {
|
| 5 |
+
startDelay: 50,
|
| 6 |
+
typingDelay: 10,
|
| 7 |
+
};
|
| 8 |
+
|
| 9 |
+
let isArmed = true;
|
| 10 |
+
|
| 11 |
+
// EXECCOMMAND METHOD
|
| 12 |
+
// This often bypasses "isTrusted" checks because it simulates a browser action (paste/insert)
|
| 13 |
+
// rather than a raw key event.
|
| 14 |
+
function typeChar(char) {
|
| 15 |
+
// We use insertText which is a powerful way to simulate user input
|
| 16 |
+
document.execCommand('insertText', false, char);
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
async function autoType(text) {
|
| 20 |
+
console.log(`Typing ${text.length} chars (Command Method)...`);
|
| 21 |
+
for (let i = 0; i < text.length; i++) {
|
| 22 |
+
typeChar(text[i]);
|
| 23 |
+
if (CONFIG.typingDelay > 0) {
|
| 24 |
+
await new Promise(r => setTimeout(r, CONFIG.typingDelay));
|
| 25 |
+
}
|
| 26 |
+
}
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
const triggerHandler = (e) => {
|
| 30 |
+
if (!isArmed) return;
|
| 31 |
+
|
| 32 |
+
if (e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey) {
|
| 33 |
+
|
| 34 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 35 |
+
if (!activeWord) return;
|
| 36 |
+
|
| 37 |
+
const firstLetterElement = activeWord.querySelector('letter');
|
| 38 |
+
const firstLetter = firstLetterElement ? firstLetterElement.textContent : null;
|
| 39 |
+
|
| 40 |
+
if (firstLetter && e.key === firstLetter) {
|
| 41 |
+
isArmed = false;
|
| 42 |
+
|
| 43 |
+
// Fetch text similar to before
|
| 44 |
+
const allWords = document.querySelectorAll('#words .word');
|
| 45 |
+
let fullBuffer = "";
|
| 46 |
+
let foundActive = false;
|
| 47 |
+
|
| 48 |
+
allWords.forEach(word => {
|
| 49 |
+
if (word === activeWord) {
|
| 50 |
+
foundActive = true;
|
| 51 |
+
const letters = word.querySelectorAll('letter');
|
| 52 |
+
for (let i = 1; i < letters.length; i++) {
|
| 53 |
+
fullBuffer += letters[i].textContent;
|
| 54 |
+
}
|
| 55 |
+
fullBuffer += " ";
|
| 56 |
+
} else if (foundActive) {
|
| 57 |
+
const letters = word.querySelectorAll('letter');
|
| 58 |
+
letters.forEach(l => fullBuffer += l.textContent);
|
| 59 |
+
fullBuffer += " ";
|
| 60 |
+
}
|
| 61 |
+
});
|
| 62 |
+
|
| 63 |
+
if (fullBuffer.endsWith(" ")) {
|
| 64 |
+
fullBuffer = fullBuffer.slice(0, -1);
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
window.removeEventListener('keydown', triggerHandler);
|
| 68 |
+
|
| 69 |
+
console.log("Trigger detected. Starting Command Typer...");
|
| 70 |
+
setTimeout(() => {
|
| 71 |
+
autoType(fullBuffer);
|
| 72 |
+
}, CONFIG.startDelay);
|
| 73 |
+
}
|
| 74 |
+
}
|
| 75 |
+
};
|
| 76 |
+
|
| 77 |
+
window.addEventListener('keydown', triggerHandler);
|
| 78 |
+
console.log("READY! Type the first letter to test Command Mode.");
|
| 79 |
+
})();
|
javascript/monkeytype_advanced.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
(function () {
|
| 2 |
+
console.log("%c Monkeytype Command Typer (execCommand) ", "background: #222; color: #ff0000; font-size: 20px");
|
| 3 |
+
|
| 4 |
+
const CONFIG = {
|
| 5 |
+
startDelay: 50,
|
| 6 |
+
typingDelay: 10,
|
| 7 |
+
};
|
| 8 |
+
|
| 9 |
+
let isArmed = true;
|
| 10 |
+
|
| 11 |
+
// EXECCOMMAND METHOD
|
| 12 |
+
// This often bypasses "isTrusted" checks because it simulates a browser action (paste/insert)
|
| 13 |
+
// rather than a raw key event.
|
| 14 |
+
function typeChar(char) {
|
| 15 |
+
// We use insertText which is a powerful way to simulate user input
|
| 16 |
+
document.execCommand('insertText', false, char);
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
async function autoType(text) {
|
| 20 |
+
console.log(`Typing ${text.length} chars (Command Method)...`);
|
| 21 |
+
for (let i = 0; i < text.length; i++) {
|
| 22 |
+
typeChar(text[i]);
|
| 23 |
+
await new Promise(r => setTimeout(r, getRandomDelay()));
|
| 24 |
+
}
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
const triggerHandler = (e) => {
|
| 28 |
+
if (!isArmed) return;
|
| 29 |
+
|
| 30 |
+
if (e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey) {
|
| 31 |
+
|
| 32 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 33 |
+
if (!activeWord) return;
|
| 34 |
+
|
| 35 |
+
const firstLetterElement = activeWord.querySelector('letter');
|
| 36 |
+
const firstLetter = firstLetterElement ? firstLetterElement.textContent : null;
|
| 37 |
+
|
| 38 |
+
if (firstLetter && e.key === firstLetter) {
|
| 39 |
+
isArmed = false;
|
| 40 |
+
|
| 41 |
+
// Fetch text similar to before
|
| 42 |
+
const allWords = document.querySelectorAll('#words .word');
|
| 43 |
+
let fullBuffer = "";
|
| 44 |
+
let foundActive = false;
|
| 45 |
+
|
| 46 |
+
allWords.forEach(word => {
|
| 47 |
+
if (word === activeWord) {
|
| 48 |
+
foundActive = true;
|
| 49 |
+
const letters = word.querySelectorAll('letter');
|
| 50 |
+
for (let i = 1; i < letters.length; i++) {
|
| 51 |
+
fullBuffer += letters[i].textContent;
|
| 52 |
+
}
|
| 53 |
+
fullBuffer += " ";
|
| 54 |
+
} else if (foundActive) {
|
| 55 |
+
const letters = word.querySelectorAll('letter');
|
| 56 |
+
letters.forEach(l => fullBuffer += l.textContent);
|
| 57 |
+
fullBuffer += " ";
|
| 58 |
+
}
|
| 59 |
+
});
|
| 60 |
+
|
| 61 |
+
if (fullBuffer.endsWith(" ")) {
|
| 62 |
+
fullBuffer = fullBuffer.slice(0, -1);
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
window.removeEventListener('keydown', triggerHandler);
|
| 66 |
+
|
| 67 |
+
console.log("Trigger detected. Starting Command Typer...");
|
| 68 |
+
setTimeout(() => {
|
| 69 |
+
autoType(fullBuffer);
|
| 70 |
+
}, CONFIG.startDelay);
|
| 71 |
+
}
|
| 72 |
+
}
|
| 73 |
+
};
|
| 74 |
+
|
| 75 |
+
window.addEventListener('keydown', triggerHandler);
|
| 76 |
+
console.log("READY! Type the first letter to test Command Mode.");
|
| 77 |
+
})();
|
javascript/monkeytype_auto_typer.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
(function () {
|
| 2 |
+
console.log("%c Monkeytype Auto-Typer (Anti-Cheat Bypass) Initiated ", "background: #222; color: #00ff00; font-size: 20px");
|
| 3 |
+
|
| 4 |
+
// CONFIGURATION
|
| 5 |
+
const CONFIG = {
|
| 6 |
+
// Delay after you type the first character before the bot takes over (ms)
|
| 7 |
+
startDelay: 50,
|
| 8 |
+
// Delay between characters (ms).
|
| 9 |
+
// 0 = Instant (but risky for some anti-cheats).
|
| 10 |
+
// 10-30 = Super fast but slightly safer.
|
| 11 |
+
typingDelay: 10,
|
| 12 |
+
// If true, types spaces between words.
|
| 13 |
+
typeSpaces: true
|
| 14 |
+
};
|
| 15 |
+
|
| 16 |
+
let isArmed = true;
|
| 17 |
+
|
| 18 |
+
// Helper: Create and dispatch events that look "real"
|
| 19 |
+
function typeChar(char) {
|
| 20 |
+
const target = document.activeElement || document.body;
|
| 21 |
+
|
| 22 |
+
let key = char;
|
| 23 |
+
let code, keyCode;
|
| 24 |
+
|
| 25 |
+
// Handle Space specifically
|
| 26 |
+
if (char === ' ') {
|
| 27 |
+
code = 'Space';
|
| 28 |
+
keyCode = 32;
|
| 29 |
+
}
|
| 30 |
+
// Handle common punctuation to ensure correct codes
|
| 31 |
+
else if (char === '\n') {
|
| 32 |
+
code = 'Enter';
|
| 33 |
+
keyCode = 13;
|
| 34 |
+
}
|
| 35 |
+
else {
|
| 36 |
+
// Very basic mapping. For complex symbols, this might be generic (which usually passes).
|
| 37 |
+
code = `Key${char.toUpperCase()}`;
|
| 38 |
+
keyCode = char.charCodeAt(0);
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
const eventOptions = {
|
| 42 |
+
key: key,
|
| 43 |
+
code: code,
|
| 44 |
+
keyCode: keyCode,
|
| 45 |
+
which: keyCode,
|
| 46 |
+
bubbles: true,
|
| 47 |
+
cancelable: true,
|
| 48 |
+
isTrusted: true // Browser ignores this for script-generated events, but we set it anyway.
|
| 49 |
+
};
|
| 50 |
+
|
| 51 |
+
// 1. Keydown
|
| 52 |
+
target.dispatchEvent(new KeyboardEvent('keydown', eventOptions));
|
| 53 |
+
|
| 54 |
+
// 2. Keypress (Deprecated but some sites check it)
|
| 55 |
+
target.dispatchEvent(new KeyboardEvent('keypress', eventOptions));
|
| 56 |
+
|
| 57 |
+
// 3. Input (Essential for modern frameworks like React/Vue used in Monkeytype)
|
| 58 |
+
const inputEvent = new InputEvent('input', {
|
| 59 |
+
data: char,
|
| 60 |
+
inputType: 'insertText',
|
| 61 |
+
bubbles: true,
|
| 62 |
+
cancelable: true
|
| 63 |
+
});
|
| 64 |
+
target.dispatchEvent(inputEvent);
|
| 65 |
+
|
| 66 |
+
// 4. Keyup
|
| 67 |
+
target.dispatchEvent(new KeyboardEvent('keyup', eventOptions));
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
async function autoType(text) {
|
| 71 |
+
console.log(`Taking over! Typing ${text.length} characters...`);
|
| 72 |
+
|
| 73 |
+
for (let i = 0; i < text.length; i++) {
|
| 74 |
+
typeChar(text[i]);
|
| 75 |
+
// Small delay to prevent freezing the browser and mimic extremely fast typing
|
| 76 |
+
if (CONFIG.typingDelay > 0) {
|
| 77 |
+
await new Promise(r => setTimeout(r, CONFIG.typingDelay));
|
| 78 |
+
}
|
| 79 |
+
}
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
// MAIN LOGIC
|
| 83 |
+
const triggerHandler = (e) => {
|
| 84 |
+
if (!isArmed) return;
|
| 85 |
+
|
| 86 |
+
// We only care about single key presses (no Ctrl/Alt commands)
|
| 87 |
+
// We also ignore if the user is just navigating menus.
|
| 88 |
+
// We assume the user is "starting" the test.
|
| 89 |
+
if (e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey) {
|
| 90 |
+
|
| 91 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 92 |
+
if (!activeWord) return;
|
| 93 |
+
|
| 94 |
+
const firstLetterElement = activeWord.querySelector('letter');
|
| 95 |
+
// Monkeytype sometimes puts the first letter in a slightly different state
|
| 96 |
+
// or we might need to be careful about 'correct' class.
|
| 97 |
+
// But generally, the first letter of the active word is what we need.
|
| 98 |
+
|
| 99 |
+
const firstLetter = firstLetterElement ? firstLetterElement.textContent : null;
|
| 100 |
+
|
| 101 |
+
// CHECK: Did the user type the CORRECT first key?
|
| 102 |
+
if (firstLetter && e.key === firstLetter) {
|
| 103 |
+
isArmed = false; // Disarm immediately
|
| 104 |
+
|
| 105 |
+
// Get ALL remaining text
|
| 106 |
+
const allWords = document.querySelectorAll('#words .word');
|
| 107 |
+
let fullBuffer = "";
|
| 108 |
+
let foundActive = false;
|
| 109 |
+
|
| 110 |
+
allWords.forEach(word => {
|
| 111 |
+
if (word === activeWord) {
|
| 112 |
+
foundActive = true;
|
| 113 |
+
// For the active word, we need to skip the first letter (user just typed it)
|
| 114 |
+
// But wait! If we type too fast, we might conflict with the user's input event processing.
|
| 115 |
+
// So we rebuild the string *including* the rest of this word.
|
| 116 |
+
|
| 117 |
+
const letters = word.querySelectorAll('letter');
|
| 118 |
+
// Start from index 1 (second letter)
|
| 119 |
+
for (let i = 1; i < letters.length; i++) {
|
| 120 |
+
fullBuffer += letters[i].textContent;
|
| 121 |
+
}
|
| 122 |
+
if (CONFIG.typeSpaces) fullBuffer += " ";
|
| 123 |
+
} else if (foundActive) {
|
| 124 |
+
// Future words
|
| 125 |
+
const letters = word.querySelectorAll('letter');
|
| 126 |
+
letters.forEach(l => fullBuffer += l.textContent);
|
| 127 |
+
if (CONFIG.typeSpaces) fullBuffer += " "; // Add space between words
|
| 128 |
+
}
|
| 129 |
+
});
|
| 130 |
+
|
| 131 |
+
// Remove the very last trailing space if it exists (Monkeytype hates extra spaces at end)
|
| 132 |
+
if (fullBuffer.endsWith(" ")) {
|
| 133 |
+
fullBuffer = fullBuffer.slice(0, -1);
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
// Remove listener to prevent checking every single key stroke from now on
|
| 137 |
+
window.removeEventListener('keydown', triggerHandler);
|
| 138 |
+
|
| 139 |
+
console.log("Trigger detected. Typer starting in " + CONFIG.startDelay + "ms");
|
| 140 |
+
|
| 141 |
+
setTimeout(() => {
|
| 142 |
+
autoType(fullBuffer);
|
| 143 |
+
}, CONFIG.startDelay);
|
| 144 |
+
}
|
| 145 |
+
}
|
| 146 |
+
};
|
| 147 |
+
|
| 148 |
+
// Auto-rearm logic (Optional, simple reload usually safer)
|
| 149 |
+
// For now, we just run once per page load to ensure stability.
|
| 150 |
+
window.addEventListener('keydown', triggerHandler);
|
| 151 |
+
|
| 152 |
+
console.log("READY! Start the test by typing the first letter manually.");
|
| 153 |
+
})();
|
javascript/monkeytype_cheat.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
(function () {
|
| 2 |
+
console.log("%c Monkeytype Cheat Initiated (Persistent Mode) ", "background: #222; color: #bada55; font-size: 20px");
|
| 3 |
+
|
| 4 |
+
const keyMap = {
|
| 5 |
+
' ': { code: 'Space', keyCode: 32 },
|
| 6 |
+
'\n': { code: 'Enter', keyCode: 13 },
|
| 7 |
+
};
|
| 8 |
+
|
| 9 |
+
let isArmed = false;
|
| 10 |
+
|
| 11 |
+
function typeChar(char) {
|
| 12 |
+
const target = document.activeElement || document.body;
|
| 13 |
+
let key = char;
|
| 14 |
+
let code, keyCode;
|
| 15 |
+
|
| 16 |
+
if (keyMap[char]) {
|
| 17 |
+
code = keyMap[char].code;
|
| 18 |
+
keyCode = keyMap[char].keyCode;
|
| 19 |
+
} else {
|
| 20 |
+
code = `Key${char.toUpperCase()}`;
|
| 21 |
+
keyCode = char.toUpperCase().charCodeAt(0);
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
const eventOptions = {
|
| 25 |
+
key: key,
|
| 26 |
+
code: code,
|
| 27 |
+
keyCode: keyCode,
|
| 28 |
+
which: keyCode,
|
| 29 |
+
bubbles: true,
|
| 30 |
+
cancelable: true,
|
| 31 |
+
isTrusted: true
|
| 32 |
+
};
|
| 33 |
+
|
| 34 |
+
target.dispatchEvent(new KeyboardEvent('keydown', eventOptions));
|
| 35 |
+
target.dispatchEvent(new KeyboardEvent('keypress', eventOptions));
|
| 36 |
+
|
| 37 |
+
const inputEvent = new InputEvent('input', {
|
| 38 |
+
data: char,
|
| 39 |
+
inputType: 'insertText',
|
| 40 |
+
bubbles: true,
|
| 41 |
+
cancelable: true
|
| 42 |
+
});
|
| 43 |
+
target.dispatchEvent(inputEvent);
|
| 44 |
+
|
| 45 |
+
target.dispatchEvent(new KeyboardEvent('keyup', eventOptions));
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
function getDelay() {
|
| 49 |
+
return 100 + (Math.random() * 60 - 30);
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
async function cheat(textToType) {
|
| 53 |
+
console.log(`Typing ${textToType.length} chars...`);
|
| 54 |
+
for (let i = 0; i < textToType.length; i++) {
|
| 55 |
+
// Check if test was reset mid-run
|
| 56 |
+
if (!document.querySelector('#words .word.active')) {
|
| 57 |
+
console.log("Test reset detected. Stopping current run.");
|
| 58 |
+
return;
|
| 59 |
+
}
|
| 60 |
+
typeChar(textToType[i]);
|
| 61 |
+
await new Promise(r => setTimeout(r, getDelay()));
|
| 62 |
+
}
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
function getFullText() {
|
| 66 |
+
const words = document.querySelectorAll('#words .word');
|
| 67 |
+
let fullBuffer = "";
|
| 68 |
+
words.forEach((word, index) => {
|
| 69 |
+
const letters = word.querySelectorAll('letter');
|
| 70 |
+
letters.forEach(l => fullBuffer += l.textContent);
|
| 71 |
+
if (index < words.length - 1) fullBuffer += " ";
|
| 72 |
+
});
|
| 73 |
+
return fullBuffer;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
const triggerHandler = (e) => {
|
| 77 |
+
if (!isArmed) return;
|
| 78 |
+
|
| 79 |
+
if (e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey) {
|
| 80 |
+
const targetText = getFullText();
|
| 81 |
+
if (!targetText) return;
|
| 82 |
+
|
| 83 |
+
const firstChar = targetText[0];
|
| 84 |
+
if (firstChar && e.key === firstChar) {
|
| 85 |
+
isArmed = false; // Disarm to prevent double trigger
|
| 86 |
+
const remainingText = targetText.substring(1);
|
| 87 |
+
console.log("Triggered! Starting...");
|
| 88 |
+
setTimeout(() => cheat(remainingText), 150);
|
| 89 |
+
}
|
| 90 |
+
}
|
| 91 |
+
};
|
| 92 |
+
|
| 93 |
+
function armCheat() {
|
| 94 |
+
// Debounce slightly to ensure DOM is ready
|
| 95 |
+
setTimeout(() => {
|
| 96 |
+
const text = getFullText();
|
| 97 |
+
if (text.length > 0) {
|
| 98 |
+
isArmed = true;
|
| 99 |
+
console.log("Cheat RE-ARMED. Waiting for first key...");
|
| 100 |
+
} else {
|
| 101 |
+
console.log("Training ended or no words found.");
|
| 102 |
+
}
|
| 103 |
+
}, 500);
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
// LISTENER: Watch for Keydown (Trigger)
|
| 107 |
+
// We add this ONCE and keep it capable of firing whenever 'isArmed' is true.
|
| 108 |
+
window.addEventListener('keydown', triggerHandler);
|
| 109 |
+
|
| 110 |
+
// MUTATION OBSERVER: Watch for "Restart Test"
|
| 111 |
+
// When #words changes (new words added), we re-arm.
|
| 112 |
+
const wordsContainer = document.querySelector('#words');
|
| 113 |
+
if (wordsContainer) {
|
| 114 |
+
const observer = new MutationObserver((mutations) => {
|
| 115 |
+
for (const mutation of mutations) {
|
| 116 |
+
// If words are added/removed, it means test reset/changed
|
| 117 |
+
if (mutation.type === 'childList') {
|
| 118 |
+
// Check if we have new words
|
| 119 |
+
const words = document.querySelectorAll('#words .word');
|
| 120 |
+
if (words.length > 5) { // Arbitrary threshold to ensure it's a real set of words
|
| 121 |
+
armCheat();
|
| 122 |
+
// We break to avoid calling armCheat multiple times per batch update
|
| 123 |
+
break;
|
| 124 |
+
}
|
| 125 |
+
}
|
| 126 |
+
}
|
| 127 |
+
});
|
| 128 |
+
|
| 129 |
+
observer.observe(wordsContainer, { childList: true });
|
| 130 |
+
console.log("Observer attached. Auto-restart enabled.");
|
| 131 |
+
|
| 132 |
+
// Initial Arm
|
| 133 |
+
armCheat();
|
| 134 |
+
} else {
|
| 135 |
+
console.error("Container #words not found. Is the page loaded?");
|
| 136 |
+
}
|
| 137 |
+
})();
|
javascript/monkeytype_custom_text.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
(function () {
|
| 2 |
+
console.log("%c Monkeytype Custom Text Typer Initiated ", "background: #222; color: #00ffff; font-size: 20px");
|
| 3 |
+
|
| 4 |
+
// ==========================================
|
| 5 |
+
// PASTE YOUR TEXT HERE
|
| 6 |
+
// ==========================================
|
| 7 |
+
const CUSTOM_TEXT = "do for between since face can leave where life head all own in be great there state what find back by even";
|
| 8 |
+
// ==========================================
|
| 9 |
+
|
| 10 |
+
const CONFIG = {
|
| 11 |
+
startDelay: 50, // ms to wait after first key
|
| 12 |
+
typingDelay: 1000, // ms between keys
|
| 13 |
+
};
|
| 14 |
+
|
| 15 |
+
let isArmed = true;
|
| 16 |
+
|
| 17 |
+
function typeChar(char) {
|
| 18 |
+
const target = document.activeElement || document.body;
|
| 19 |
+
|
| 20 |
+
let key = char;
|
| 21 |
+
let code, keyCode;
|
| 22 |
+
|
| 23 |
+
if (char === ' ') {
|
| 24 |
+
code = 'Space';
|
| 25 |
+
keyCode = 32;
|
| 26 |
+
}
|
| 27 |
+
else if (char === '\n') {
|
| 28 |
+
code = 'Enter';
|
| 29 |
+
keyCode = 13;
|
| 30 |
+
}
|
| 31 |
+
else {
|
| 32 |
+
code = `Key${char.toUpperCase()}`;
|
| 33 |
+
keyCode = char.charCodeAt(0);
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
const eventOptions = {
|
| 37 |
+
key: key,
|
| 38 |
+
code: code,
|
| 39 |
+
keyCode: keyCode,
|
| 40 |
+
which: keyCode,
|
| 41 |
+
bubbles: true,
|
| 42 |
+
cancelable: true,
|
| 43 |
+
isTrusted: true
|
| 44 |
+
};
|
| 45 |
+
|
| 46 |
+
target.dispatchEvent(new KeyboardEvent('keydown', eventOptions));
|
| 47 |
+
target.dispatchEvent(new KeyboardEvent('keypress', eventOptions));
|
| 48 |
+
|
| 49 |
+
const inputEvent = new InputEvent('input', {
|
| 50 |
+
data: char,
|
| 51 |
+
inputType: 'insertText',
|
| 52 |
+
bubbles: true,
|
| 53 |
+
cancelable: true
|
| 54 |
+
});
|
| 55 |
+
target.dispatchEvent(inputEvent);
|
| 56 |
+
|
| 57 |
+
target.dispatchEvent(new KeyboardEvent('keyup', eventOptions));
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
async function autoType(text) {
|
| 61 |
+
console.log(`Typing custom text (${text.length} chars)...`);
|
| 62 |
+
for (let i = 0; i < text.length; i++) {
|
| 63 |
+
typeChar(text[i]);
|
| 64 |
+
if (CONFIG.typingDelay > 0) {
|
| 65 |
+
await new Promise(r => setTimeout(r, CONFIG.typingDelay));
|
| 66 |
+
}
|
| 67 |
+
}
|
| 68 |
+
console.log("Done!");
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
const triggerHandler = (e) => {
|
| 72 |
+
if (!isArmed) return;
|
| 73 |
+
|
| 74 |
+
// Check if user is typing a single character (no shortcuts)
|
| 75 |
+
if (e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey) {
|
| 76 |
+
|
| 77 |
+
// We use the FIRST character of our CUSTOM_TEXT as the trigger
|
| 78 |
+
const firstCharOfCustom = CUSTOM_TEXT[0];
|
| 79 |
+
|
| 80 |
+
if (firstCharOfCustom && e.key === firstCharOfCustom) {
|
| 81 |
+
isArmed = false;
|
| 82 |
+
window.removeEventListener('keydown', triggerHandler);
|
| 83 |
+
|
| 84 |
+
// We skip the first char because the user just typed it
|
| 85 |
+
const remainingText = CUSTOM_TEXT.substring(1);
|
| 86 |
+
|
| 87 |
+
console.log("Trigger matched! Starting in " + CONFIG.startDelay + "ms...");
|
| 88 |
+
|
| 89 |
+
setTimeout(() => {
|
| 90 |
+
autoType(remainingText);
|
| 91 |
+
}, CONFIG.startDelay);
|
| 92 |
+
}
|
| 93 |
+
}
|
| 94 |
+
};
|
| 95 |
+
|
| 96 |
+
window.addEventListener('keydown', triggerHandler);
|
| 97 |
+
|
| 98 |
+
console.log(`READY! Type the first letter "${CUSTOM_TEXT[0]}" to start.`);
|
| 99 |
+
})();
|
javascript/monkeytype_legacy.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
(function () {
|
| 2 |
+
console.log("%c Monkeytype Legacy / Input Event Typer ", "background: #222; color: #ff00ff; font-size: 20px");
|
| 3 |
+
|
| 4 |
+
const CONFIG = {
|
| 5 |
+
startDelay: 100,
|
| 6 |
+
typingDelay: 20, // Slightly slower to be safe
|
| 7 |
+
};
|
| 8 |
+
|
| 9 |
+
let isArmed = true;
|
| 10 |
+
|
| 11 |
+
// Different method: Focus purely on InputEvent which carries the character
|
| 12 |
+
// Many modern sites (React based) care more about 'beforeinput' and 'input' than keydown.
|
| 13 |
+
function typeChar(char) {
|
| 14 |
+
const target = document.activeElement || document.body;
|
| 15 |
+
|
| 16 |
+
// 1. Dispatch 'beforeinput' (modern standard)
|
| 17 |
+
const beforeInput = new InputEvent('beforeinput', {
|
| 18 |
+
data: char,
|
| 19 |
+
inputType: 'insertText',
|
| 20 |
+
bubbles: true,
|
| 21 |
+
cancelable: true,
|
| 22 |
+
view: window,
|
| 23 |
+
isTrusted: true // We hope...
|
| 24 |
+
});
|
| 25 |
+
target.dispatchEvent(beforeInput);
|
| 26 |
+
|
| 27 |
+
// 2. Dispatch 'input'
|
| 28 |
+
const inputEvent = new InputEvent('input', {
|
| 29 |
+
data: char,
|
| 30 |
+
inputType: 'insertText',
|
| 31 |
+
bubbles: true,
|
| 32 |
+
cancelable: true,
|
| 33 |
+
view: window,
|
| 34 |
+
});
|
| 35 |
+
target.dispatchEvent(inputEvent);
|
| 36 |
+
|
| 37 |
+
// 3. Dispatch 'textInput' (legacy, but sometimes checked)
|
| 38 |
+
if (document.createEvent) {
|
| 39 |
+
const textEvent = document.createEvent('TextEvent');
|
| 40 |
+
textEvent.initTextEvent('textInput', true, true, window, char, 0, "en-US");
|
| 41 |
+
target.dispatchEvent(textEvent);
|
| 42 |
+
}
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
async function autoType(text) {
|
| 46 |
+
console.log(`Typing ${text.length} chars (InputEvent only)...`);
|
| 47 |
+
for (let i = 0; i < text.length; i++) {
|
| 48 |
+
typeChar(text[i]);
|
| 49 |
+
if (CONFIG.typingDelay > 0) {
|
| 50 |
+
await new Promise(r => setTimeout(r, CONFIG.typingDelay));
|
| 51 |
+
}
|
| 52 |
+
}
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
const triggerHandler = (e) => {
|
| 56 |
+
if (!isArmed) return;
|
| 57 |
+
|
| 58 |
+
if (e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey) {
|
| 59 |
+
|
| 60 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 61 |
+
if (!activeWord) return;
|
| 62 |
+
|
| 63 |
+
const firstLetterElement = activeWord.querySelector('letter');
|
| 64 |
+
const firstLetter = firstLetterElement ? firstLetterElement.textContent : null;
|
| 65 |
+
|
| 66 |
+
if (firstLetter && e.key === firstLetter) {
|
| 67 |
+
isArmed = false;
|
| 68 |
+
|
| 69 |
+
// Get ALL remaining text from DOM
|
| 70 |
+
const allWords = document.querySelectorAll('#words .word');
|
| 71 |
+
let fullBuffer = "";
|
| 72 |
+
let foundActive = false;
|
| 73 |
+
|
| 74 |
+
allWords.forEach(word => {
|
| 75 |
+
if (word === activeWord) {
|
| 76 |
+
foundActive = true;
|
| 77 |
+
const letters = word.querySelectorAll('letter');
|
| 78 |
+
// Start from index 1 (user just typed 0)
|
| 79 |
+
for (let i = 1; i < letters.length; i++) {
|
| 80 |
+
fullBuffer += letters[i].textContent;
|
| 81 |
+
}
|
| 82 |
+
fullBuffer += " ";
|
| 83 |
+
} else if (foundActive) {
|
| 84 |
+
const letters = word.querySelectorAll('letter');
|
| 85 |
+
letters.forEach(l => fullBuffer += l.textContent);
|
| 86 |
+
fullBuffer += " ";
|
| 87 |
+
}
|
| 88 |
+
});
|
| 89 |
+
|
| 90 |
+
if (fullBuffer.endsWith(" ")) {
|
| 91 |
+
fullBuffer = fullBuffer.slice(0, -1);
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
window.removeEventListener('keydown', triggerHandler);
|
| 95 |
+
|
| 96 |
+
console.log("Trigger detected. Starting Legacy Typer...");
|
| 97 |
+
setTimeout(() => {
|
| 98 |
+
autoType(fullBuffer);
|
| 99 |
+
}, CONFIG.startDelay);
|
| 100 |
+
}
|
| 101 |
+
}
|
| 102 |
+
};
|
| 103 |
+
|
| 104 |
+
window.addEventListener('keydown', triggerHandler);
|
| 105 |
+
console.log("READY! Type the first letter to test Legacy Mode.");
|
| 106 |
+
})();
|
javascript/script_candidate copy.js
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
(function () {
|
| 2 |
+
console.log("%c Monkeytype Command Typer (execCommand) ", "background: #222; color: #ff0000; font-size: 20px");
|
| 3 |
+
|
| 4 |
+
const CONFIG = {
|
| 5 |
+
minWPM: 250, // Minimum expected WPM
|
| 6 |
+
maxWPM: 350, // Maximum expected WPM
|
| 7 |
+
errorRate: 0.15, // 15% chance to make a mistake
|
| 8 |
+
accuracy: 90, // Target accuracy (affects error correction)
|
| 9 |
+
startDelay: 50, // Delay before starting to type
|
| 10 |
+
};
|
| 11 |
+
|
| 12 |
+
let isArmed = true;
|
| 13 |
+
|
| 14 |
+
// EXECCOMMAND METHOD
|
| 15 |
+
// This often bypasses "isTrusted" checks because it simulates a browser action (paste/insert)
|
| 16 |
+
// rather than a raw key event.
|
| 17 |
+
function typeChar(char) {
|
| 18 |
+
const target = document.activeElement || document.body;
|
| 19 |
+
const keyConfig = {
|
| 20 |
+
key: char,
|
| 21 |
+
code: char === ' ' ? 'Space' : `Key${char.toUpperCase()}`,
|
| 22 |
+
bubbles: true,
|
| 23 |
+
cancelable: true,
|
| 24 |
+
view: window
|
| 25 |
+
};
|
| 26 |
+
|
| 27 |
+
// Dispatch keydown
|
| 28 |
+
target.dispatchEvent(new KeyboardEvent('keydown', keyConfig));
|
| 29 |
+
|
| 30 |
+
// Dispatch keypress (typical for character input)
|
| 31 |
+
target.dispatchEvent(new KeyboardEvent('keypress', keyConfig));
|
| 32 |
+
|
| 33 |
+
// We use insertText which is a powerful way to simulate user input
|
| 34 |
+
document.execCommand('insertText', false, char);
|
| 35 |
+
|
| 36 |
+
// Dispatch input event (execCommand usually triggers this, but to be safe)
|
| 37 |
+
// target.dispatchEvent(new InputEvent('input', { data: char, inputType: 'insertText', bubbles: true }));
|
| 38 |
+
|
| 39 |
+
// Dispatch keyup
|
| 40 |
+
target.dispatchEvent(new KeyboardEvent('keyup', keyConfig));
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
// Helper to sleep for a random duration
|
| 44 |
+
function sleep(ms) {
|
| 45 |
+
return new Promise(resolve => setTimeout(resolve, ms));
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
// Calculate dynamic delay based on WPM
|
| 49 |
+
// Standard word length is 5 chars. WPM = (Chars / 5) / (Time_min)
|
| 50 |
+
// Time_char_ms = (60000 / (WPM * 5))
|
| 51 |
+
function getKeystrokeDelay() {
|
| 52 |
+
// Pick a random WPM between min and max
|
| 53 |
+
const currentWPM = Math.floor(Math.random() * (CONFIG.maxWPM - CONFIG.minWPM + 1)) + CONFIG.minWPM;
|
| 54 |
+
const baseDelay = 60000 / (currentWPM * 5);
|
| 55 |
+
|
| 56 |
+
// Add some noise: +/- 20% variance per keystroke
|
| 57 |
+
const variance = baseDelay * 0.2;
|
| 58 |
+
const noise = (Math.random() * variance * 2) - variance;
|
| 59 |
+
|
| 60 |
+
return Math.max(10, baseDelay + noise); // Ensure delay is at least 10ms
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
async function simulateMistake(correctChar) {
|
| 64 |
+
const possibleMistakes = "abcdefghijklmnopqrstuvwxyz";
|
| 65 |
+
const distinctMistake = possibleMistakes.charAt(Math.floor(Math.random() * possibleMistakes.length));
|
| 66 |
+
|
| 67 |
+
// Type wrong char
|
| 68 |
+
typeChar(distinctMistake);
|
| 69 |
+
|
| 70 |
+
// Realization reaction time (slower than typing)
|
| 71 |
+
await sleep(getKeystrokeDelay() * 2.5);
|
| 72 |
+
|
| 73 |
+
// Backspace - simulate by selecting and deleting or execCommand delete?
|
| 74 |
+
// execCommand 'delete' works well for single char deletion
|
| 75 |
+
// Dispatch Backspace events
|
| 76 |
+
const target = document.activeElement || document.body;
|
| 77 |
+
const bsConfig = { key: 'Backspace', code: 'Backspace', bubbles: true, cancelable: true, view: window };
|
| 78 |
+
|
| 79 |
+
target.dispatchEvent(new KeyboardEvent('keydown', bsConfig));
|
| 80 |
+
document.execCommand('delete', false, null);
|
| 81 |
+
target.dispatchEvent(new KeyboardEvent('keyup', bsConfig));
|
| 82 |
+
|
| 83 |
+
// Correction pause
|
| 84 |
+
await sleep(getKeystrokeDelay() * 1.5);
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
async function autoType(text) {
|
| 88 |
+
console.log(`Typing ${text.length} chars (Human-Like Method)...`);
|
| 89 |
+
|
| 90 |
+
for (let i = 0; i < text.length; i++) {
|
| 91 |
+
const char = text[i];
|
| 92 |
+
|
| 93 |
+
// Check for mistake opportunity (only on alpha characters, not spaces)
|
| 94 |
+
if (/[a-zA-Z]/.test(char) && Math.random() < CONFIG.errorRate) {
|
| 95 |
+
// Determine if we should correct it immediately (high accuracy simulation)
|
| 96 |
+
// For now, always correct immediately
|
| 97 |
+
await simulateMistake(char);
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
typeChar(char);
|
| 101 |
+
|
| 102 |
+
let delay = getKeystrokeDelay();
|
| 103 |
+
|
| 104 |
+
// Pause longer on word boundaries (spaces)
|
| 105 |
+
if (char === ' ') {
|
| 106 |
+
delay *= 1.3;
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
await sleep(delay);
|
| 110 |
+
}
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
const triggerHandler = (e) => {
|
| 114 |
+
if (!isArmed) return;
|
| 115 |
+
|
| 116 |
+
if (e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey) {
|
| 117 |
+
|
| 118 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 119 |
+
if (!activeWord) return;
|
| 120 |
+
|
| 121 |
+
const firstLetterElement = activeWord.querySelector('letter');
|
| 122 |
+
const firstLetter = firstLetterElement ? firstLetterElement.textContent : null;
|
| 123 |
+
|
| 124 |
+
if (firstLetter && e.key === firstLetter) {
|
| 125 |
+
isArmed = false;
|
| 126 |
+
|
| 127 |
+
// Fetch text similar to before
|
| 128 |
+
const allWords = document.querySelectorAll('#words .word');
|
| 129 |
+
let fullBuffer = "";
|
| 130 |
+
let foundActive = false;
|
| 131 |
+
|
| 132 |
+
allWords.forEach(word => {
|
| 133 |
+
if (word === activeWord) {
|
| 134 |
+
foundActive = true;
|
| 135 |
+
const letters = word.querySelectorAll('letter');
|
| 136 |
+
for (let i = 1; i < letters.length; i++) {
|
| 137 |
+
fullBuffer += letters[i].textContent;
|
| 138 |
+
}
|
| 139 |
+
fullBuffer += " ";
|
| 140 |
+
} else if (foundActive) {
|
| 141 |
+
const letters = word.querySelectorAll('letter');
|
| 142 |
+
letters.forEach(l => fullBuffer += l.textContent);
|
| 143 |
+
fullBuffer += " ";
|
| 144 |
+
}
|
| 145 |
+
});
|
| 146 |
+
|
| 147 |
+
if (fullBuffer.endsWith(" ")) {
|
| 148 |
+
fullBuffer = fullBuffer.slice(0, -1);
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
window.removeEventListener('keydown', triggerHandler);
|
| 152 |
+
|
| 153 |
+
console.log("Trigger detected. Starting Command Typer...");
|
| 154 |
+
setTimeout(() => {
|
| 155 |
+
autoType(fullBuffer);
|
| 156 |
+
}, CONFIG.startDelay);
|
| 157 |
+
}
|
| 158 |
+
}
|
| 159 |
+
};
|
| 160 |
+
|
| 161 |
+
window.addEventListener('keydown', triggerHandler);
|
| 162 |
+
console.log("READY! Type the first letter to test Command Mode.");
|
| 163 |
+
})();
|
javascript/script_candidate copy1.js
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
(function () {
|
| 2 |
+
console.log("%c Monkeytype Command Typer (execCommand) ", "background: #222; color: #ff0000; font-size: 20px");
|
| 3 |
+
|
| 4 |
+
const CONFIG = {
|
| 5 |
+
minWPM: 310, // Minimum expected WPM
|
| 6 |
+
maxWPM: 550, // Maximum expected WPM
|
| 7 |
+
errorRate: 0.05, // 15% chance to make a mistake
|
| 8 |
+
accuracy: 95, // Target accuracy (affects error correction)
|
| 9 |
+
startDelay: 50, // Delay before starting to type
|
| 10 |
+
};
|
| 11 |
+
|
| 12 |
+
let isArmed = true;
|
| 13 |
+
|
| 14 |
+
// EXECCOMMAND METHOD
|
| 15 |
+
// This often bypasses "isTrusted" checks because it simulates a browser action (paste/insert)
|
| 16 |
+
// rather than a raw key event.
|
| 17 |
+
function typeChar(char) {
|
| 18 |
+
const target = document.activeElement || document.body;
|
| 19 |
+
const keyConfig = {
|
| 20 |
+
key: char,
|
| 21 |
+
code: char === ' ' ? 'Space' : `Key${char.toUpperCase()}`,
|
| 22 |
+
bubbles: true,
|
| 23 |
+
cancelable: true,
|
| 24 |
+
view: window
|
| 25 |
+
};
|
| 26 |
+
|
| 27 |
+
// Dispatch keydown
|
| 28 |
+
target.dispatchEvent(new KeyboardEvent('keydown', keyConfig));
|
| 29 |
+
|
| 30 |
+
// Dispatch keypress (typical for character input)
|
| 31 |
+
target.dispatchEvent(new KeyboardEvent('keypress', keyConfig));
|
| 32 |
+
|
| 33 |
+
// We use insertText which is a powerful way to simulate user input
|
| 34 |
+
document.execCommand('insertText', false, char);
|
| 35 |
+
|
| 36 |
+
// Dispatch input event (execCommand usually triggers this, but to be safe)
|
| 37 |
+
// target.dispatchEvent(new InputEvent('input', { data: char, inputType: 'insertText', bubbles: true }));
|
| 38 |
+
|
| 39 |
+
// Dispatch keyup
|
| 40 |
+
target.dispatchEvent(new KeyboardEvent('keyup', keyConfig));
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
// Helper to sleep for a random duration
|
| 44 |
+
function sleep(ms) {
|
| 45 |
+
return new Promise(resolve => setTimeout(resolve, ms));
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
// Calculate dynamic delay based on WPM
|
| 49 |
+
// Standard word length is 5 chars. WPM = (Chars / 5) / (Time_min)
|
| 50 |
+
// Time_char_ms = (60000 / (WPM * 5))
|
| 51 |
+
function getKeystrokeDelay() {
|
| 52 |
+
// Pick a random WPM between min and max
|
| 53 |
+
const currentWPM = Math.floor(Math.random() * (CONFIG.maxWPM - CONFIG.minWPM + 1)) + CONFIG.minWPM;
|
| 54 |
+
const baseDelay = 60000 / (currentWPM * 5);
|
| 55 |
+
|
| 56 |
+
// Add some noise: +/- 20% variance per keystroke
|
| 57 |
+
const variance = baseDelay * 0.2;
|
| 58 |
+
const noise = (Math.random() * variance * 2) - variance;
|
| 59 |
+
|
| 60 |
+
return Math.max(10, baseDelay + noise); // Ensure delay is at least 10ms
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
async function simulateMistake(correctChar) {
|
| 64 |
+
const possibleMistakes = "abcdefghijklmnopqrstuvwxyz";
|
| 65 |
+
const distinctMistake = possibleMistakes.charAt(Math.floor(Math.random() * possibleMistakes.length));
|
| 66 |
+
|
| 67 |
+
// Type wrong char
|
| 68 |
+
typeChar(distinctMistake);
|
| 69 |
+
|
| 70 |
+
// Realization reaction time (slower than typing)
|
| 71 |
+
await sleep(getKeystrokeDelay() * 2.5);
|
| 72 |
+
|
| 73 |
+
// Backspace - simulate by selecting and deleting or execCommand delete?
|
| 74 |
+
// execCommand 'delete' works well for single char deletion
|
| 75 |
+
// Dispatch Backspace events
|
| 76 |
+
const target = document.activeElement || document.body;
|
| 77 |
+
const bsConfig = { key: 'Backspace', code: 'Backspace', bubbles: true, cancelable: true, view: window };
|
| 78 |
+
|
| 79 |
+
target.dispatchEvent(new KeyboardEvent('keydown', bsConfig));
|
| 80 |
+
document.execCommand('delete', false, null);
|
| 81 |
+
target.dispatchEvent(new KeyboardEvent('keyup', bsConfig));
|
| 82 |
+
|
| 83 |
+
// Correction pause
|
| 84 |
+
await sleep(getKeystrokeDelay() * 1.5);
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
// Get the current word text that needs to be typed (remaining letters)
|
| 88 |
+
function getCurrentWordText() {
|
| 89 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 90 |
+
if (!activeWord) return null;
|
| 91 |
+
|
| 92 |
+
const letters = activeWord.querySelectorAll('letter');
|
| 93 |
+
let text = "";
|
| 94 |
+
let foundUntyped = false;
|
| 95 |
+
|
| 96 |
+
for (const letter of letters) {
|
| 97 |
+
// Check if this letter hasn't been typed yet (no 'correct' or 'incorrect' class)
|
| 98 |
+
if (!letter.classList.contains('correct') && !letter.classList.contains('incorrect')) {
|
| 99 |
+
foundUntyped = true;
|
| 100 |
+
}
|
| 101 |
+
if (foundUntyped) {
|
| 102 |
+
text += letter.textContent;
|
| 103 |
+
}
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
return text;
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
// Main typing loop - continuously fetches words from DOM
|
| 110 |
+
async function autoTypeLoop() {
|
| 111 |
+
console.log("Starting continuous auto-type loop...");
|
| 112 |
+
|
| 113 |
+
let wordCount = 0;
|
| 114 |
+
while (true) {
|
| 115 |
+
// Get current word's remaining text
|
| 116 |
+
const currentWordText = getCurrentWordText();
|
| 117 |
+
|
| 118 |
+
if (currentWordText === null) {
|
| 119 |
+
// No active word found - test might be complete
|
| 120 |
+
console.log(`Auto-type complete! Typed ${wordCount} words.`);
|
| 121 |
+
break;
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
if (currentWordText.length === 0) {
|
| 125 |
+
// Current word is fully typed, need to press space
|
| 126 |
+
// But first check if there's another word coming
|
| 127 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 128 |
+
const nextWord = activeWord ? activeWord.nextElementSibling : null;
|
| 129 |
+
|
| 130 |
+
if (!nextWord || !nextWord.classList.contains('word')) {
|
| 131 |
+
// Might be at the end, wait a bit and check again
|
| 132 |
+
await sleep(50);
|
| 133 |
+
const stillActive = document.querySelector('#words .word.active');
|
| 134 |
+
if (!stillActive) {
|
| 135 |
+
console.log(`Auto-type complete! Typed ${wordCount} words.`);
|
| 136 |
+
break;
|
| 137 |
+
}
|
| 138 |
+
continue;
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
// Type space to move to next word
|
| 142 |
+
typeChar(' ');
|
| 143 |
+
wordCount++;
|
| 144 |
+
|
| 145 |
+
let delay = getKeystrokeDelay() * 1.3; // Longer pause between words
|
| 146 |
+
await sleep(delay);
|
| 147 |
+
continue;
|
| 148 |
+
}
|
| 149 |
+
|
| 150 |
+
// Type the next character
|
| 151 |
+
const char = currentWordText[0];
|
| 152 |
+
|
| 153 |
+
// Check for mistake opportunity (only on alpha characters)
|
| 154 |
+
if (/[a-zA-Z]/.test(char) && Math.random() < CONFIG.errorRate) {
|
| 155 |
+
await simulateMistake(char);
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
typeChar(char);
|
| 159 |
+
|
| 160 |
+
let delay = getKeystrokeDelay();
|
| 161 |
+
await sleep(delay);
|
| 162 |
+
}
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
const triggerHandler = (e) => {
|
| 166 |
+
if (!isArmed) return;
|
| 167 |
+
|
| 168 |
+
if (e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey) {
|
| 169 |
+
|
| 170 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 171 |
+
if (!activeWord) return;
|
| 172 |
+
|
| 173 |
+
const firstLetterElement = activeWord.querySelector('letter');
|
| 174 |
+
const firstLetter = firstLetterElement ? firstLetterElement.textContent : null;
|
| 175 |
+
|
| 176 |
+
if (firstLetter && e.key === firstLetter) {
|
| 177 |
+
isArmed = false;
|
| 178 |
+
window.removeEventListener('keydown', triggerHandler);
|
| 179 |
+
|
| 180 |
+
console.log("Trigger detected. Starting Command Typer...");
|
| 181 |
+
setTimeout(() => {
|
| 182 |
+
autoTypeLoop();
|
| 183 |
+
}, CONFIG.startDelay);
|
| 184 |
+
}
|
| 185 |
+
}
|
| 186 |
+
};
|
| 187 |
+
|
| 188 |
+
window.addEventListener('keydown', triggerHandler);
|
| 189 |
+
console.log("READY! Type the first letter to test Command Mode.");
|
| 190 |
+
})();
|
javascript/script_candidate copy2.js
ADDED
|
@@ -0,0 +1,461 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
(function () {
|
| 2 |
+
console.log("%c Monkeytype Command Typer (Human-Like) ", "background: #222; color: #ff0000; font-size: 20px");
|
| 3 |
+
|
| 4 |
+
const CONFIG = {
|
| 5 |
+
minWPM: 310, // Minimum expected WPM
|
| 6 |
+
maxWPM: 550, // Maximum expected WPM
|
| 7 |
+
startDelay: 50, // Delay before starting to type
|
| 8 |
+
|
| 9 |
+
// === HUMAN IMPERFECTION RATES ===
|
| 10 |
+
// Wrong character (random letter instead of correct one)
|
| 11 |
+
wrongCharRate: 0.025,
|
| 12 |
+
|
| 13 |
+
// Adjacent key typo (hit a nearby key on keyboard)
|
| 14 |
+
adjacentKeyRate: 0.02,
|
| 15 |
+
|
| 16 |
+
// Double/triple letter (accidentally press key multiple times)
|
| 17 |
+
doubleLetterRate: 0.015,
|
| 18 |
+
tripleLetterRate: 0.003,
|
| 19 |
+
|
| 20 |
+
// Skip letter (finger moved too fast, missed a key)
|
| 21 |
+
skipLetterRate: 0.01,
|
| 22 |
+
|
| 23 |
+
// Transposed letters (swap two adjacent letters like "teh" instead of "the")
|
| 24 |
+
transposeRate: 0.012,
|
| 25 |
+
|
| 26 |
+
// Ctrl+Backspace (delete whole word when frustrated)
|
| 27 |
+
ctrlBackspaceRate: 0.008,
|
| 28 |
+
|
| 29 |
+
// Hesitation/thinking pause (longer pause before difficult letters)
|
| 30 |
+
hesitationRate: 0.04,
|
| 31 |
+
hesitationMultiplier: 3.5, // How much longer the pause is
|
| 32 |
+
|
| 33 |
+
// Burst typing (fast typing followed by slowdown)
|
| 34 |
+
burstTypingRate: 0.08,
|
| 35 |
+
burstSpeedMultiplier: 0.5, // Faster during burst
|
| 36 |
+
burstLength: 5, // Characters in burst
|
| 37 |
+
|
| 38 |
+
// Slow start to words (first letter of word typed slower)
|
| 39 |
+
wordStartSlowdown: 1.8,
|
| 40 |
+
|
| 41 |
+
// Fatigue simulation (gradually slow down over time)
|
| 42 |
+
fatigueEnabled: true,
|
| 43 |
+
fatigueRate: 0.0001, // How much to slow down per character
|
| 44 |
+
|
| 45 |
+
// Recovery pause after mistakes (humans pause after making errors)
|
| 46 |
+
postMistakePauseMultiplier: 2.0,
|
| 47 |
+
};
|
| 48 |
+
|
| 49 |
+
// QWERTY keyboard adjacency map for realistic typos
|
| 50 |
+
const ADJACENT_KEYS = {
|
| 51 |
+
'a': ['q', 'w', 's', 'z'],
|
| 52 |
+
'b': ['v', 'g', 'h', 'n'],
|
| 53 |
+
'c': ['x', 'd', 'f', 'v'],
|
| 54 |
+
'd': ['s', 'e', 'r', 'f', 'c', 'x'],
|
| 55 |
+
'e': ['w', 's', 'd', 'r'],
|
| 56 |
+
'f': ['d', 'r', 't', 'g', 'v', 'c'],
|
| 57 |
+
'g': ['f', 't', 'y', 'h', 'b', 'v'],
|
| 58 |
+
'h': ['g', 'y', 'u', 'j', 'n', 'b'],
|
| 59 |
+
'i': ['u', 'j', 'k', 'o'],
|
| 60 |
+
'j': ['h', 'u', 'i', 'k', 'm', 'n'],
|
| 61 |
+
'k': ['j', 'i', 'o', 'l', 'm'],
|
| 62 |
+
'l': ['k', 'o', 'p'],
|
| 63 |
+
'm': ['n', 'j', 'k'],
|
| 64 |
+
'n': ['b', 'h', 'j', 'm'],
|
| 65 |
+
'o': ['i', 'k', 'l', 'p'],
|
| 66 |
+
'p': ['o', 'l'],
|
| 67 |
+
'q': ['w', 'a'],
|
| 68 |
+
'r': ['e', 'd', 'f', 't'],
|
| 69 |
+
's': ['a', 'w', 'e', 'd', 'x', 'z'],
|
| 70 |
+
't': ['r', 'f', 'g', 'y'],
|
| 71 |
+
'u': ['y', 'h', 'j', 'i'],
|
| 72 |
+
'v': ['c', 'f', 'g', 'b'],
|
| 73 |
+
'w': ['q', 'a', 's', 'e'],
|
| 74 |
+
'x': ['z', 's', 'd', 'c'],
|
| 75 |
+
'y': ['t', 'g', 'h', 'u'],
|
| 76 |
+
'z': ['a', 's', 'x'],
|
| 77 |
+
};
|
| 78 |
+
|
| 79 |
+
let isArmed = true;
|
| 80 |
+
let inBurstMode = false;
|
| 81 |
+
let burstCharsRemaining = 0;
|
| 82 |
+
let totalCharsTyped = 0;
|
| 83 |
+
let recentMistake = false;
|
| 84 |
+
|
| 85 |
+
// Type a single character
|
| 86 |
+
function typeChar(char) {
|
| 87 |
+
const target = document.activeElement || document.body;
|
| 88 |
+
const keyConfig = {
|
| 89 |
+
key: char,
|
| 90 |
+
code: char === ' ' ? 'Space' : `Key${char.toUpperCase()}`,
|
| 91 |
+
bubbles: true,
|
| 92 |
+
cancelable: true,
|
| 93 |
+
view: window
|
| 94 |
+
};
|
| 95 |
+
|
| 96 |
+
target.dispatchEvent(new KeyboardEvent('keydown', keyConfig));
|
| 97 |
+
target.dispatchEvent(new KeyboardEvent('keypress', keyConfig));
|
| 98 |
+
document.execCommand('insertText', false, char);
|
| 99 |
+
target.dispatchEvent(new KeyboardEvent('keyup', keyConfig));
|
| 100 |
+
|
| 101 |
+
totalCharsTyped++;
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
// Single backspace
|
| 105 |
+
function typeBackspace() {
|
| 106 |
+
const target = document.activeElement || document.body;
|
| 107 |
+
const bsConfig = { key: 'Backspace', code: 'Backspace', bubbles: true, cancelable: true, view: window };
|
| 108 |
+
target.dispatchEvent(new KeyboardEvent('keydown', bsConfig));
|
| 109 |
+
document.execCommand('delete', false, null);
|
| 110 |
+
target.dispatchEvent(new KeyboardEvent('keyup', bsConfig));
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
// Ctrl+Backspace to delete whole word
|
| 114 |
+
function typeCtrlBackspace() {
|
| 115 |
+
const target = document.activeElement || document.body;
|
| 116 |
+
const ctrlBsConfig = {
|
| 117 |
+
key: 'Backspace',
|
| 118 |
+
code: 'Backspace',
|
| 119 |
+
ctrlKey: true,
|
| 120 |
+
bubbles: true,
|
| 121 |
+
cancelable: true,
|
| 122 |
+
view: window
|
| 123 |
+
};
|
| 124 |
+
|
| 125 |
+
target.dispatchEvent(new KeyboardEvent('keydown', ctrlBsConfig));
|
| 126 |
+
|
| 127 |
+
// Delete characters until we hit a space or beginning
|
| 128 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 129 |
+
if (activeWord) {
|
| 130 |
+
const incorrectLetters = activeWord.querySelectorAll('letter.incorrect, letter.extra');
|
| 131 |
+
incorrectLetters.forEach(() => {
|
| 132 |
+
document.execCommand('delete', false, null);
|
| 133 |
+
});
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
target.dispatchEvent(new KeyboardEvent('keyup', ctrlBsConfig));
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
function sleep(ms) {
|
| 140 |
+
return new Promise(resolve => setTimeout(resolve, ms));
|
| 141 |
+
}
|
| 142 |
+
|
| 143 |
+
// Get adjacent key for realistic typo
|
| 144 |
+
function getAdjacentKey(char) {
|
| 145 |
+
const lowerChar = char.toLowerCase();
|
| 146 |
+
const adjacent = ADJACENT_KEYS[lowerChar];
|
| 147 |
+
if (adjacent && adjacent.length > 0) {
|
| 148 |
+
const randomAdj = adjacent[Math.floor(Math.random() * adjacent.length)];
|
| 149 |
+
return char === char.toUpperCase() ? randomAdj.toUpperCase() : randomAdj;
|
| 150 |
+
}
|
| 151 |
+
return char; // Fallback to same char if no adjacent found
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
// Get random wrong character
|
| 155 |
+
function getRandomChar() {
|
| 156 |
+
const chars = "abcdefghijklmnopqrstuvwxyz";
|
| 157 |
+
return chars.charAt(Math.floor(Math.random() * chars.length));
|
| 158 |
+
}
|
| 159 |
+
|
| 160 |
+
// Calculate keystroke delay with fatigue and burst mode
|
| 161 |
+
function getKeystrokeDelay() {
|
| 162 |
+
const currentWPM = Math.floor(Math.random() * (CONFIG.maxWPM - CONFIG.minWPM + 1)) + CONFIG.minWPM;
|
| 163 |
+
let baseDelay = 60000 / (currentWPM * 5);
|
| 164 |
+
|
| 165 |
+
// Apply fatigue (gradually slow down)
|
| 166 |
+
if (CONFIG.fatigueEnabled) {
|
| 167 |
+
baseDelay *= (1 + totalCharsTyped * CONFIG.fatigueRate);
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
// Apply burst mode (faster typing)
|
| 171 |
+
if (inBurstMode && burstCharsRemaining > 0) {
|
| 172 |
+
baseDelay *= CONFIG.burstSpeedMultiplier;
|
| 173 |
+
burstCharsRemaining--;
|
| 174 |
+
if (burstCharsRemaining === 0) {
|
| 175 |
+
inBurstMode = false;
|
| 176 |
+
}
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
// Add variance
|
| 180 |
+
const variance = baseDelay * 0.25;
|
| 181 |
+
const noise = (Math.random() * variance * 2) - variance;
|
| 182 |
+
|
| 183 |
+
return Math.max(8, baseDelay + noise);
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
// Get current word's remaining untyped text
|
| 187 |
+
function getCurrentWordText() {
|
| 188 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 189 |
+
if (!activeWord) return null;
|
| 190 |
+
|
| 191 |
+
const letters = activeWord.querySelectorAll('letter');
|
| 192 |
+
let text = "";
|
| 193 |
+
let foundUntyped = false;
|
| 194 |
+
|
| 195 |
+
for (const letter of letters) {
|
| 196 |
+
if (!letter.classList.contains('correct') && !letter.classList.contains('incorrect')) {
|
| 197 |
+
foundUntyped = true;
|
| 198 |
+
}
|
| 199 |
+
if (foundUntyped) {
|
| 200 |
+
text += letter.textContent;
|
| 201 |
+
}
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
return text;
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
// Count how many incorrect letters we've typed in current word
|
| 208 |
+
function getIncorrectCount() {
|
| 209 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 210 |
+
if (!activeWord) return 0;
|
| 211 |
+
return activeWord.querySelectorAll('letter.incorrect, letter.extra').length;
|
| 212 |
+
}
|
| 213 |
+
|
| 214 |
+
// Check if we're at the start of a word
|
| 215 |
+
function isWordStart() {
|
| 216 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 217 |
+
if (!activeWord) return false;
|
| 218 |
+
const typed = activeWord.querySelectorAll('letter.correct, letter.incorrect');
|
| 219 |
+
return typed.length === 0;
|
| 220 |
+
}
|
| 221 |
+
|
| 222 |
+
// === MISTAKE SIMULATION FUNCTIONS ===
|
| 223 |
+
|
| 224 |
+
// Type wrong character and correct it
|
| 225 |
+
async function simulateWrongChar(correctChar) {
|
| 226 |
+
const wrongChar = getRandomChar();
|
| 227 |
+
typeChar(wrongChar);
|
| 228 |
+
await sleep(getKeystrokeDelay() * 2.5);
|
| 229 |
+
typeBackspace();
|
| 230 |
+
await sleep(getKeystrokeDelay() * 1.5);
|
| 231 |
+
recentMistake = true;
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
// Type adjacent key typo and correct it
|
| 235 |
+
async function simulateAdjacentKeyTypo(correctChar) {
|
| 236 |
+
const adjacentChar = getAdjacentKey(correctChar);
|
| 237 |
+
if (adjacentChar !== correctChar) {
|
| 238 |
+
typeChar(adjacentChar);
|
| 239 |
+
await sleep(getKeystrokeDelay() * 2.2);
|
| 240 |
+
typeBackspace();
|
| 241 |
+
await sleep(getKeystrokeDelay() * 1.3);
|
| 242 |
+
recentMistake = true;
|
| 243 |
+
}
|
| 244 |
+
}
|
| 245 |
+
|
| 246 |
+
// Double or triple letter mistake
|
| 247 |
+
async function simulateDoubleLetter(char, count = 2) {
|
| 248 |
+
// Type the correct char first, then extra(s)
|
| 249 |
+
for (let i = 1; i < count; i++) {
|
| 250 |
+
typeChar(char);
|
| 251 |
+
await sleep(getKeystrokeDelay() * 0.3); // Very fast double tap
|
| 252 |
+
}
|
| 253 |
+
// Pause to realize mistake
|
| 254 |
+
await sleep(getKeystrokeDelay() * 2.0);
|
| 255 |
+
// Delete the extras
|
| 256 |
+
for (let i = 1; i < count; i++) {
|
| 257 |
+
typeBackspace();
|
| 258 |
+
await sleep(getKeystrokeDelay() * 0.5);
|
| 259 |
+
}
|
| 260 |
+
await sleep(getKeystrokeDelay() * 1.2);
|
| 261 |
+
recentMistake = true;
|
| 262 |
+
}
|
| 263 |
+
|
| 264 |
+
// Skip a letter (will be detected as wrong, then backspace and fix)
|
| 265 |
+
async function simulateSkipLetter() {
|
| 266 |
+
// The letter gets skipped - we don't type it
|
| 267 |
+
// The next letter will be typed in its place
|
| 268 |
+
// This creates a natural error that gets corrected
|
| 269 |
+
return true; // Signal that we should skip
|
| 270 |
+
}
|
| 271 |
+
|
| 272 |
+
// Transpose two letters (type in wrong order, then fix)
|
| 273 |
+
async function simulateTranspose(char1, char2) {
|
| 274 |
+
// Type second char first
|
| 275 |
+
typeChar(char2);
|
| 276 |
+
await sleep(getKeystrokeDelay() * 0.4);
|
| 277 |
+
// Type first char second
|
| 278 |
+
typeChar(char1);
|
| 279 |
+
await sleep(getKeystrokeDelay() * 2.5);
|
| 280 |
+
// Delete both
|
| 281 |
+
typeBackspace();
|
| 282 |
+
await sleep(getKeystrokeDelay() * 0.4);
|
| 283 |
+
typeBackspace();
|
| 284 |
+
await sleep(getKeystrokeDelay() * 1.5);
|
| 285 |
+
recentMistake = true;
|
| 286 |
+
// Return true so main loop knows we handled these chars
|
| 287 |
+
return true;
|
| 288 |
+
}
|
| 289 |
+
|
| 290 |
+
// Use Ctrl+Backspace to clear word and retype
|
| 291 |
+
async function simulateCtrlBackspace() {
|
| 292 |
+
const incorrectCount = getIncorrectCount();
|
| 293 |
+
if (incorrectCount > 2) {
|
| 294 |
+
await sleep(getKeystrokeDelay() * 3); // Frustration pause
|
| 295 |
+
typeCtrlBackspace();
|
| 296 |
+
await sleep(getKeystrokeDelay() * 2);
|
| 297 |
+
recentMistake = true;
|
| 298 |
+
return true;
|
| 299 |
+
}
|
| 300 |
+
return false;
|
| 301 |
+
}
|
| 302 |
+
|
| 303 |
+
// Main typing loop with all human imperfections
|
| 304 |
+
async function autoTypeLoop() {
|
| 305 |
+
console.log("Starting human-like auto-type loop...");
|
| 306 |
+
console.log("Active imperfections: wrong char, adjacent key, double/triple letter, skip, transpose, Ctrl+Backspace, hesitation, burst typing, fatigue");
|
| 307 |
+
|
| 308 |
+
let wordCount = 0;
|
| 309 |
+
let skipNext = false;
|
| 310 |
+
|
| 311 |
+
while (true) {
|
| 312 |
+
const currentWordText = getCurrentWordText();
|
| 313 |
+
|
| 314 |
+
if (currentWordText === null) {
|
| 315 |
+
console.log(`Auto-type complete! Typed ${wordCount} words, ${totalCharsTyped} characters.`);
|
| 316 |
+
break;
|
| 317 |
+
}
|
| 318 |
+
|
| 319 |
+
// Check if we should use Ctrl+Backspace (when frustrated with errors)
|
| 320 |
+
if (Math.random() < CONFIG.ctrlBackspaceRate) {
|
| 321 |
+
const didCtrlBackspace = await simulateCtrlBackspace();
|
| 322 |
+
if (didCtrlBackspace) continue;
|
| 323 |
+
}
|
| 324 |
+
|
| 325 |
+
if (currentWordText.length === 0) {
|
| 326 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 327 |
+
const nextWord = activeWord ? activeWord.nextElementSibling : null;
|
| 328 |
+
|
| 329 |
+
if (!nextWord || !nextWord.classList.contains('word')) {
|
| 330 |
+
await sleep(50);
|
| 331 |
+
const stillActive = document.querySelector('#words .word.active');
|
| 332 |
+
if (!stillActive) {
|
| 333 |
+
console.log(`Auto-type complete! Typed ${wordCount} words.`);
|
| 334 |
+
break;
|
| 335 |
+
}
|
| 336 |
+
continue;
|
| 337 |
+
}
|
| 338 |
+
|
| 339 |
+
typeChar(' ');
|
| 340 |
+
wordCount++;
|
| 341 |
+
|
| 342 |
+
// Longer pause between words
|
| 343 |
+
let delay = getKeystrokeDelay() * 1.4;
|
| 344 |
+
await sleep(delay);
|
| 345 |
+
continue;
|
| 346 |
+
}
|
| 347 |
+
|
| 348 |
+
const char = currentWordText[0];
|
| 349 |
+
const nextChar = currentWordText.length > 1 ? currentWordText[1] : null;
|
| 350 |
+
let delay = getKeystrokeDelay();
|
| 351 |
+
|
| 352 |
+
// === APPLY HUMAN IMPERFECTIONS ===
|
| 353 |
+
|
| 354 |
+
// Slow start to words
|
| 355 |
+
if (isWordStart()) {
|
| 356 |
+
delay *= CONFIG.wordStartSlowdown;
|
| 357 |
+
}
|
| 358 |
+
|
| 359 |
+
// Random hesitation (thinking pause)
|
| 360 |
+
if (Math.random() < CONFIG.hesitationRate) {
|
| 361 |
+
delay *= CONFIG.hesitationMultiplier;
|
| 362 |
+
}
|
| 363 |
+
|
| 364 |
+
// Post-mistake recovery pause
|
| 365 |
+
if (recentMistake) {
|
| 366 |
+
delay *= CONFIG.postMistakePauseMultiplier;
|
| 367 |
+
recentMistake = false;
|
| 368 |
+
}
|
| 369 |
+
|
| 370 |
+
// Trigger burst mode randomly
|
| 371 |
+
if (!inBurstMode && Math.random() < CONFIG.burstTypingRate) {
|
| 372 |
+
inBurstMode = true;
|
| 373 |
+
burstCharsRemaining = CONFIG.burstLength;
|
| 374 |
+
}
|
| 375 |
+
|
| 376 |
+
// Skip letter imperfection (handled by typing next char instead, creating error)
|
| 377 |
+
if (/[a-zA-Z]/.test(char) && Math.random() < CONFIG.skipLetterRate && nextChar) {
|
| 378 |
+
// Skip this char - type next char instead (creates transposition-like error)
|
| 379 |
+
typeChar(nextChar);
|
| 380 |
+
await sleep(getKeystrokeDelay() * 2.5);
|
| 381 |
+
typeBackspace();
|
| 382 |
+
await sleep(getKeystrokeDelay() * 1.3);
|
| 383 |
+
recentMistake = true;
|
| 384 |
+
// Now type correct char
|
| 385 |
+
typeChar(char);
|
| 386 |
+
await sleep(delay);
|
| 387 |
+
continue;
|
| 388 |
+
}
|
| 389 |
+
|
| 390 |
+
// Transpose letters
|
| 391 |
+
if (/[a-zA-Z]/.test(char) && nextChar && /[a-zA-Z]/.test(nextChar) && Math.random() < CONFIG.transposeRate) {
|
| 392 |
+
await simulateTranspose(char, nextChar);
|
| 393 |
+
// Type both chars correctly now
|
| 394 |
+
typeChar(char);
|
| 395 |
+
await sleep(getKeystrokeDelay());
|
| 396 |
+
typeChar(nextChar);
|
| 397 |
+
await sleep(delay);
|
| 398 |
+
// Skip the next character in main loop since we already typed it
|
| 399 |
+
skipNext = true;
|
| 400 |
+
continue;
|
| 401 |
+
}
|
| 402 |
+
|
| 403 |
+
// Triple letter (rarer)
|
| 404 |
+
if (/[a-zA-Z]/.test(char) && Math.random() < CONFIG.tripleLetterRate) {
|
| 405 |
+
typeChar(char); // Type the correct one first
|
| 406 |
+
await simulateDoubleLetter(char, 3);
|
| 407 |
+
await sleep(delay);
|
| 408 |
+
continue;
|
| 409 |
+
}
|
| 410 |
+
|
| 411 |
+
// Double letter
|
| 412 |
+
if (/[a-zA-Z]/.test(char) && Math.random() < CONFIG.doubleLetterRate) {
|
| 413 |
+
typeChar(char); // Type the correct one first
|
| 414 |
+
await simulateDoubleLetter(char, 2);
|
| 415 |
+
await sleep(delay);
|
| 416 |
+
continue;
|
| 417 |
+
}
|
| 418 |
+
|
| 419 |
+
// Adjacent key typo
|
| 420 |
+
if (/[a-zA-Z]/.test(char) && Math.random() < CONFIG.adjacentKeyRate) {
|
| 421 |
+
await simulateAdjacentKeyTypo(char);
|
| 422 |
+
}
|
| 423 |
+
|
| 424 |
+
// Wrong character
|
| 425 |
+
if (/[a-zA-Z]/.test(char) && Math.random() < CONFIG.wrongCharRate) {
|
| 426 |
+
await simulateWrongChar(char);
|
| 427 |
+
}
|
| 428 |
+
|
| 429 |
+
// Type the correct character
|
| 430 |
+
typeChar(char);
|
| 431 |
+
await sleep(delay);
|
| 432 |
+
}
|
| 433 |
+
}
|
| 434 |
+
|
| 435 |
+
const triggerHandler = (e) => {
|
| 436 |
+
if (!isArmed) return;
|
| 437 |
+
|
| 438 |
+
if (e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey) {
|
| 439 |
+
const activeWord = document.querySelector('#words .word.active');
|
| 440 |
+
if (!activeWord) return;
|
| 441 |
+
|
| 442 |
+
const firstLetterElement = activeWord.querySelector('letter');
|
| 443 |
+
const firstLetter = firstLetterElement ? firstLetterElement.textContent : null;
|
| 444 |
+
|
| 445 |
+
if (firstLetter && e.key === firstLetter) {
|
| 446 |
+
isArmed = false;
|
| 447 |
+
window.removeEventListener('keydown', triggerHandler);
|
| 448 |
+
|
| 449 |
+
console.log("Trigger detected. Starting Human-Like Command Typer...");
|
| 450 |
+
console.log("Config:", CONFIG);
|
| 451 |
+
setTimeout(() => {
|
| 452 |
+
autoTypeLoop();
|
| 453 |
+
}, CONFIG.startDelay);
|
| 454 |
+
}
|
| 455 |
+
}
|
| 456 |
+
};
|
| 457 |
+
|
| 458 |
+
window.addEventListener('keydown', triggerHandler);
|
| 459 |
+
console.log("READY! Type the first letter to activate Human-Like Mode.");
|
| 460 |
+
console.log("Imperfections enabled: wrong char, adjacent key typo, double/triple letter, skip, transpose, Ctrl+Backspace, hesitation, burst typing, fatigue, word-start slowdown");
|
| 461 |
+
})();
|
mnk_lightning_v3.js
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// MnkLightning v3 - Browser-Based Human Typer
|
| 2 |
+
// Merges logic from Python script and JS injector into a single userscript/console script.
|
| 3 |
+
|
| 4 |
+
(function () {
|
| 5 |
+
console.log("%c MnkLightning v3 Active ", "background: #222; color: #00ff00; font-size: 16px");
|
| 6 |
+
|
| 7 |
+
// === CONFIGURATION ===
|
| 8 |
+
const CONFIG = {
|
| 9 |
+
min_wpm: 100,
|
| 10 |
+
max_wpm: 140,
|
| 11 |
+
// Key Hold Time (Seconds)
|
| 12 |
+
min_key_hold: 0.01,
|
| 13 |
+
max_key_hold: 0.04,
|
| 14 |
+
|
| 15 |
+
// Imperfection Rates (0.0 to 1.0)
|
| 16 |
+
wrong_char_rate: 0.005,
|
| 17 |
+
adjacent_key_rate: 0.005,
|
| 18 |
+
double_letter_rate: 0.001,
|
| 19 |
+
skip_letter_rate: 0.001,
|
| 20 |
+
|
| 21 |
+
hesitation_rate: 0.02,
|
| 22 |
+
burst_rate: 0.08,
|
| 23 |
+
insane_burst_rate: 0.001,
|
| 24 |
+
|
| 25 |
+
// Timing Multipliers
|
| 26 |
+
hesitation_multiplier: 2.5,
|
| 27 |
+
burst_speed_multiplier: 0.6,
|
| 28 |
+
post_mistake_pause: 0.4,
|
| 29 |
+
word_start_slowdown: 1.2,
|
| 30 |
+
};
|
| 31 |
+
|
| 32 |
+
// QWERTY Adjacency Map
|
| 33 |
+
const ADJACENT_KEYS = {
|
| 34 |
+
'a': 'qwsz', 'b': 'vghn', 'c': 'xdfv', 'd': 'serfcx', 'e': 'wsdr',
|
| 35 |
+
'f': 'drtgvc', 'g': 'ftyhbv', 'h': 'gyujnb', 'i': 'ujko', 'j': 'huikmn',
|
| 36 |
+
'k': 'jiolm', 'l': 'kop', 'm': 'njk', 'n': 'bhjm', 'o': 'iklp',
|
| 37 |
+
'p': 'ol', 'q': 'wa', 'r': 'edft', 's': 'awedxz', 't': 'rfgy',
|
| 38 |
+
'u': 'yhji', 'v': 'cfgb', 'w': 'qase', 'x': 'zsdc', 'y': 'tghu',
|
| 39 |
+
'z': 'asx'
|
| 40 |
+
};
|
| 41 |
+
|
| 42 |
+
// Global State
|
| 43 |
+
let isTyping = false;
|
| 44 |
+
let abortTyping = false;
|
| 45 |
+
|
| 46 |
+
// === HELPERS ===
|
| 47 |
+
|
| 48 |
+
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
| 49 |
+
const randomUniform = (min, max) => Math.random() * (max - min) + min;
|
| 50 |
+
const randomInt = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
|
| 51 |
+
const randomChoice = (arr) => arr[Math.floor(Math.random() * arr.length)];
|
| 52 |
+
const randomChar = () => "abcdefghijklmnopqrstuvwxyz"[Math.floor(Math.random() * 26)];
|
| 53 |
+
|
| 54 |
+
function getKeystrokeDelay(wpm, inBurst = false) {
|
| 55 |
+
const cpm = wpm * 5;
|
| 56 |
+
let baseDelay = 60 / cpm;
|
| 57 |
+
|
| 58 |
+
if (inBurst) {
|
| 59 |
+
baseDelay *= CONFIG.burst_speed_multiplier;
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
const variance = baseDelay * 0.20;
|
| 63 |
+
const noise = randomUniform(-variance, variance);
|
| 64 |
+
return Math.max(0.005, baseDelay + noise) * 1000;
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
function getAdjacentKey(char) {
|
| 68 |
+
const charLower = char.toLowerCase();
|
| 69 |
+
if (ADJACENT_KEYS[charLower]) {
|
| 70 |
+
const adj = randomChoice(ADJACENT_KEYS[charLower]);
|
| 71 |
+
return char === char.toUpperCase() ? adj.toUpperCase() : adj;
|
| 72 |
+
}
|
| 73 |
+
return char;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
// === INPUT SIMULATION ===
|
| 77 |
+
|
| 78 |
+
const CODE_MAP = {
|
| 79 |
+
' ': 'Space',
|
| 80 |
+
'Enter': 'Enter',
|
| 81 |
+
'Backspace': 'Backspace',
|
| 82 |
+
'Escape': 'Escape',
|
| 83 |
+
',': 'Comma',
|
| 84 |
+
'.': 'Period',
|
| 85 |
+
'/': 'Slash',
|
| 86 |
+
';': 'Semicolon',
|
| 87 |
+
"'": 'Quote',
|
| 88 |
+
'[': 'BracketLeft',
|
| 89 |
+
']': 'BracketRight',
|
| 90 |
+
'\\': 'Backslash',
|
| 91 |
+
'-': 'Minus',
|
| 92 |
+
'=': 'Equal',
|
| 93 |
+
'`': 'Backquote',
|
| 94 |
+
'1': 'Digit1', '2': 'Digit2', '3': 'Digit3', '4': 'Digit4', '5': 'Digit5',
|
| 95 |
+
'6': 'Digit6', '7': 'Digit7', '8': 'Digit8', '9': 'Digit9', '0': 'Digit0'
|
| 96 |
+
};
|
| 97 |
+
|
| 98 |
+
function dispatchKey(key, type) {
|
| 99 |
+
let code;
|
| 100 |
+
|
| 101 |
+
// 1. Check strict map
|
| 102 |
+
if (CODE_MAP[key]) {
|
| 103 |
+
code = CODE_MAP[key];
|
| 104 |
+
}
|
| 105 |
+
// 2. Letters
|
| 106 |
+
else if (key.length === 1 && /[a-zA-Z]/.test(key)) {
|
| 107 |
+
code = `Key${key.toUpperCase()}`;
|
| 108 |
+
}
|
| 109 |
+
// 3. Fallback for shifted punctuation
|
| 110 |
+
else if (key === '!') code = 'Digit1';
|
| 111 |
+
else if (key === '@') code = 'Digit2';
|
| 112 |
+
else if (key === '#') code = 'Digit3';
|
| 113 |
+
else if (key === '$') code = 'Digit4';
|
| 114 |
+
else if (key === '%') code = 'Digit5';
|
| 115 |
+
else if (key === '^') code = 'Digit6';
|
| 116 |
+
else if (key === '&') code = 'Digit7';
|
| 117 |
+
else if (key === '*') code = 'Digit8';
|
| 118 |
+
else if (key === '(') code = 'Digit9';
|
| 119 |
+
else if (key === ')') code = 'Digit0';
|
| 120 |
+
else if (key === '_') code = 'Minus';
|
| 121 |
+
else if (key === '+') code = 'Equal';
|
| 122 |
+
else if (key === '{') code = 'BracketLeft';
|
| 123 |
+
else if (key === '}') code = 'BracketRight';
|
| 124 |
+
else if (key === '|') code = 'Backslash';
|
| 125 |
+
else if (key === ':') code = 'Semicolon';
|
| 126 |
+
else if (key === '"') code = 'Quote';
|
| 127 |
+
else if (key === '<') code = 'Comma';
|
| 128 |
+
else if (key === '>') code = 'Period';
|
| 129 |
+
else if (key === '?') code = 'Slash';
|
| 130 |
+
else if (key === '~') code = 'Backquote';
|
| 131 |
+
else {
|
| 132 |
+
code = key;
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
const event = new KeyboardEvent(type, {
|
| 136 |
+
key: key,
|
| 137 |
+
code: code,
|
| 138 |
+
bubbles: true,
|
| 139 |
+
cancelable: true,
|
| 140 |
+
view: window,
|
| 141 |
+
which: key.charCodeAt(0),
|
| 142 |
+
keyCode: key.charCodeAt(0)
|
| 143 |
+
});
|
| 144 |
+
|
| 145 |
+
const target = document.activeElement || document.body;
|
| 146 |
+
target.dispatchEvent(event);
|
| 147 |
+
}
|
| 148 |
+
|
| 149 |
+
async function typeChar(char) {
|
| 150 |
+
dispatchKey(char, 'keydown');
|
| 151 |
+
dispatchKey(char, 'keypress');
|
| 152 |
+
|
| 153 |
+
const holdTime = randomUniform(CONFIG.min_key_hold, CONFIG.max_key_hold) * 1000;
|
| 154 |
+
await sleep(holdTime);
|
| 155 |
+
dispatchKey(char, 'keyup');
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
async function simulateBackspace(count = 1) {
|
| 159 |
+
for (let i = 0; i < count; i++) {
|
| 160 |
+
dispatchKey('Backspace', 'keydown');
|
| 161 |
+
await sleep(randomUniform(CONFIG.min_key_hold, CONFIG.max_key_hold) * 1000);
|
| 162 |
+
dispatchKey('Backspace', 'keyup');
|
| 163 |
+
await sleep(randomUniform(50, 100));
|
| 164 |
+
}
|
| 165 |
+
}
|
| 166 |
+
|
| 167 |
+
// === CORE LOGIC ===
|
| 168 |
+
|
| 169 |
+
function getVisibleText() {
|
| 170 |
+
const words = document.querySelectorAll('.word');
|
| 171 |
+
if (words.length === 0) return null;
|
| 172 |
+
|
| 173 |
+
let text = "";
|
| 174 |
+
words.forEach((word) => {
|
| 175 |
+
word.querySelectorAll('letter').forEach(letter => {
|
| 176 |
+
text += letter.textContent;
|
| 177 |
+
});
|
| 178 |
+
text += " ";
|
| 179 |
+
});
|
| 180 |
+
return text.trim();
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
+
async function startTyping() {
|
| 184 |
+
if (isTyping) return;
|
| 185 |
+
|
| 186 |
+
const text = getVisibleText();
|
| 187 |
+
if (!text) {
|
| 188 |
+
console.error("MnkLightning: No text found! Are you in a test?");
|
| 189 |
+
return;
|
| 190 |
+
}
|
| 191 |
+
|
| 192 |
+
// Try to focus the game area if possible
|
| 193 |
+
const gameWords = document.getElementById('words');
|
| 194 |
+
if (gameWords) {
|
| 195 |
+
gameWords.click(); // Hack to ensure focus
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
isTyping = true;
|
| 199 |
+
abortTyping = false;
|
| 200 |
+
|
| 201 |
+
const wpm = randomInt(CONFIG.min_wpm, CONFIG.max_wpm);
|
| 202 |
+
console.log(`MnkLightning: Starting... Target WPM: ${wpm}, Length: ${text.length}`);
|
| 203 |
+
|
| 204 |
+
let idx = 0;
|
| 205 |
+
let burstRemaining = 0;
|
| 206 |
+
|
| 207 |
+
try {
|
| 208 |
+
while (idx < text.length) {
|
| 209 |
+
if (abortTyping) break;
|
| 210 |
+
|
| 211 |
+
const char = text[idx];
|
| 212 |
+
let delay = getKeystrokeDelay(wpm, burstRemaining > 0);
|
| 213 |
+
|
| 214 |
+
if (burstRemaining > 0) burstRemaining--;
|
| 215 |
+
|
| 216 |
+
// === IMPERFECTIONS ===
|
| 217 |
+
|
| 218 |
+
if (Math.random() < CONFIG.hesitation_rate) {
|
| 219 |
+
delay *= CONFIG.hesitation_multiplier;
|
| 220 |
+
}
|
| 221 |
+
|
| 222 |
+
if (burstRemaining === 0 && Math.random() < CONFIG.burst_rate) {
|
| 223 |
+
burstRemaining = 5;
|
| 224 |
+
}
|
| 225 |
+
|
| 226 |
+
// Insane Burst
|
| 227 |
+
if (Math.random() < CONFIG.insane_burst_rate) {
|
| 228 |
+
const burstLen = randomInt(4, 5);
|
| 229 |
+
for (let i = 0; i < burstLen; i++) {
|
| 230 |
+
if (idx >= text.length || abortTyping) break;
|
| 231 |
+
dispatchKey(text[idx], 'keydown');
|
| 232 |
+
dispatchKey(text[idx], 'keyup');
|
| 233 |
+
idx++;
|
| 234 |
+
await sleep(2);
|
| 235 |
+
}
|
| 236 |
+
continue;
|
| 237 |
+
}
|
| 238 |
+
|
| 239 |
+
// Mistakes
|
| 240 |
+
if (Math.random() < CONFIG.wrong_char_rate && /[a-zA-Z0-9]/.test(char)) {
|
| 241 |
+
const wrong = randomChar();
|
| 242 |
+
await typeChar(wrong);
|
| 243 |
+
await sleep(delay * 2);
|
| 244 |
+
await simulateBackspace(1);
|
| 245 |
+
await sleep(delay);
|
| 246 |
+
}
|
| 247 |
+
|
| 248 |
+
await typeChar(char);
|
| 249 |
+
idx++;
|
| 250 |
+
|
| 251 |
+
if (char === ' ') {
|
| 252 |
+
delay *= CONFIG.word_start_slowdown;
|
| 253 |
+
}
|
| 254 |
+
|
| 255 |
+
await sleep(delay);
|
| 256 |
+
}
|
| 257 |
+
} catch (e) {
|
| 258 |
+
console.error(e);
|
| 259 |
+
}
|
| 260 |
+
|
| 261 |
+
console.log("MnkLightning: Finished.");
|
| 262 |
+
isTyping = false;
|
| 263 |
+
}
|
| 264 |
+
|
| 265 |
+
// === LISTENERS ===
|
| 266 |
+
|
| 267 |
+
window.addEventListener('keydown', (e) => {
|
| 268 |
+
if (e.key === 'Insert') {
|
| 269 |
+
e.preventDefault();
|
| 270 |
+
if (isTyping) {
|
| 271 |
+
console.log("MnkLightning: Already running!");
|
| 272 |
+
return;
|
| 273 |
+
}
|
| 274 |
+
startTyping();
|
| 275 |
+
}
|
| 276 |
+
if (e.key === 'Escape') {
|
| 277 |
+
abortTyping = true;
|
| 278 |
+
if (isTyping) {
|
| 279 |
+
console.log("MnkLightning: Aborting...");
|
| 280 |
+
isTyping = false;
|
| 281 |
+
}
|
| 282 |
+
}
|
| 283 |
+
});
|
| 284 |
+
|
| 285 |
+
})();
|
mnk_typer.py
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pyautogui
|
| 2 |
+
import keyboard
|
| 3 |
+
import time
|
| 4 |
+
import random
|
| 5 |
+
import pyperclip
|
| 6 |
+
import sys
|
| 7 |
+
|
| 8 |
+
# Remove default 0.1s pause after every PyAutoGUI call
|
| 9 |
+
pyautogui.PAUSE = 0
|
| 10 |
+
|
| 11 |
+
# === CONFIGURATION ===
|
| 12 |
+
CONFIG = {
|
| 13 |
+
"min_wpm": 390,
|
| 14 |
+
"max_wpm": 450,
|
| 15 |
+
# Key Hold Time (Seconds)
|
| 16 |
+
"min_key_hold": 0.01,
|
| 17 |
+
"max_key_hold": 0.03,
|
| 18 |
+
|
| 19 |
+
# Imperfection Rates (0.0 to 1.0)
|
| 20 |
+
"wrong_char_rate": 0.0025,
|
| 21 |
+
"adjacent_key_rate": 0.002,
|
| 22 |
+
"double_letter_rate": 0.0015,
|
| 23 |
+
"skip_letter_rate": 0.01,
|
| 24 |
+
"transpose_rate": 0.0012,
|
| 25 |
+
"hesitation_rate": 0.04,
|
| 26 |
+
"burst_rate": 0.08,
|
| 27 |
+
|
| 28 |
+
# Timing Multipliers
|
| 29 |
+
"hesitation_multiplier": 3.5,
|
| 30 |
+
"burst_speed_multiplier": 0.5,
|
| 31 |
+
"post_mistake_pause": 2.0,
|
| 32 |
+
"word_start_slowdown": 1.5,
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
# QWERTY Adjacency Map
|
| 36 |
+
ADJACENT_KEYS = {
|
| 37 |
+
'a': 'qwsz', 'b': 'vghn', 'c': 'xdfv', 'd': 'serfcx', 'e': 'wsdr',
|
| 38 |
+
'f': 'drtgvc', 'g': 'ftyhbv', 'h': 'gyujnb', 'i': 'ujko', 'j': 'huikmn',
|
| 39 |
+
'k': 'jiolm', 'l': 'kop', 'm': 'njk', 'n': 'bhjm', 'o': 'iklp',
|
| 40 |
+
'p': 'ol', 'q': 'wa', 'r': 'edft', 's': 'awedxz', 't': 'rfgy',
|
| 41 |
+
'u': 'yhji', 'v': 'cfgb', 'w': 'qase', 'x': 'zsdc', 'y': 'tghu',
|
| 42 |
+
'z': 'asx'
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
def get_keystroke_delay(wpm, in_burst=False):
|
| 46 |
+
"""Calculates delay between keystrokes based on WPM."""
|
| 47 |
+
cpm = wpm * 5
|
| 48 |
+
base_delay = 10 / cpm
|
| 49 |
+
|
| 50 |
+
if in_burst:
|
| 51 |
+
base_delay *= CONFIG["burst_speed_multiplier"]
|
| 52 |
+
|
| 53 |
+
# Add noise (+/- 25%)
|
| 54 |
+
variance = base_delay * 0.25
|
| 55 |
+
noise = random.uniform(-variance, variance)
|
| 56 |
+
return max(0.008, base_delay + noise)
|
| 57 |
+
|
| 58 |
+
def get_adjacent_key(char):
|
| 59 |
+
"""Returns a key adjacent to the given char on QWERTY layout."""
|
| 60 |
+
char_lower = char.lower()
|
| 61 |
+
if char_lower in ADJACENT_KEYS:
|
| 62 |
+
adj = random.choice(ADJACENT_KEYS[char_lower])
|
| 63 |
+
return adj.upper() if char.isupper() else adj
|
| 64 |
+
return char
|
| 65 |
+
|
| 66 |
+
def type_char(char):
|
| 67 |
+
"""Types a single character with human-like key hold duration."""
|
| 68 |
+
# Handle special characters or shift needs
|
| 69 |
+
try:
|
| 70 |
+
pyautogui.keyDown(char)
|
| 71 |
+
time.sleep(random.uniform(CONFIG["min_key_hold"], CONFIG["max_key_hold"]))
|
| 72 |
+
pyautogui.keyUp(char)
|
| 73 |
+
except:
|
| 74 |
+
# Fallback for complex chars
|
| 75 |
+
pyautogui.write(char)
|
| 76 |
+
|
| 77 |
+
def simulate_backspace(count=1):
|
| 78 |
+
"""Simulates pressing backspace with hold time."""
|
| 79 |
+
for _ in range(count):
|
| 80 |
+
pyautogui.keyDown('backspace')
|
| 81 |
+
time.sleep(random.uniform(CONFIG["min_key_hold"], CONFIG["max_key_hold"]))
|
| 82 |
+
pyautogui.keyUp('backspace')
|
| 83 |
+
time.sleep(random.uniform(0.05, 0.1))
|
| 84 |
+
|
| 85 |
+
def mnk_typer():
|
| 86 |
+
print("=== MnkLightning Python Automation ===")
|
| 87 |
+
print("1. Copy text from Monkeytype using injector.js (Press Insert in browser)")
|
| 88 |
+
print("2. Focus the browser window")
|
| 89 |
+
print("3. Press 'Insert' to START typing")
|
| 90 |
+
print("4. Press 'Esc' to STOP")
|
| 91 |
+
print("Waiting for trigger...")
|
| 92 |
+
|
| 93 |
+
while True:
|
| 94 |
+
if keyboard.is_pressed('esc'):
|
| 95 |
+
print("\nExiting...")
|
| 96 |
+
sys.exit()
|
| 97 |
+
|
| 98 |
+
if keyboard.is_pressed('insert'):
|
| 99 |
+
# Debounce
|
| 100 |
+
time.sleep(0.5)
|
| 101 |
+
|
| 102 |
+
# Get text from clipboard
|
| 103 |
+
text = pyperclip.paste()
|
| 104 |
+
if not text:
|
| 105 |
+
print("Clipboard empty! extraction failed?")
|
| 106 |
+
continue
|
| 107 |
+
|
| 108 |
+
print(f"Typing {len(text)} characters...")
|
| 109 |
+
|
| 110 |
+
wpm = random.randint(CONFIG["min_wpm"], CONFIG["max_wpm"])
|
| 111 |
+
print(f"Target WPM: {wpm}")
|
| 112 |
+
|
| 113 |
+
# State
|
| 114 |
+
idx = 0
|
| 115 |
+
burst_remaining = 0
|
| 116 |
+
|
| 117 |
+
try:
|
| 118 |
+
while idx < len(text):
|
| 119 |
+
if keyboard.is_pressed('esc'):
|
| 120 |
+
return
|
| 121 |
+
|
| 122 |
+
char = text[idx]
|
| 123 |
+
delay = get_keystroke_delay(wpm, burst_remaining > 0)
|
| 124 |
+
|
| 125 |
+
if burst_remaining > 0:
|
| 126 |
+
burst_remaining -= 1
|
| 127 |
+
|
| 128 |
+
# === IMPERFECTIONS ===
|
| 129 |
+
|
| 130 |
+
# 1. Hesitation
|
| 131 |
+
if random.random() < CONFIG["hesitation_rate"]:
|
| 132 |
+
delay *= CONFIG["hesitation_multiplier"]
|
| 133 |
+
|
| 134 |
+
# 2. Burst Mode
|
| 135 |
+
if burst_remaining == 0 and random.random() < CONFIG["burst_rate"]:
|
| 136 |
+
burst_remaining = 5
|
| 137 |
+
|
| 138 |
+
# 3. Wrong Character (Type random, then fix)
|
| 139 |
+
if random.random() < CONFIG["wrong_char_rate"] and char.isalnum():
|
| 140 |
+
wrong = random.choice("abcdefghijklmnopqrstuvwxyz")
|
| 141 |
+
type_char(wrong)
|
| 142 |
+
time.sleep(delay * 2)
|
| 143 |
+
simulate_backspace(1)
|
| 144 |
+
time.sleep(delay)
|
| 145 |
+
# Don't increment idx, we need to type correct char
|
| 146 |
+
|
| 147 |
+
# 4. Adjacent Key (Type neighbor, then fix)
|
| 148 |
+
elif random.random() < CONFIG["adjacent_key_rate"] and char.isalpha():
|
| 149 |
+
adj = get_adjacent_key(char)
|
| 150 |
+
type_char(adj)
|
| 151 |
+
time.sleep(delay * 1.5)
|
| 152 |
+
simulate_backspace(1)
|
| 153 |
+
time.sleep(delay)
|
| 154 |
+
|
| 155 |
+
# 5. Skip Letter (Type next char, realize, backspace 2, type current)
|
| 156 |
+
elif random.random() < CONFIG["skip_letter_rate"] and idx + 1 < len(text):
|
| 157 |
+
next_char = text[idx+1]
|
| 158 |
+
type_char(next_char)
|
| 159 |
+
time.sleep(delay * 2.5)
|
| 160 |
+
simulate_backspace(1)
|
| 161 |
+
time.sleep(delay)
|
| 162 |
+
# Now continue loop to type 'char'
|
| 163 |
+
|
| 164 |
+
# 6. Double Letter (Type char twice, delete one)
|
| 165 |
+
elif random.random() < CONFIG["double_letter_rate"] and char.isalpha():
|
| 166 |
+
type_char(char)
|
| 167 |
+
time.sleep(0.05)
|
| 168 |
+
type_char(char) # Double
|
| 169 |
+
time.sleep(delay * 2)
|
| 170 |
+
simulate_backspace(1)
|
| 171 |
+
idx += 1 # We kept one valid char
|
| 172 |
+
time.sleep(delay)
|
| 173 |
+
continue
|
| 174 |
+
|
| 175 |
+
# === TYPING ===
|
| 176 |
+
type_char(char)
|
| 177 |
+
idx += 1
|
| 178 |
+
|
| 179 |
+
# Word boundary pause
|
| 180 |
+
if char == ' ':
|
| 181 |
+
delay *= CONFIG["word_start_slowdown"]
|
| 182 |
+
|
| 183 |
+
time.sleep(delay)
|
| 184 |
+
|
| 185 |
+
except KeyboardInterrupt:
|
| 186 |
+
pass
|
| 187 |
+
|
| 188 |
+
print("\nTyping complete.")
|
| 189 |
+
time.sleep(1) # Prevent double trigger
|
| 190 |
+
|
| 191 |
+
if __name__ == "__main__":
|
| 192 |
+
try:
|
| 193 |
+
mnk_typer()
|
| 194 |
+
except KeyboardInterrupt:
|
| 195 |
+
sys.exit()
|
requirements.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
pyautogui==0.9.54
|
| 2 |
+
keyboard==0.13.5
|
| 3 |
+
pyperclip==1.8.2
|