Greasy Fork

Greasy Fork is available in English.

解锁网页复制/粘贴/右键/切屏限制💉

移除网页对复制、粘贴、右键、选中、切屏检测(onblur / visibilitychange)的限制,支持 iframe 与 Shadow DOM 深层拦截。

当前为 2025-11-06 提交的版本,查看 最新版本

// ==UserScript==
// @name         解锁网页复制/粘贴/右键/切屏限制💉
// @namespace    http://greasyfork.icu/zh-CN/users/1534803-ookamiame
// @version      1.0
// @description  移除网页对复制、粘贴、右键、选中、切屏检测(onblur / visibilitychange)的限制,支持 iframe 与 Shadow DOM 深层拦截。
// @author       狼小雨
// @license      MIT
// @match        *://*/*
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function () {
    'use strict';
// Hook window/document 层面的焦点与可见性检测
    function hookGlobalFocus() {
        // 拦截 window.onblur
        Object.defineProperty(window, 'onblur', {
            configurable: true,
            enumerable: true,
            get() { return null; },
            set(v) { console.log('[Hook] 阻止设置 window.onblur:', v); }
        });

        // 拦截 window.addEventListener('blur', ...)
        const _addEventListener = window.addEventListener;
        window.addEventListener = function (type, listener, options) {
            // 这些事件用于检测离开、切屏、鼠标移出
            if (['blur', 'focus', 'visibilitychange', 'mouseleave',
                'mouseout', 'pagehide', 'beforeunload', 'unload'].includes(type)) {
                console.log('[Hook] 阻止添加事件:', type);
                return;
            }
            return _addEventListener.call(this, type, listener, options);
        };

        // 拦截 document.onvisibilitychange
        Object.defineProperty(document, 'onvisibilitychange', {
            configurable: true,
            enumerable: true,
            get() { return null; },
            set(v) { console.log('[Hook] 阻止设置 document.onvisibilitychange:', v); }
        });
        // 让页面始终认为自己在前台
        
        Object.defineProperty(document, 'hidden', {
            configurable: true,
            get() { return false; }
        });
        Object.defineProperty(document, 'visibilityState', {
            configurable: true,
            get() { return 'visible'; }
        });
        document.hasFocus = () => true;
    }

    // 解锁复制/粘贴/右键/选中限制
    function unlockPageRestrictions(root = document) {
        const eventsToBlock = [
            'copy', 'cut', 'paste', 'selectstart', 'contextmenu',
            'dragstart', 'mousedown', 'mouseup', 'keydown', 'keyup', 'keypress',
            'blur', 'focus', 'visibilitychange',
            'mouseleave', 'mouseout', 'pagehide', 'beforeunload', 'unload'
        ];

        // 阻止事件冒泡
        eventsToBlock.forEach(event => {
            root.addEventListener(event, e => e.stopPropagation(), true);
        });

        // 遍历所有节点解除绑定与样式
        const all = root.querySelectorAll('*');
        all.forEach(el => {
            el.oncopy = el.oncut = el.onpaste =
            el.onselectstart = el.oncontextmenu =
            el.ondragstart = el.onmousedown =
            el.onmouseup = el.onkeydown = el.onkeypress = null;

            el.style.userSelect = 'text';
            el.style.webkitUserSelect = 'text';
            el.style.msUserSelect = 'text';
            el.style.mozUserSelect = 'text';
        });

        // 解除焦点检测
        window.onblur = null;
        window.onfocus = null;
        document.onvisibilitychange = null;
        document.onkeydown = null;
        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) {
                    unlockPageRestrictions(doc);
                    deepUnlock(doc);
                }
            } catch (e) {
                console.warn('[Tampermonkey] 无法访问 iframe(跨域限制):', e);
            }
        });

        // 递归 Shadow DOM
        const traverseShadow = (node) => {
            if (!node) return;
            if (node.shadowRoot) {
                unlockPageRestrictions(node.shadowRoot);
                deepUnlock(node.shadowRoot);
            }
            node.childNodes.forEach(traverseShadow);
        };
        traverseShadow(root.body || root);
    }

// 启动解锁逻辑 + 动态监听 DOM 变化
    hookGlobalFocus();

    const run = () => {
        deepUnlock(document);
    };

    // 页面加载后运行一次
    window.addEventListener('DOMContentLoaded', run);

    // 动态监听(防止网站重新注入限制)
    const observer = new MutationObserver(() => deepUnlock(document));
    observer.observe(document, { childList: true, subtree: true });
})();