// ==UserScript== // @name 咪咕游戏保活(模拟Ctrl按键) // @namespace http://tampermonkey.net/ // @version 5.2 // @description 通过模拟Ctrl键防止挂机断开,含悬浮面板和测试按钮 // @author Your Assistant // @match https://www.migufun.com/* // @match https://www.zfrontier.com/lab/keyboardTester // @grant none // @license MPL-2.0 // ==/UserScript== (function() { 'use strict'; // ---------- 配置 ---------- const INTERVAL = 5 * 60 * 1000; // 5分钟 const MAX_RECORDS = 10; // ---------- 状态 ---------- let nextExecutionTime = Date.now() + INTERVAL; let records = []; let panelVisible = false; let countdownInterval = null; let testTimer = null; // ---------- 核心:模拟键盘按键(Ctrl) ---------- function simulateKeyPress(type = 'auto') { try { // 创建 keydown 和 keyup 事件,使用左 Ctrl const keyDownEvent = new KeyboardEvent('keydown', { key: 'Control', code: 'ControlLeft', keyCode: 17, which: 17, ctrlKey: true, // 标记Ctrl被按下 bubbles: true, cancelable: true, composed: true }); const keyUpEvent = new KeyboardEvent('keyup', { key: 'Control', code: 'ControlLeft', keyCode: 17, which: 17, ctrlKey: false, // 释放后Ctrl状态为false bubbles: true, cancelable: true, composed: true }); // 在 document 上触发 document.dispatchEvent(keyDownEvent); document.dispatchEvent(keyUpEvent); // 额外:也可以在 body 或游戏容器上触发(如果存在) const target = document.querySelector('canvas, #game-container, body') || document.body; target.dispatchEvent(keyDownEvent); target.dispatchEvent(keyUpEvent); // 记录执行 const now = new Date(); const timeStr = now.toLocaleTimeString() + '.' + String(now.getMilliseconds()).padStart(3, '0'); const label = type === 'test' ? '🧪 测试' : '🔄 保活'; records.unshift({ time: timeStr, type: label, detail: 'Ctrl 按键' }); if (records.length > MAX_RECORDS) records.pop(); if (type === 'auto') { nextExecutionTime = Date.now() + INTERVAL; } if (panelVisible) updatePanelContent(); console.log(`[保活] ${label} 模拟 Ctrl 按键 at ${timeStr}`); } catch (e) { console.warn('⚠️ [保活] 脚本异常:', e.message); } } // ---------- 测试调度 ---------- function scheduleTest() { if (testTimer) { clearTimeout(testTimer); testTimer = null; } const testBtn = document.getElementById('migu-test-btn'); if (testBtn) { testBtn.textContent = '⏳ 10s...'; testBtn.disabled = true; testBtn.style.opacity = '0.6'; } testTimer = setTimeout(() => { simulateKeyPress('test'); if (testBtn) { testBtn.textContent = '🧪 10秒后测试'; testBtn.disabled = false; testBtn.style.opacity = '1'; } testTimer = null; if (panelVisible) updatePanelContent(); }, 10000); } // ---------- 创建UI(保持不变) ---------- function createUI() { // 悬浮按钮 const btn = document.createElement('div'); btn.id = 'migu-keepalive-btn'; btn.textContent = '⏱️'; btn.style.cssText = ` position: fixed; bottom: 20px; right: 20px; width: 50px; height: 50px; border-radius: 50%; background: #2196F3; color: white; font-size: 24px; text-align: center; line-height: 50px; cursor: pointer; z-index: 999999; box-shadow: 0 2px 10px rgba(0,0,0,0.3); user-select: none; transition: background 0.2s; `; btn.title = '点击查看保活状态'; btn.addEventListener('mouseenter', () => btn.style.background = '#1976D2'); btn.addEventListener('mouseleave', () => btn.style.background = '#2196F3'); // 面板 const panel = document.createElement('div'); panel.id = 'migu-keepalive-panel'; panel.style.cssText = ` position: fixed; bottom: 80px; right: 20px; width: 300px; max-height: 400px; background: #ffffff; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.25); padding: 15px; z-index: 999998; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; font-size: 14px; color: #333; display: none; overflow-y: auto; border: 1px solid #e0e0e0; `; // 倒计时 const countdownDiv = document.createElement('div'); countdownDiv.id = 'migu-countdown'; countdownDiv.style.cssText = ` font-weight: bold; margin-bottom: 10px; padding-bottom: 8px; border-bottom: 1px solid #eee; `; countdownDiv.textContent = '⏳ 下次执行: 计算中...'; // 测试按钮 const testBtn = document.createElement('button'); testBtn.id = 'migu-test-btn'; testBtn.textContent = '🧪 10秒后测试'; testBtn.style.cssText = ` background: #4CAF50; color: white; border: none; border-radius: 4px; padding: 6px 12px; font-size: 14px; cursor: pointer; margin-bottom: 10px; transition: background 0.2s; `; testBtn.addEventListener('mouseenter', () => testBtn.style.background = '#388E3C'); testBtn.addEventListener('mouseleave', () => testBtn.style.background = '#4CAF50'); testBtn.addEventListener('click', scheduleTest); // 记录标题 const recordsTitle = document.createElement('div'); recordsTitle.style.cssText = ` font-weight: bold; margin-bottom: 4px; color: #555; `; recordsTitle.textContent = '📋 执行记录 (最近' + MAX_RECORDS + '条)'; // 记录列表 const recordsList = document.createElement('div'); recordsList.id = 'migu-records-list'; recordsList.style.cssText = ` max-height: 200px; overflow-y: auto; font-size: 13px; `; // 组装 panel.appendChild(countdownDiv); panel.appendChild(testBtn); panel.appendChild(recordsTitle); panel.appendChild(recordsList); document.body.appendChild(btn); document.body.appendChild(panel); // 按钮点击切换面板 btn.addEventListener('click', (e) => { e.stopPropagation(); panelVisible = !panelVisible; panel.style.display = panelVisible ? 'block' : 'none'; if (panelVisible) { updatePanelContent(); if (!countdownInterval) { countdownInterval = setInterval(updateCountdown, 1000); } } else { if (countdownInterval) { clearInterval(countdownInterval); countdownInterval = null; } } }); } // ---------- 更新面板 ---------- function updatePanelContent() { updateCountdown(); updateRecords(); } function updateCountdown() { const countdownDiv = document.getElementById('migu-countdown'); if (!countdownDiv) return; const now = Date.now(); const remaining = Math.max(0, Math.floor((nextExecutionTime - now) / 1000)); const minutes = Math.floor(remaining / 60); const seconds = remaining % 60; countdownDiv.textContent = `⏳ 下次执行: ${minutes}分 ${seconds.toString().padStart(2, '0')}秒`; if (remaining <= 0) { countdownDiv.textContent = '⏳ 即将执行...'; } } function updateRecords() { const list = document.getElementById('migu-records-list'); if (!list) return; if (records.length === 0) { list.innerHTML = '