// ==UserScript== // @name 解锁网页复制/粘贴/右键/切屏限制💉 // @namespace https://greasyfork.org/zh-CN/users/1534803-ookamiame // @version 1.0.1 // @description 移除网页对复制、粘贴、右键、选中、切屏检测(onblur / visibilitychange)的限制,支持 iframe 与 Shadow DOM 深层拦截。 // @author 狼小雨 // @license MIT // @match *://*/* // @grant none // @run-at document-start // @downloadURL https://update.greasyfork.icu/scripts/555006/%E8%A7%A3%E9%94%81%E7%BD%91%E9%A1%B5%E5%A4%8D%E5%88%B6%E7%B2%98%E8%B4%B4%E5%8F%B3%E9%94%AE%E5%88%87%E5%B1%8F%E9%99%90%E5%88%B6%F0%9F%92%89.user.js // @updateURL https://update.greasyfork.icu/scripts/555006/%E8%A7%A3%E9%94%81%E7%BD%91%E9%A1%B5%E5%A4%8D%E5%88%B6%E7%B2%98%E8%B4%B4%E5%8F%B3%E9%94%AE%E5%88%87%E5%B1%8F%E9%99%90%E5%88%B6%F0%9F%92%89.meta.js // ==/UserScript== (function () { 'use strict'; /** 防重复执行标记 */ if (window.__UNLOCK_SCRIPT_LOADED__) return; window.__UNLOCK_SCRIPT_LOADED__ = true; /** 屏蔽事件类型(复制、粘贴、右键、切屏等) */ const blockEvents = new Set([ 'copy', 'cut', 'paste', 'selectstart', 'contextmenu', 'dragstart', 'mousedown', 'mouseup', 'keydown', 'keyup', 'keypress', 'blur', 'focus', 'visibilitychange', 'mouseleave', 'mouseout', 'pagehide', 'beforeunload', 'unload' ]); /** Hook 全局焦点与可见性检测 */ function hookGlobalFocus() { if (window.__FOCUS_HOOKED__) return; window.__FOCUS_HOOKED__ = true; /**工具函数:安全重定义属性 */ function redefine(obj, key, getter, setter) { try { Object.defineProperty(obj, key, { configurable: true, enumerable: true, get: getter, set: setter || (() => {}), }); } catch (e) { console.log(`[Hook] 无法定义属性 ${key}:`, e); } } // Hook window.onblur let customOnBlur = () => redefine(window, 'onblur', () => customOnBlur, (v) => { if (typeof v === 'function') { console.log('[Hook] 阻止网页覆盖 window.onblur'); return; } if (v == null) customOnBlur = null; } ); // Hook window.addEventListener const _addEventListener = window.addEventListener; window.addEventListener = function (type, listener, options) { if (blockEvents.has(type)) { console.log('[Hook] 阻止添加事件:', type); return; } return _addEventListener.call(this, type, listener, options); }; // Hook document.onvisibilitychange let customVisibility = () => redefine(document, 'onvisibilitychange', () => customVisibility, (v) => { if (typeof v === 'function') { console.log('[Hook] 阻止网页覆盖 document.onvisibilitychange'); return; } if (v == null) customVisibility = null; } ); // 页面始终处于前台聚焦状态 Object.defineProperty(document, 'hidden', { configurable: true, get: () => false }); Object.defineProperty(document, 'visibilityState', { configurable: true, get: () => 'visible' }); document.hasFocus = () => true; } /** 解锁网页交互限制 */ function unlockPageRestrictions(root = document) { if (!root || root.__UNLOCKED__) return; root.__UNLOCKED__ = true; // 阻止限制事件冒泡 blockEvents.forEach(event => { root.addEventListener(event, e => e.stopPropagation(), true); }); // 遍历元素解除事件绑定与样式限制 const all = root.querySelectorAll('*'); all.forEach(el => { ['oncopy','oncut','onpaste','onselectstart','oncontextmenu', 'ondragstart','onmousedown','onmouseup','onkeydown','onkeypress'] .forEach(attr => { if (el[attr]) el[attr] = null; }); // 仅当未设置 user-select:none 时再恢复 const style = getComputedStyle(el); if (style.userSelect === 'none') { el.style.userSelect = 'text'; el.style.webkitUserSelect = 'text'; el.style.msUserSelect = 'text'; el.style.mozUserSelect = 'text'; } }); // 全局解除 window.onblur = window.onfocus = document.onvisibilitychange = null; document.onkeydown = document.oncontextmenu = null; } /** 深层处理 iframe 与 shadow DOM */ function deepUnlock(root = document) { unlockPageRestrictions(root); // iframe root.querySelectorAll('iframe').forEach(iframe => { try { const doc = iframe.contentDocument || iframe.contentWindow?.document; if (doc && !doc.__UNLOCKED__) deepUnlock(doc); } catch (e) { console.log('[Unlock] 跨域 iframe 无法访问:', e); } }); // shadow DOM const traverse = node => { if (!node) return; if (node.shadowRoot && !node.shadowRoot.__UNLOCKED__) deepUnlock(node.shadowRoot); node.childNodes.forEach(traverse); }; traverse(root.body || root); } /** 初始化 */ function init() { hookGlobalFocus(); deepUnlock(document); } /** DOM 变化监控(防止重新绑定限制) */ const observer = new MutationObserver(() => { requestIdleCallback(() => deepUnlock(document)); }); observer.observe(document, { childList: true, subtree: true }); // DOMContentLoaded 后执行一次 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();