diff --git a/README.md b/README.md index d4330d6..b85a20d 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ - 📝 Emulate typing by pasting clipboard contents into text input fields. - âšī¸ Ability to stop the emulation. - đŸ•šī¸ Realistic typing emulation with random intervals between key presses. +- âŗ Settings to adjust keystroke speed +- âŒ¨ī¸âŒ¨ī¸ Hotkey support: Ctrl/Command+Shift+Y (default) ## đŸ› ī¸ Installation diff --git a/background.js b/background.js index ed6f495..f76120f 100644 --- a/background.js +++ b/background.js @@ -1,23 +1,67 @@ chrome.runtime.onInstalled.addListener(() => { - chrome.contextMenus.create({ - id: "pasteHuman", - title: "PasteHuman: Emulate typing", - contexts: ["editable"], - }); + chrome.contextMenus.create({ + id: "pasteHuman", + title: "PasteHuman: Emulate typing", + contexts: ["editable"], + }); - chrome.contextMenus.create({ - id: "stopPasteHuman", - title: "PasteHuman: Stop typing", - contexts: ["editable"], - }); + chrome.contextMenus.create({ + id: "stopPasteHuman", + title: "PasteHuman: Stop typing", + contexts: ["editable"], + }); + + // Set default settings + const defaultSettings = { + minDelay: 10, + maxDelay: 75, + extraDelayChance: 0.05, + extraDelayMin: 20, + extraDelayMax: 100, + }; + + chrome.storage.sync.set(defaultSettings, function () { + console.log("Default settings saved"); + }); }); chrome.contextMenus.onClicked.addListener((info, tab) => { - console.log('background.js: Context menu clicked:', info.menuItemId); // Log context menu item clicked + console.log("background.js: Context menu clicked:", info.menuItemId); // Log context menu item clicked + + if (info.menuItemId === "pasteHuman") { + // Get settings from chrome.storage + chrome.storage.sync.get(defaultSettings, function (items) { + // Send settings along with action + chrome.tabs.sendMessage(tab.id, { action: "emulateTyping", settings: items }); + }); + } else if (info.menuItemId === "stopPasteHuman") { + chrome.tabs.sendMessage(tab.id, { action: "stopTyping" }); + } +}); + +chrome.commands.onCommand.addListener(function (command) { + console.log("Command:", command); - if (info.menuItemId === "pasteHuman") { - chrome.tabs.sendMessage(tab.id, { action: "emulateTyping" }); - } else if (info.menuItemId === "stopPasteHuman") { - chrome.tabs.sendMessage(tab.id, { action: "stopTyping" }); - } + if (command === "emulateTyping") { + // Get settings from chrome.storage + chrome.storage.local.get( + { + minDelay: 50, + maxDelay: 200, + extraDelayChance: 0.05, + extraDelayMin: 200, + extraDelayMax: 700, + }, + function (items) { + // Send settings along with action + chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) { + chrome.tabs.sendMessage(tabs[0].id, { action: "emulateTyping", settings: items }); + }); + } + ); + } else if (command === "stopTyping") { + chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) { + chrome.tabs.sendMessage(tabs[0].id, { action: "stopTyping" }); + }); + } }); diff --git a/content.js b/content.js index cc6decd..95580e7 100644 --- a/content.js +++ b/content.js @@ -1,17 +1,18 @@ + + let currentTypingSession = null; chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) { - console.log('content.js: Message received:', request.action); // Log message received + //console.log("content.js: Message received:", request.action); // Log message received if (request.action === "emulateTyping") { - console.log("content.js: Action received: emulateTyping"); + //console.log("content.js: Action received: emulateTyping"); + let settings = request.settings; currentTypingSession = Math.random().toString(); // Create a new unique typing session identifier - navigator.clipboard - .readText() - .then((clipText) => { - console.log("content.js: Clipboard text read:", clipText); // Log clipboard text - emulateTyping(clipText, currentTypingSession, request.delayedStart); - }); + navigator.clipboard.readText().then((clipText) => { + //console.log("content.js: Clipboard text read:", clipText); // Log clipboard text + emulateTyping(clipText, currentTypingSession, request.delayedStart, settings); + }); } else if (request.action === "stopTyping") { currentTypingSession = null; // Invalidate the current typing session } @@ -20,18 +21,18 @@ chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) { // Listen for any keydown event at the window level window.addEventListener("keydown", function () { currentTypingSession = null; // Invalidate the current typing session - console.log('content.js: Keydown event detected'); // Log keydown event + //console.log("content.js: Keydown event detected"); // Log keydown event }); -function emulateTyping(text, session, delayedStart) { +function emulateTyping(text, session, delayedStart, settings) { const activeElement = document.activeElement; - console.log('content.js: Active element:', activeElement); // Log the active element + //console.log("content.js: Active element:", activeElement); // Log the active element let i = 0; const startTyping = function () { function typeNextCharacter() { - console.log('content.js: Typing character', text[i]); // Log character being typed + // console.log("content.js: Typing character", text[i]); // Log character being typed if (i < text.length && session === currentTypingSession) { // Create a KeyboardEvent instance @@ -49,10 +50,14 @@ function emulateTyping(text, session, delayedStart) { // Attempt to insert the text using document.execCommand document.execCommand("insertText", false, text[i++]); - let delay = Math.random() * (200 - 50) + 50; + // Set the initial delay to a random value between MIN_DELAY and MAX_DELAY. + // This simulates the natural variation in the time it takes a human to press each key. + let delay = Math.random() * (settings.maxDelay - settings.minDelay) + settings.minDelay; - if (Math.random() < 0.05) { - delay += Math.random() * (700 - 200) + 200; + // With a 5% chance, add an additional delay to the base delay. + // This simulates the occasional longer pauses a human might take while typing, such as when thinking or moving from one part of the keyboard to another. + if (Math.random() < settings.extraDelayChance) { + delay += Math.random() * (settings.extraDelayMax - settings.extraDelayMin) + settings.extraDelayMin; } setTimeout(typeNextCharacter, delay); @@ -63,7 +68,7 @@ function emulateTyping(text, session, delayedStart) { }; if (delayedStart) { - console.log('content.js: Starting typing with a delay'); + //console.log("content.js: Starting typing with a delay"); setTimeout(startTyping, 0); // Delay is in milliseconds } else { startTyping(); diff --git a/manifest.json b/manifest.json index 0c4407c..c056894 100644 --- a/manifest.json +++ b/manifest.json @@ -2,8 +2,8 @@ "manifest_version": 3, "name": "PasteHuman", "description": "Transforming plain text into human-like typing. This extension emulates typing in textboxes.", - "version": "1.0", - "permissions": ["contextMenus", "activeTab", "clipboardRead"], + "version": "1.1", + "permissions": ["contextMenus", "activeTab", "clipboardRead", "storage"], "background": { "service_worker": "background.js" }, @@ -15,6 +15,22 @@ "128": "icons/icon128.png" } }, + "commands": { + "emulateTyping": { + "suggested_key": { + "default": "Ctrl+Shift+Y", + "mac": "Command+Shift+Y" + }, + "description": "Emulate typing" + }, + "stopTyping": { + "suggested_key": { + "default": "Ctrl+Shift+U", + "mac": "Command+Shift+U" + }, + "description": "Stop typing" + } + }, "icons": { "16": "icons/icon16.png", "48": "icons/icon48.png", @@ -25,5 +41,6 @@ "matches": [""], "js": ["content.js"] } - ] + ], + "options_page": "options.html" } diff --git a/options.html b/options.html new file mode 100644 index 0000000..8f4e021 --- /dev/null +++ b/options.html @@ -0,0 +1,46 @@ + + + + PasteHuman Settings + + + + +

