您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Works anywhere! Type like a pro with "start-now" trigger, stylish UI, manual controls & Shift x3 to stop. Try it!
// ==UserScript== // @name Human Auto Typer // @namespace http://tampermonkey.net/ // @version 4.5 // @description Works anywhere! Type like a pro with "start-now" trigger, stylish UI, manual controls & Shift x3 to stop. Try it! // @author Koolkars (Felix) // @match *://*/* // @grant none // @icon https://static.vecteezy.com/system/resources/previews/010/750/505/original/typing-icon-design-free-vector.jpg // @license MIT // ==/UserScript== (function () { 'use strict'; let typingInterval = 300; let typingText = ''; let typingTarget = null; let typingInProgress = false; let typingTimeoutId = null; let shiftPressTimes = []; // Create toggle icon const toggleIcon = document.createElement('div'); toggleIcon.id = 'typingToggleIcon'; toggleIcon.title = 'Simulated Typing Panel'; toggleIcon.style.position = 'fixed'; toggleIcon.style.top = '50%'; toggleIcon.style.right = '0'; toggleIcon.style.transform = 'translateY(-50%)'; toggleIcon.style.width = '40px'; toggleIcon.style.height = '40px'; toggleIcon.style.background = 'linear-gradient(135deg, #6ab7ff, #4285f4)'; toggleIcon.style.borderTopLeftRadius = '20px'; toggleIcon.style.borderBottomLeftRadius = '20px'; toggleIcon.style.cursor = 'pointer'; toggleIcon.style.boxShadow = '0 2px 8px rgba(0,0,0,0.15)'; toggleIcon.style.display = 'flex'; toggleIcon.style.alignItems = 'center'; toggleIcon.style.justifyContent = 'center'; toggleIcon.style.zIndex = '999999'; toggleIcon.style.userSelect = 'none'; toggleIcon.innerHTML = ` <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="white" viewBox="0 0 24 24"> <path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04a1.003 1.003 0 0 0 0-1.42l-2.34-2.34a1.003 1.003 0 0 0-1.42 0L14.13 4.94l3.75 3.75 2.83-2.83z"/> </svg>`; document.body.appendChild(toggleIcon); const ui = document.createElement('div'); ui.id = 'typingUI'; ui.style.position = 'fixed'; ui.style.top = '50%'; ui.style.right = '-360px'; ui.style.transform = 'translateY(-50%)'; ui.style.width = '350px'; ui.style.background = 'white'; ui.style.borderRadius = '20px 0 0 20px'; ui.style.boxShadow = '0 8px 24px rgba(66, 133, 244, 0.3)'; ui.style.padding = '20px 25px 25px 25px'; ui.style.fontFamily = "'Segoe UI', Tahoma, Geneva, Verdana, sans-serif"; ui.style.color = '#1a1a1a'; ui.style.zIndex = '999998'; ui.style.transition = 'right 0.3s cubic-bezier(0.4, 0, 0.2, 1)'; ui.style.userSelect = 'none'; ui.style.display = 'flex'; ui.style.flexDirection = 'column'; ui.style.gap = '15px'; ui.innerHTML = ` <h2 style="margin:0; font-weight: 600; color: #4285f4;">Human Auto Typer</h2> <label for="pasteArea" style="font-weight: 500;">Paste Text:</label> <textarea id="pasteArea" rows="6" placeholder="Paste text here..." style="width: 100%; font-size: 14px; padding: 10px; border: 1.8px solid #ddd; border-radius: 10px; resize: vertical; outline-offset: 2px; outline-color: #4285f4;"></textarea> <label for="wpmInput" style="font-weight: 500;">Words Per Minute (WPM):</label> <input id="wpmInput" type="number" min="1" value="40" style="width: 70px; padding: 6px 8px; font-size: 14px; border-radius: 8px; border: 1.5px solid #ddd; outline-offset: 2px; outline-color: #4285f4;"> <div style="display: flex; justify-content: flex-start; gap: 12px; margin-top: 10px;"> <button id="startTypingBtn" style="background: #4285f4; border: none; color: white; padding: 10px 18px; border-radius: 12px; font-weight: 600; cursor: pointer; box-shadow: 0 2px 8px rgba(66, 133, 244, 0.5); transition: background 0.3s ease;"> Start </button> <button id="stopTypingBtn" style="background: #f44336; border: none; color: white; padding: 10px 18px; border-radius: 12px; font-weight: 600; cursor: pointer; box-shadow: 0 2px 8px rgba(244, 67, 54, 0.5); transition: background 0.3s ease;"> Stop </button> </div> <small style="color: #666;">Type <code>start-now</code> in an input or editable field to trigger typing.<br>Press <b>Shift</b> 3 times quickly to stop typing.</small> <div style="font-size: 10px; color: #999; text-align: right; margin-top: 10px;">made by koolkars</div> `; document.body.appendChild(ui); let panelOpen = false; toggleIcon.addEventListener('click', () => { panelOpen = !panelOpen; ui.style.right = panelOpen ? '0' : '-360px'; toggleIcon.style.background = panelOpen ? 'linear-gradient(135deg, #2a6dfd, #1a4ed8)' : 'linear-gradient(135deg, #6ab7ff, #4285f4)'; }); function getIntervalFromWPM(wpm) { const charsPerMinute = wpm * 5; return 60000 / charsPerMinute; } function simulateTyping(text, element, interval) { let i = 0; typingInProgress = true; function typeNextChar() { if (!typingInProgress) return; if (i >= text.length) { typingInProgress = false; typingTimeoutId = null; return; } const char = text[i++]; if (element.isContentEditable) { const sel = window.getSelection(); if (!sel.rangeCount) { typingInProgress = false; typingTimeoutId = null; return; } const range = sel.getRangeAt(0); range.deleteContents(); range.insertNode(document.createTextNode(char)); range.collapse(false); sel.removeAllRanges(); sel.addRange(range); } else { const start = element.selectionStart; const end = element.selectionEnd; const before = element.value.slice(0, start); const after = element.value.slice(end); element.value = before + char + after; element.selectionStart = element.selectionEnd = start + 1; } typingTimeoutId = setTimeout(typeNextChar, interval); } typeNextChar(); } function stopTyping() { if (typingInProgress) { typingInProgress = false; if (typingTimeoutId) { clearTimeout(typingTimeoutId); typingTimeoutId = null; } console.log('Typing stopped.'); } } document.getElementById('startTypingBtn').addEventListener('click', () => { if (typingInProgress) { alert('Typing already in progress!'); return; } const text = document.getElementById('pasteArea').value.trim(); if (!text) { alert('Please paste some text first!'); return; } const wpm = parseInt(document.getElementById('wpmInput').value); if (isNaN(wpm) || wpm < 1) { alert('Please enter a valid WPM (1 or more).'); return; } const interval = getIntervalFromWPM(wpm); const activeEl = document.activeElement; if (!activeEl || (!activeEl.isContentEditable && activeEl.tagName !== 'TEXTAREA' && !(activeEl.tagName === 'INPUT' && ['text', 'search', 'email', 'url', 'tel', 'password'].includes(activeEl.type)))) { alert('Please focus a text input, textarea, or editable element to start typing.'); return; } typingText = text; typingInterval = interval; typingTarget = activeEl; simulateTyping(typingText, typingTarget, typingInterval); }); document.getElementById('stopTypingBtn').addEventListener('click', () => { stopTyping(); }); const triggerPhrase = 'start-now'; const triggerLength = triggerPhrase.length; function attachInputListener(el) { if (!el || el._hasTypingListener) return; el._hasTypingListener = true; el.addEventListener('input', () => { if (typingInProgress) return; let content = el.isContentEditable ? el.textContent || '' : el.value || ''; if (content.length < triggerLength) return; if (content.slice(-triggerLength) === triggerPhrase) { if (el.isContentEditable) { el.textContent = content.slice(0, -triggerLength); const sel = window.getSelection(); const range = document.createRange(); range.selectNodeContents(el); range.collapse(false); sel.removeAllRanges(); sel.addRange(range); } else { el.value = content.slice(0, -triggerLength); el.selectionStart = el.selectionEnd = el.value.length; } const text = document.getElementById('pasteArea').value.trim(); if (!text) return alert('Please paste some text in the panel first!'); const wpm = parseInt(document.getElementById('wpmInput').value); if (isNaN(wpm) || wpm < 1) return alert('Please enter a valid WPM (1 or more) in the panel.'); typingText = text; typingInterval = getIntervalFromWPM(wpm); typingTarget = el; simulateTyping(typingText, typingTarget, typingInterval); } }); } function attachListenersToAllInputs() { const inputs = [...document.querySelectorAll('input[type=text], input[type=search], input[type=email], input[type=url], input[type=tel], input[type=password], textarea')]; inputs.forEach(attachInputListener); const editables = [...document.querySelectorAll('[contenteditable="true"], [contenteditable=""]')]; editables.forEach(attachInputListener); } attachListenersToAllInputs(); const observer = new MutationObserver((mutations) => { for (const mutation of mutations) { if (mutation.type === 'childList') { mutation.addedNodes.forEach((node) => { if (!(node instanceof HTMLElement)) return; if (node.matches('input[type=text], input[type=search], input[type=email], input[type=url], input[type=tel], input[type=password], textarea')) { attachInputListener(node); } if (node.isContentEditable) attachInputListener(node); node.querySelectorAll('input[type=text], input[type=search], input[type=email], input[type=url], input[type=tel], input[type=password], textarea').forEach(attachInputListener); node.querySelectorAll('[contenteditable="true"], [contenteditable=""]').forEach(attachInputListener); }); } } }); observer.observe(document.body, { childList: true, subtree: true }); window.addEventListener('keydown', (e) => { if (e.key === 'Shift') { const now = Date.now(); shiftPressTimes = shiftPressTimes.filter(t => now - t < 1000); shiftPressTimes.push(now); if (shiftPressTimes.length >= 3) { stopTyping(); shiftPressTimes = []; } } }); })();