Automates clicks at various locations on the screen with customizable intervals
目前為
// ==UserScript==
// @name YAD Multiple Auto Clicker
// @namespace http://tampermonkey.net/
// @version 2.1
// @description Automates clicks at various locations on the screen with customizable intervals
// @author YAD
// @license MIT
// @match *://*/*
// @grant none
// ==/UserScript==
(function () {
'use strict';
let buttons = [];
let buttonId = 1;
let isRunning = false;
const loadButtonData = () => JSON.parse(localStorage.getItem('buttonData') || '[]');
const saveButtonData = () => {
const buttonData = buttons.map(button => ({
id: button.id,
top: button.style.top,
left: button.style.left,
interval: button.dataset.interval || 1000,
clicks: button.dataset.clicks || 1
}));
localStorage.setItem('buttonData', JSON.stringify(buttonData));
};
const saveRunningState = () => {
localStorage.setItem('isRunning', JSON.stringify(isRunning));
};
const loadRunningState = () => {
return JSON.parse(localStorage.getItem('isRunning') || 'false');
};
const mainInterface = document.createElement('div');
mainInterface.style.position = 'fixed';
mainInterface.style.right = '10px';
mainInterface.style.top = '50%';
mainInterface.style.transform = 'translateY(-50%)';
mainInterface.style.zIndex = '9999';
const plusButton = document.createElement('button');
plusButton.textContent = '➕';
plusButton.style.display = 'block';
plusButton.style.padding = '10px';
plusButton.style.marginBottom = '5px';
plusButton.style.fontSize = '16px';
plusButton.style.cursor = 'pointer';
plusButton.style.backgroundColor = '#28a745';
plusButton.style.border = 'none';
plusButton.style.color = 'transparent';
plusButton.style.textShadow = '0 0 0 white';
plusButton.style.borderRadius = '5px';
mainInterface.appendChild(plusButton);
const startStopButton = document.createElement('button');
startStopButton.textContent = '👆';
startStopButton.style.display = 'block';
startStopButton.style.padding = '10px';
startStopButton.style.marginBottom = '5px';
startStopButton.style.fontSize = '16px';
startStopButton.style.cursor = 'pointer';
startStopButton.style.backgroundColor = '#007bff';
startStopButton.style.border = 'none';
startStopButton.style.color = 'white';
startStopButton.style.borderRadius = '5px';
mainInterface.appendChild(startStopButton);
const resetButton = document.createElement('button');
resetButton.textContent = '♻️';
resetButton.style.display = 'block';
resetButton.style.padding = '10px';
resetButton.style.fontSize = '16px';
resetButton.style.cursor = 'pointer';
resetButton.style.backgroundColor = '#dc3545';
resetButton.style.border = 'none';
resetButton.style.color = 'transparent';
resetButton.style.textShadow = '0 0 0 white';
resetButton.style.borderRadius = '5px';
mainInterface.appendChild(resetButton);
document.body.appendChild(mainInterface);
plusButton.addEventListener('click', () => {
createAutoClickButton();
});
startStopButton.addEventListener('click', () => {
isRunning = !isRunning;
saveRunningState();
if (isRunning) {
startStopButton.textContent = '🛑';
startAutoClick();
} else {
startStopButton.textContent = '👆';
stopAutoClick();
}
});
resetButton.addEventListener('click', () => {
buttons.forEach(button => button.remove());
buttons = [];
localStorage.removeItem('buttonData');
buttonId = 1;
stopAutoClick();
startStopButton.textContent = '👆';
});
function createAutoClickButton(buttonData = null) {
const autoButton = document.createElement('div');
autoButton.id = buttonId++;
autoButton.textContent = autoButton.id;
autoButton.style.width = '50px';
autoButton.style.height = '50px';
autoButton.style.borderRadius = '50%';
autoButton.style.backgroundColor = '#ff0000cc';
autoButton.style.position = 'absolute';
autoButton.style.top = buttonData?.top || '50%';
autoButton.style.left = buttonData?.left || '50%';
autoButton.style.display = 'flex';
autoButton.style.alignItems = 'center';
autoButton.style.justifyContent = 'center';
autoButton.style.cursor = 'pointer';
autoButton.style.zIndex = '9999';
autoButton.style.color = 'white';
document.body.appendChild(autoButton);
makeDraggable(autoButton);
autoButton.dataset.interval = buttonData?.interval || 1000;
autoButton.dataset.clicks = buttonData?.clicks || 1;
buttons.push(autoButton);
autoButton.addEventListener('contextmenu', (e) => {
e.preventDefault();
openSettingsModal(autoButton);
});
autoButton.addEventListener('click', (e) => {
e.stopPropagation();
});
}
function makeDraggable(element) {
let posX = 0, posY = 0, mouseX = 0, mouseY = 0;
element.onmousedown = function (e) {
e.preventDefault();
mouseX = e.clientX;
mouseY = e.clientY;
document.onmousemove = moveElement;
document.onmouseup = stopMovingElement;
};
function moveElement(e) {
posX = mouseX - e.clientX;
posY = mouseY - e.clientY;
mouseX = e.clientX;
mouseY = e.clientY;
element.style.top = (element.offsetTop - posY) + 'px';
element.style.left = (element.offsetLeft - posX) + 'px';
}
function stopMovingElement() {
document.onmouseup = null;
document.onmousemove = null;
saveButtonData();
}
}
function openSettingsModal(button) {
const modal = document.createElement('div');
modal.style.position = 'fixed';
modal.style.top = '50%';
modal.style.left = '50%';
modal.style.transform = 'translate(-50%, -50%)';
modal.style.zIndex = '10000';
modal.style.padding = '15px';
modal.style.backgroundColor = '#fff';
modal.style.borderRadius = '8px';
modal.style.boxShadow = '0px 4px 12px rgba(0, 0, 0, 0.1)';
modal.style.width = '300px';
modal.style.fontFamily = 'Arial, sans-serif';
const title = document.createElement('h3');
title.textContent = 'Settings';
title.style.marginTop = '0';
title.style.marginBottom = '15px';
title.style.color = '#333';
title.style.textAlign = 'center';
title.style.fontSize = '18px';
modal.appendChild(title);
const form = document.createElement('form');
form.style.display = 'flex';
form.style.flexDirection = 'column';
form.style.gap = '10px';
modal.appendChild(form);
const createInputField = (labelText, inputType, inputValue) => {
const fieldWrapper = document.createElement('div');
fieldWrapper.style.display = 'flex';
fieldWrapper.style.flexDirection = 'column';
const label = document.createElement('label');
label.textContent = labelText;
label.style.fontSize = '14px';
label.style.color = '#555';
label.style.marginBottom = '5px';
fieldWrapper.appendChild(label);
const input = document.createElement('input');
input.type = inputType;
input.value = inputValue;
input.style.padding = '8px';
input.style.border = '1px solid #ccc';
input.style.borderRadius = '4px';
input.style.fontSize = '14px';
fieldWrapper.appendChild(input);
return { fieldWrapper, input };
};
const intervalField = createInputField('Interval (ms):', 'number', button.dataset.interval);
const clicksField = createInputField('Number of clicks:', 'number', button.dataset.clicks);
form.appendChild(intervalField.fieldWrapper);
form.appendChild(clicksField.fieldWrapper);
const buttonWrapper = document.createElement('div');
buttonWrapper.style.display = 'flex';
buttonWrapper.style.justifyContent = 'center';
buttonWrapper.style.marginTop = '15px';
modal.appendChild(buttonWrapper);
const saveButton = document.createElement('button');
saveButton.textContent = 'Save';
saveButton.style.padding = '8px 16px';
saveButton.style.border = 'none';
saveButton.style.borderRadius = '4px';
saveButton.style.backgroundColor = '#007bff';
saveButton.style.color = 'white';
saveButton.style.fontSize = '14px';
saveButton.style.cursor = 'pointer';
buttonWrapper.appendChild(saveButton);
document.body.appendChild(modal);
saveButton.addEventListener('click', (e) => {
e.preventDefault();
button.dataset.interval = intervalField.input.value;
button.dataset.clicks = clicksField.input.value;
modal.remove();
saveButtonData();
});
window.addEventListener('click', function (event) {
if (event.target === modal) {
modal.remove();
}
});
}
function autoClick(button) {
const interval = button.dataset.interval || 1000;
const clicks = button.dataset.clicks || 1;
let clickCount = 0;
return new Promise(resolve => {
const clickInterval = setInterval(() => {
if (clickCount >= clicks || !isRunning) {
clearInterval(clickInterval);
resolve();
return;
}
const rect = button.getBoundingClientRect();
button.style.visibility = 'hidden';
const elemUnderButton = document.elementFromPoint(
rect.left + rect.width / 2,
rect.top + rect.height / 2
);
button.style.visibility = 'visible';
if (elemUnderButton) {
const tagName = elemUnderButton.tagName.toLowerCase();
if (tagName === 'a' && elemUnderButton.href === '#') {
const event = new Event('click', { bubbles: true, cancelable: true });
elemUnderButton.dispatchEvent(event);
} else {
const event = new MouseEvent('click', {
bubbles: true,
cancelable: true,
view: window,
clientX: rect.left + rect.width / 2,
clientY: rect.top + rect.height / 2
});
elemUnderButton.dispatchEvent(event);
}
clickCount++;
}
}, interval);
});
}
async function startAutoClick() {
if (buttons.length === 0) return;
while (isRunning) {
for (let i = 0; i < buttons.length; i++) {
await autoClick(buttons[i]);
}
}
}
function stopAutoClick() {
isRunning = false;
saveRunningState();
}
function loadButtons() {
const savedButtons = loadButtonData();
savedButtons.forEach(buttonData => createAutoClickButton(buttonData));
}
window.addEventListener('load', () => {
loadButtons();
if (loadRunningState()) {
isRunning = true;
startStopButton.textContent = '🛑';
startAutoClick();
}
});
})();