PasteHuman Settings

+
+
+
+
+
+
+
+
+
+
+
+ +
+ + \ No newline at end of file diff --git a/options.js b/options.js new file mode 100644 index 0000000..273bf2c --- /dev/null +++ b/options.js @@ -0,0 +1,30 @@ +document.addEventListener('DOMContentLoaded', function () { + // Load settings + chrome.storage.sync.get({ + minDelay: 10, + maxDelay: 75, + extraDelayChance: 0.05, + extraDelayMin: 20, + extraDelayMax: 100, + }, function (items) { + document.getElementById('minDelay').value = items.minDelay; + document.getElementById('maxDelay').value = items.maxDelay; + document.getElementById('extraDelayChance').value = items.extraDelayChance; + document.getElementById('extraDelayMin').value = items.extraDelayMin; + document.getElementById('extraDelayMax').value = items.extraDelayMax; + }); + + // Save settings + document.getElementById('settingsForm').addEventListener('submit', function (e) { + e.preventDefault(); + chrome.storage.sync.set({ + minDelay: parseInt(document.getElementById('minDelay').value), + maxDelay: parseInt(document.getElementById('maxDelay').value), + extraDelayChance: parseFloat(document.getElementById('extraDelayChance').value), + extraDelayMin: parseInt(document.getElementById('extraDelayMin').value), + extraDelayMax: parseInt(document.getElementById('extraDelayMax').value), + }, function () { + alert('Settings saved'); + }); + }); +}); \ No newline at end of file diff --git a/popup.js b/popup.js index 0b0f946..efc474c 100644 --- a/popup.js +++ b/popup.js @@ -1,16 +1,16 @@ document.getElementById('startTyping').addEventListener('click', function() { - console.log("popup.js: Start typing button clicked"); + //console.log("popup.js: Start typing button clicked"); // Using a timeout function to delay the message being sent by 5 seconds setTimeout(function() { chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { var currentTab = tabs[0]; // There should be only one in this array - console.log(`popup.js: Sending message to tab ${currentTab.id}`); + //console.log(`popup.js: Sending message to tab ${currentTab.id}`); chrome.tabs.sendMessage(currentTab.id, { action: 'emulateTyping', delayedStart: true, }, function(response) { - console.log("popup.js: Message sent: emulateTyping"); + //console.log("popup.js: Message sent: emulateTyping"); }); }); }, 5000); // 5000 milliseconds (5 seconds) delay