diff --git a/CHANGELOG.md b/CHANGELOG.md index 84ca433..990689a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## 2026-06-21 +- 发布用户脚本 v22.7:快捷键默认从 `Alt+Shift+P/A` 改为外挂工具更常见且更少冲突的 `F8/F9`,并在配置面板新增快捷键自定义和说明。 - 发布用户脚本 v22.6:新增快捷键 `Alt+Shift+P` 暂停/恢复脚本,暂停时主页面扫描/订阅点击和验证码 iframe 自动点字/确认都会停止;新增 `Alt+Shift+A` 快速切换自动点击订阅。 - 发布用户脚本 v22.5:修正 v22.4 的释放提前量方向,改为保守发射公式 `max(0, RTT/2 - 20ms)`,确保本地发射不早于预测安全点,也不晚于 10:00 目标时间;校准失败时不提前,10:00 整释放。 - 发布用户脚本 v22.4:冲刺模式默认目标从 `09:59:58` 改为 `10:00:00`,并把旧默认配置自动迁移到 10 点整。 diff --git a/README.md b/README.md index 4dd8f21..e1bb431 100644 --- a/README.md +++ b/README.md @@ -149,8 +149,10 @@ https://www.bigmodel.cn/glm-coding - `Esc`:关闭系统繁忙弹窗或支付弹窗 - `Enter` / `Space`:点击验证码确认按钮 -- `Alt+Shift+P`:暂停/恢复脚本(暂停后停止扫描、订阅点击、验证码自动点击/确认) -- `Alt+Shift+A`:切换自动点击订阅 +- `F8`:暂停/恢复脚本(暂停后停止扫描、订阅点击、验证码自动点击/确认) +- `F9`:切换自动点击订阅 + +快捷键可在配置面板中自定义。默认使用外挂工具常见的 `F8/F9`,避开浏览器常见快捷键;输入框、文本框、下拉框和可编辑区域内不会触发。 ### 重要提醒 diff --git a/glm-coding-helper.user.js b/glm-coding-helper.user.js index 52a7085..5f6e705 100644 --- a/glm-coding-helper.user.js +++ b/glm-coding-helper.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name 智谱 GLM Coding Plan 抢购助手 + 本地 OCR 自动验证码 // @namespace http://tampermonkey.net/ -// @version 22.6 +// @version 22.7 // @description GLM Coding Rush / 智谱 GLM Coding Plan 抢购助手,一键抢购油猴脚本 / Tampermonkey userscript,配合本地 CPU/GPU OCR 自动识别中文点选验证码并点击,支持多窗口并发、限流重试和支付页安全保护 // @author mumumi // @include https://*bigmodel.cn/glm-coding* @@ -535,6 +535,8 @@ RUSH_TARGET_SEC : 0, RUSH_HOLD_WINDOW_MS : 10000, RUSH_RELEASE_ADVANCE_MS: 0, + HOTKEY_PAUSE: 'F8', + HOTKEY_AUTO_CLICK_SUB: 'F9', }; function loadCfg() { try { const s = GM_getValue(STORAGE_KEY, null); return s ? { ...DEF, ...JSON.parse(s) } : { ...DEF }; } catch { return { ...DEF }; } } function saveCfg(c) { GM_setValue(STORAGE_KEY, JSON.stringify(c)); } @@ -599,8 +601,63 @@ GM_registerMenuCommand('⚙️ 打开配置面板', openConfigPanel); GM_registerMenuCommand('🗑️ 清除今日套餐状态缓存', () => { localStorage.removeItem(_dsKey); alert('今日状态已清除,即将刷新。'); location.reload(); }); GM_registerMenuCommand('🚀 一键多开窗口', openMultipleWindows); - GM_registerMenuCommand('⏯️ 暂停/恢复脚本 (Alt+Shift+P)', toggleRuntimePause); - GM_registerMenuCommand('🖱️ 切换自动点击订阅 (Alt+Shift+A)', toggleAutoClickSub); + function normalizeHotkeyString(value, fallback = '') { + const raw = String(value || '').trim(); + if (!raw) return fallback; + const aliases = { + esc: 'Escape', + escape: 'Escape', + ins: 'Insert', + insert: 'Insert', + del: 'Delete', + delete: 'Delete', + space: 'Space', + ' ': 'Space', + pause: 'Pause', + home: 'Home', + end: 'End', + pgup: 'PageUp', + pageup: 'PageUp', + pgdn: 'PageDown', + pagedown: 'PageDown', + }; + const parts = raw.split('+').map(s => s.trim()).filter(Boolean); + const mods = []; + let key = ''; + for (const part of parts) { + const lower = part.toLowerCase(); + if (lower === 'ctrl' || lower === 'control') { if (!mods.includes('Ctrl')) mods.push('Ctrl'); continue; } + if (lower === 'alt') { if (!mods.includes('Alt')) mods.push('Alt'); continue; } + if (lower === 'shift') { if (!mods.includes('Shift')) mods.push('Shift'); continue; } + if (lower === 'meta' || lower === 'cmd' || lower === 'win') { if (!mods.includes('Meta')) mods.push('Meta'); continue; } + if (/^f([1-9]|1[0-2])$/i.test(part)) key = part.toUpperCase(); + else if (aliases[lower]) key = aliases[lower]; + else if (part.length === 1) key = part.toUpperCase(); + else key = part; + } + if (!key) return fallback; + return [...mods, key].join('+'); + } + function hotkeyFromEvent(e) { + const mods = []; + if (e.ctrlKey) mods.push('Ctrl'); + if (e.altKey) mods.push('Alt'); + if (e.shiftKey) mods.push('Shift'); + if (e.metaKey) mods.push('Meta'); + let key = e.key || ''; + if (!key || ['Control', 'Alt', 'Shift', 'Meta'].includes(key)) return ''; + if (key === ' ') key = 'Space'; + if (/^f([1-9]|1[0-2])$/i.test(key)) key = key.toUpperCase(); + else if (key.length === 1) key = key.toUpperCase(); + return [...mods, key].join('+'); + } + function hotkeyMatches(e, hotkey) { + return normalizeHotkeyString(hotkey) === hotkeyFromEvent(e); + } + const pauseHotkey = () => normalizeHotkeyString(CFG.HOTKEY_PAUSE, 'F8'); + const autoClickSubHotkey = () => normalizeHotkeyString(CFG.HOTKEY_AUTO_CLICK_SUB, 'F9'); + GM_registerMenuCommand(`⏯️ 暂停/恢复脚本 (${pauseHotkey()})`, toggleRuntimePause); + GM_registerMenuCommand(`🖱️ 切换自动点击订阅 (${autoClickSubHotkey()})`, toggleAutoClickSub); function saveRuntimeCfgPatch(patch) { Object.assign(CFG, patch); saveCfg({ ...CFG }); @@ -609,7 +666,7 @@ runtimePaused = paused === true; GM_setValue(RUNTIME_PAUSE_KEY, runtimePaused); if (runtimePaused) { - setBar(`⏸️ 脚本已暂停(${source})。Alt+Shift+P 恢复。`, '#722ed1'); + setBar(`⏸️ 脚本已暂停(${source})。${pauseHotkey()} 恢复。`, '#722ed1'); } else { setBar(`▶️ 脚本已恢复(${source})。`, '#237804'); } @@ -620,7 +677,7 @@ function toggleAutoClickSub() { const next = !CFG.AUTO_CLICK_SUB; saveRuntimeCfgPatch({ AUTO_CLICK_SUB: next }); - setBar(`${next ? '✅ 已开启' : '🛑 已关闭'}自动点击订阅(Alt+Shift+A)`, next ? '#237804' : '#d46b08'); + setBar(`${next ? '✅ 已开启' : '🛑 已关闭'}自动点击订阅(${autoClickSubHotkey()})`, next ? '#237804' : '#d46b08'); } function isEditableHotkeyTarget(el) { if (!el) return false; @@ -628,15 +685,13 @@ return tag === 'input' || tag === 'textarea' || tag === 'select' || el.isContentEditable; } function handleControlHotkeys(e) { - if (!e.altKey || !e.shiftKey || e.ctrlKey || e.metaKey) return false; if (isEditableHotkeyTarget(e.target)) return false; - const key = String(e.key || '').toLowerCase(); - if (key === 'p') { + if (hotkeyMatches(e, pauseHotkey())) { e.preventDefault(); toggleRuntimePause(); return true; } - if (key === 'a') { + if (hotkeyMatches(e, autoClickSubHotkey())) { e.preventDefault(); toggleAutoClickSub(); return true; @@ -1024,6 +1079,20 @@ : +
+
+
+ 快捷键 + ? +
+
+ 暂停/恢复 + + 自动点击订阅 + +
+
推荐:F8/F9、Insert/Home/End。避免 F5/F11/F12、Ctrl/Alt 组合和输入法快捷键。
+
@@ -1036,6 +1105,18 @@ document.body.appendChild(ov); const getPkgs = buildTransferBox(document.getElementById('glm-wp'), PKGS_MAP, CFG.PACKAGES_PRIORITY, '套餐优先级'); const getTabs = buildTransferBox(document.getElementById('glm-wt'), TABS_MAP, CFG.TABS_PRIORITY, '订阅周期优先级'); + function bindHotkeyInput(input) { + input.title = '点击后按键录入'; + input.addEventListener('keydown', e => { + e.preventDefault(); + e.stopPropagation(); + const hk = hotkeyFromEvent(e); + if (hk) input.value = hk; + }); + input.addEventListener('focus', () => input.select()); + } + bindHotkeyInput(panel.querySelector('#glm-hk-pause')); + bindHotkeyInput(panel.querySelector('#glm-hk-sub')); panel.querySelector('#glm-cc').onclick = () => ov.remove(); panel.querySelector('#glm-multi').onclick = () => { openMultipleWindows(); }; panel.querySelector('#glm-cs').onclick = () => { @@ -1060,6 +1141,8 @@ RUSH_TARGET_MIN: parseInt(panel.querySelector('#glm-rm').value, 10), RUSH_TARGET_SEC: parseInt(panel.querySelector('#glm-rs').value, 10), RUSH_RELEASE_ADVANCE_MS: CFG.RUSH_RELEASE_ADVANCE_MS, + HOTKEY_PAUSE: normalizeHotkeyString(panel.querySelector('#glm-hk-pause').value, 'F8'), + HOTKEY_AUTO_CLICK_SUB: normalizeHotkeyString(panel.querySelector('#glm-hk-sub').value, 'F9'), SAFE_DEFAULTS_VERSION, }); ov.remove(); alert('已保存,即将刷新。'); location.reload(); @@ -1072,7 +1155,7 @@ function tick() { if (state === 'DONE') return; if (runtimePaused) { - setBar('⏸️ 脚本已暂停。Alt+Shift+P 恢复。', '#722ed1'); + setBar(`⏸️ 脚本已暂停。${pauseHotkey()} 恢复。`, '#722ed1'); return; } if (window.__glmRushConfirmed && window.__glmRushDialogSeen && !getPayDialog()) {