Unlock Text Selection & Copy

Universal unlock for text selection, copy, right-click menu, and keyboard shortcuts. Defeats CSS user-select, event interception, key blocking, and clipboard clearing.

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

Advertisement:

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

Advertisement:

// ==UserScript==
// @name         Unlock Text Selection & Copy
// @name:zh-CN   解除网页禁止选中/复制限制
// @name:en      Unlock Text Selection & Copy
// @namespace    https://alicexia.app/
// @version      2.0.0
// @description  Universal unlock for text selection, copy, right-click menu, and keyboard shortcuts. Defeats CSS user-select, event interception, key blocking, and clipboard clearing.
// @description:zh-CN 通用解除网页禁止选中文本、复制文本、右键菜单、快捷键等所有限制。支持 CSS user-select、事件拦截、快捷键封锁、剪贴板清空等全部手段。
// @author       alicexia
// @match        https://*.hotjob.cn/*
// @match        https://*.zhiye.com/*
// @match        https://*.iguopin.com/*
// @grant        none
// @run-at       document-start
// @license      MIT
// @contributionURL https://github.com/alicexiacn
// @homepageURL  https://github.com/alicexiacn/unlock-copy
// @supportURL   https://github.com/alicexiacn/unlock-copy/issues
// @icon         data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%234CAF50' d='M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z'/%3E%3C/svg%3E
// @compatible   chrome
// @compatible   edge
// @compatible   firefox
// @compatible   opera
// @compatible   safari
// ==/UserScript==

(function () {
    'use strict';

    // ============================================================
    // 第一层:CSS 防护解除
    // 覆盖 user-select: none / pointer-events: none
    // ============================================================
    function injectCSS() {
        var style = document.createElement('style');
        style.id = 'wb-unlock-select-style';
        style.textContent = [
            '*, *::before, *::after {',
            '    -webkit-user-select: text !important;',
            '    -moz-user-select: text !important;',
            '    -ms-user-select: text !important;',
            '    user-select: text !important;',
            '    -webkit-touch-callout: default !important;',
            '    pointer-events: auto !important;',
            '}'
        ].join('\n');
        (document.head || document.documentElement).appendChild(style);
    }

    // ============================================================
    // 第二层:事件拦截解除
    // 在捕获阶段(capture)用 stopImmediatePropagation 阻断
    // 网站自己注册的 contextmenu / selectstart / copy 等监听器
    // ============================================================
    var blockedEvents = [
        'contextmenu',      // 右键菜单
        'selectstart',      // 开始选中
        'select',           // 选中过程
        'copy',             // 复制
        'cut',              // 剪切
        'paste',            // 粘贴
        'dragstart',        // 拖拽
        'beforecopy',       // 复制前
        'beforecut',        // 剪切前
        'beforepaste',      // 粘贴前
        'mousedown',        // 鼠标按下(部分网站用它阻止选区起点)
        'mouseup'           // 鼠标抬起
    ];

    // 对普通用户来说,mousedown/mouseup 全局拦截可能影响交互
    // 这里只阻断那些调用了 preventDefault 的处理
    blockedEvents.forEach(function (eventName) {
        document.addEventListener(eventName, function (e) {
            e.stopPropagation();
            // stopImmediatePropagation 会阻止同元素上后续注册的同类监听器执行
            // 但只对 selectstart / contextmenu / copy 等关键事件使用
            if (['contextmenu', 'selectstart', 'copy', 'cut', 'paste', 'dragstart'].indexOf(eventName) !== -1) {
                e.stopImmediatePropagation();
            }
            // 放行默认行为
            try { e.returnValue = true; } catch (_) {}
        }, true);  // true = 捕获阶段,比网站的监听器更早执行
    });

    // ============================================================
    // 第三层:快捷键解除
    // 阻断网站对 Ctrl+C / Ctrl+A / Ctrl+X / Ctrl+V 的拦截
    // ============================================================
    document.addEventListener('keydown', function (e) {
        if (e.ctrlKey || e.metaKey) {
            var key = (e.key || '').toLowerCase();
            if (['c', 'a', 'x', 'v', 'insert'].indexOf(key) !== -1) {
                e.stopPropagation();
                e.stopImmediatePropagation();
            }
        }
        // F12 / Ctrl+Shift+I / Ctrl+Shift+J / Ctrl+U 也一并放行
        if (e.key === 'F12' || (e.ctrlKey && e.shiftKey && ['i', 'j', 'c'].indexOf((e.key || '').toLowerCase()) !== -1) || (e.ctrlKey && (e.key || '').toLowerCase() === 'u')) {
            e.stopPropagation();
            e.stopImmediatePropagation();
        }
    }, true);

    // ============================================================
    // 第四层:清除内联事件处理器 & 保护剪贴板
    // ============================================================
    var inlineProps = [
        'oncontextmenu', 'onselectstart', 'oncopy', 'oncut',
        'onpaste', 'ondragstart', 'onmousedown', 'onmouseup',
        'onbeforecopy', 'onbeforecut', 'onbeforepaste'
    ];

    function clearInlineHandlers() {
        inlineProps.forEach(function (prop) {
            try {
                document[prop] = null;
                if (document.body) { document.body[prop] = null; }
                document.documentElement[prop] = null;
            } catch (_) {}
        });
    }

    // 用 Object.defineProperty 彻底锁死,防止网站重新赋值
    inlineProps.forEach(function (prop) {
        try {
            Object.defineProperty(document, prop, {
                get: function () { return null; },
                set: function () { /* 吞掉赋值 */ },
                configurable: true
            });
        } catch (_) {}
    });

    // ============================================================
    // 第五层:MutationObserver 持续监控
    // 部分网站会在 DOM 动态变化后重新注入限制
    // ============================================================
    var observer = new MutationObserver(function () {
        clearInlineHandlers();
    });

    function startObserver() {
        observer.observe(document.documentElement || document, {
            childList: true,
            subtree: true,
            attributes: true,
            attributeFilter: ['oncontextmenu', 'onselectstart', 'oncopy', 'oncut',
                              'onpaste', 'ondragstart', 'style']
        });
    }

    // ============================================================
    // 初始化:多个时机执行,确保覆盖所有加载阶段
    // ============================================================
    // 1. 立即注入 CSS(document-start 时 head 可能还不存在,先放 html 上)
    injectCSS();

    // 2. DOMContentLoaded 时清除内联事件 + 重新注入 CSS + 启动 Observer
    document.addEventListener('DOMContentLoaded', function () {
        clearInlineHandlers();
        injectCSS();
        startObserver();
    });

    // 3. window.load 时再补一次(处理懒加载脚本)
    window.addEventListener('load', function () {
        clearInlineHandlers();
        injectCSS();
    });

    // 4. 如果 document 已经 ready,立即执行
    if (document.readyState !== 'loading') {
        clearInlineHandlers();
        injectCSS();
        startObserver();
    }

    console.log('解除选中/复制限制脚本已加载 ✓');
})();