我真的没有切屏!

我真的没有切屏!!!采用多重策略,从内核层面阻止浏览器将失焦或隐藏状态暴露给网站。尽最大可能伪造一直在窗口的假象

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         我真的没有切屏!
// @namespace    https://github.com/lanzeweie
// @version      0.82
// @description  我真的没有切屏!!!采用多重策略,从内核层面阻止浏览器将失焦或隐藏状态暴露给网站。尽最大可能伪造一直在窗口的假象
// @author       [email protected]
// @match        *://*/*
// @grant        none
// @run-at       document-start
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    const blockEvents = ['visibilitychange', 'blur', 'focus', 'focusin', 'focusout', 'pagehide', 'pageshow'];
    const originalAddEventListener = EventTarget.prototype.addEventListener;

    EventTarget.prototype.addEventListener = function(type, listener, options) {
        if (blockEvents.includes(type)) {
            addLog('proxy', `🚫 已代理并阻止 ${type} 监听器附加`, '#6f42c1');
            return;
        }
        return originalAddEventListener.call(this, type, listener, options);
    };

    ["visibilitychange", "blur", "focus", "focusin", "focusout"].forEach((e) => {
        originalAddEventListener.call(
            window,
            e,
            (event) => {
                event.stopImmediatePropagation();
                event.stopPropagation();
                event.preventDefault();
                return false;
            },
            true
        );
    });

    let isEnabled = true;
    let isUIVisible = false;
    let uiContainer = null;
    let uiMinimizedTag = null;
    let uiUpdateFunction = () => {};

    const stats = {
        visibilitychange: 0,
        blur: 0,
        focusout: 0,
        focusin: 0,
        pagehide: 0,
        pageshow: 0,
        proxy: 0,
        get total() {
            return this.visibilitychange + this.blur + this.focusout + this.focusin + this.pagehide + this.pageshow + this.proxy;
        }
    };

    const interceptLog = [];
    const MAX_LOG_ITEMS = 15;

    function addLog(type, message, color = '#dc3545') {
        const timestamp = new Date().toLocaleTimeString();
        interceptLog.unshift({ time: timestamp, type: type, message: message, color: color });
        if (interceptLog.length > MAX_LOG_ITEMS) {
            interceptLog.pop();
        }
        if (type === 'proxy') {
            stats.proxy++;
        }
        if (uiUpdateFunction) {
            uiUpdateFunction();
        }
    }

    try {
        document.hasFocus = () => true;
        Object.defineProperty(document, 'hidden', {
            get() { return false; },
            configurable: true
        });
        Object.defineProperty(document, 'visibilityState', {
            get: () => 'visible',
            configurable: true
        });
        if (!document.__hasFocusPatched) {
            document.hasFocus = function() { return true; };
            document.__hasFocusPatched = true;
        }
        addLog('system', '✓ 属性覆盖成功 (hasFocus/hidden/visibilityState)', '#28a745');
    } catch (e) {
        addLog('system', '❌ 属性覆盖失败: ' + e.message, '#dc3545');
    }

    const interceptOtherEvents = (e) => {
        if (!isEnabled) return;
        e.preventDefault();
        e.stopImmediatePropagation();
        e.stopPropagation();

        const eventType = e.type;
        if (stats.hasOwnProperty(eventType)) {
            stats[eventType]++;
            let logMessage = '';
            switch (eventType) {
                case 'visibilitychange':
                    logMessage = `📱 强力阻止 页面可见性检测`;
                    break;
                case 'pagehide':
                    logMessage = `📄 强力阻止 页面隐藏 (pagehide)`;
                    break;
                case 'pageshow':
                    logMessage = `📄 强力阻止 页面显示 (pageshow)`;
                    break;
                case 'focusin':
                    logMessage = `⚡ 强力阻止 焦点获得 (focusin)`;
                    break;
            }
            addLog(eventType, logMessage, '#28a745');
        }
    };

    try {
        ['visibilitychange', 'pagehide', 'pageshow', 'focusin'].forEach(eventType => {
            originalAddEventListener.call(window, eventType, interceptOtherEvents, true);
            originalAddEventListener.call(document, eventType, interceptOtherEvents, true);
        });
    } catch (e) {
         addLog('system', '❌ 监听器附加失败: ' + e.message, '#dc3545');
    }

    (function() {
        try {
            const originalObserve = MutationObserver.prototype.observe;
            MutationObserver.prototype.observe = function(target, options) {
                if (target === document || target === document.documentElement) {
                    addLog('system', '🛡️ 拦截 DOM 观察器', '#007bff');
                    return { disconnect: () => {}, observe: () => {}, unobserve: () => {} };
                }
                return originalObserve.apply(this, arguments);
            };
            const originalMutationObserver = window.MutationObserver;
            window.MutationObserver = function(callback) {
                const observer = new originalMutationObserver((mutations) => {
                    const filteredMutations = mutations.filter(mutation => {
                        return mutation.target !== document && mutation.target !== document.documentElement;
                    });
                    if (filteredMutations.length > 0) {
                        callback(filteredMutations);
                    }
                });
                return observer;
            };
            window.MutationObserver.prototype = originalMutationObserver.prototype;
        } catch (e) {
        }
    })();

    addLog('system', '✅ 切屏防护系统已启动', '#007bff');
    addLog('system', '📌 UI优化: 最小化标签尺寸缩小 + 模式颜色区分', '#17a2b8');


    const createUI = () => {
        if (window.top !== window.self) {
            return;
        }

        const completelyHideUI = () => {
            if (uiContainer && uiContainer.parentNode) {
                uiContainer.parentNode.removeChild(uiContainer);
                uiContainer = null;
            }
            if (uiMinimizedTag && uiMinimizedTag.parentNode) {
                uiMinimizedTag.parentNode.removeChild(uiMinimizedTag);
                uiMinimizedTag = null;
            }
            addLog('system', '👻 UI 已完全隐藏 (需刷新页面恢复)', '#6c757d');
        };

        // === 最小化标签 ===
        uiMinimizedTag = document.createElement('div');
        const uiTagTitle = document.createElement('span');
        const uiTagHideButton = document.createElement('span');

        uiTagTitle.textContent = '🛡️ 防护';
        uiTagHideButton.textContent = '❌';
        uiTagHideButton.title = '从页面中移除所有UI元素 (需刷新恢复)';

        uiMinimizedTag.appendChild(uiTagTitle);
        uiMinimizedTag.appendChild(uiTagHideButton);

        // 最小化标签样式
        Object.assign(uiMinimizedTag.style, {
            position: 'fixed',
            bottom: '20px',
            right: '20px',
            color: 'white',
            padding: '4px 8px',
            borderRadius: '15px',
            fontSize: '11px',
            fontFamily: 'sans-serif',
            cursor: 'pointer',
            zIndex: '999999',
            boxShadow: '0 2px 8px rgba(0, 0, 0, 0.2)',
            transition: 'all 0.3s ease',
            userSelect: 'none',
            display: 'flex',
            gap: '5px',
            alignItems: 'center',
            fontWeight: 'bold',
        });

        Object.assign(uiTagHideButton.style, {
            padding: '2px 4px',
            backgroundColor: 'rgba(255, 255, 255, 0.2)',
            borderRadius: '10px',
            cursor: 'pointer',
            fontSize: '10px',
            fontWeight: 'normal',
            lineHeight: '1'
        });

        const updateUIMinimizedTagBackground = () => {
            const enabledColor = 'rgba(0, 123, 255, 0.9)';
            const disabledColor = 'rgba(108, 117, 125, 0.9)';
            if (uiMinimizedTag) {
                uiMinimizedTag.style.backgroundColor = isEnabled ? enabledColor : disabledColor;
            }
        };


        uiTagTitle.addEventListener('click', (e) => {
            e.stopPropagation();
            isUIVisible = !isUIVisible;
            uiContainer.style.display = isUIVisible ? 'block' : 'none';
            uiMinimizedTag.style.display = isUIVisible ? 'none' : 'flex';
        });

        uiTagHideButton.addEventListener('click', (e) => {
            e.stopPropagation();
            completelyHideUI();
        });

        // === 主面板 ===
        uiContainer = document.createElement('div');
        const uiHeader = document.createElement('div');
        const uiTitle = document.createElement('span');
        const uiControls = document.createElement('div');
        const uiToggleButton = document.createElement('span');
        const uiMinimizeButton = document.createElement('span');
        const uiHideButton = document.createElement('span');
        const uiBody = document.createElement('div');
        const uiRealTimePanel = document.createElement('div');
        const uiRealTimeTitle = document.createElement('div');
        const uiFocusStatus = document.createElement('div');
        const uiVisibilityStatus = document.createElement('div');
        const uiLogPanel = document.createElement('div');
        const uiLogTitle = document.createElement('div');
        const uiLogContent = document.createElement('div');
        const uiStatsPanel = document.createElement('div');
        const uiStatsTitle = document.createElement('div');
        const uiStatsContent = document.createElement('div');
        const uiControlPanel = document.createElement('div');
        const uiStatus = document.createElement('div');
        const uiHotKey = document.createElement('div');

        uiHeader.appendChild(uiTitle);
        uiControls.appendChild(uiToggleButton);
        uiControls.appendChild(uiMinimizeButton);
        uiControls.appendChild(uiHideButton);
        uiHeader.appendChild(uiControls);
        uiRealTimePanel.appendChild(uiRealTimeTitle);
        uiRealTimePanel.appendChild(uiFocusStatus);
        uiRealTimePanel.appendChild(uiVisibilityStatus);
        uiLogPanel.appendChild(uiLogTitle);
        uiLogPanel.appendChild(uiLogContent);
        uiStatsPanel.appendChild(uiStatsTitle);
        uiStatsPanel.appendChild(uiStatsContent);
        uiControlPanel.appendChild(uiStatus);
        uiControlPanel.appendChild(uiHotKey);
        uiBody.appendChild(uiRealTimePanel);
        uiBody.appendChild(uiLogPanel);
        uiBody.appendChild(uiStatsPanel);
        uiBody.appendChild(uiControlPanel);
        uiContainer.appendChild(uiHeader);
        uiContainer.appendChild(uiBody);

        const appendUI = () => {
            if (document.body) {
                document.body.appendChild(uiContainer);
                document.body.appendChild(uiMinimizedTag);
                uiContainer.style.display = 'none';
                updateUIMinimizedTagBackground();
            }
        };

        if (document.body) {
            appendUI();
        } else {
            originalAddEventListener.call(document, 'DOMContentLoaded', appendUI);
        }

        uiTitle.textContent = "🛡️ 切屏防护";
        uiToggleButton.title = '点击切换 启用/禁用';
        uiMinimizeButton.textContent = '—';
        uiMinimizeButton.title = '点击最小化 (切换到右下角标签)';
        uiHideButton.textContent = '✕';
        uiHideButton.title = '完全隐藏 UI';

        const updateUI = () => {
            updateUIMinimizedTagBackground();

            uiRealTimeTitle.innerHTML = '<strong>📊 实时状态</strong>';
            uiFocusStatus.innerHTML = `🎯 焦点状态: <span style="color: #28a745; font-weight: bold;">✓ 强制聚焦</span>`;
            uiVisibilityStatus.innerHTML = `📱 页面可见: <span style="color: #28a745; font-weight: bold;">visible</span> | hidden: <span style="color: #28a745; font-weight: bold;">false</span>`;

            uiLogTitle.innerHTML = '<strong>📝 拦截日志</strong>';
            if (interceptLog.length === 0) {
                uiLogContent.innerHTML = '<div style="color: #6c757d; font-style: italic;">暂无拦截记录</div>';
            } else {
                uiLogContent.innerHTML = interceptLog.map(log => {
                    return `<div style="font-size: 11px; margin: 2px 0; padding: 2px 4px; background: rgba(0,0,0,0.03); border-radius: 3px;">
                        <span style="color: #888;">${log.time}</span> - <span style="color: ${log.color};">${log.message}</span>
                    </div>`;
                }).join('');
            }

            uiStatsTitle.innerHTML = '<strong>📈 拦截统计</strong>';
            uiStatsContent.innerHTML = `
                <div style="margin-top: 5px;">
                    <div style="color: #6f42c1;">🚫 代理拦截 (blur/focusout): <strong>${stats.proxy}</strong></div>
                    <div style="color: #dc3545;">📱 页面可见性 (vis/page): <strong>${stats.visibilitychange + stats.pagehide + stats.pageshow}</strong></div>
                    <div style="color: #20c997;">⚡ 焦点事件 (focusin): <strong>${stats.focusin}</strong></div>
                    <div style="margin-top: 5px; padding-top: 5px; border-top: 1px solid #eee; color: #28a745; font-weight: bold;">
                        总拦截次数: ${stats.total}
                    </div>
                </div>
            `;

            uiStatus.innerHTML = `<span style="color: ${isEnabled ? '#28a745' : '#6c757d'}; font-weight: bold;">🛡️ 防护: ${isEnabled ? '✓ 开启' : '✗ 关闭'}</span>`;
            uiToggleButton.textContent = isEnabled ? '🟢' : '🔴';
            uiHotKey.textContent = 'Ctrl+Alt+H 显示/最小化 | 点击拖动';
        };

        uiUpdateFunction = updateUI;
        updateUI();

        // --- 样式 (主面板) ---
        Object.assign(uiContainer.style, {
            position: 'fixed',
            bottom: '20px',
            right: '20px',
            top: 'auto',
            left: 'auto',
            width: '320px',
            backgroundColor: 'rgba(255, 255, 255, 0.97)',
            color: '#333',
            border: '1px solid #ccc',
            borderRadius: '8px',
            zIndex: '999999',
            fontFamily: 'sans-serif',
            fontSize: '12px',
            backdropFilter: 'blur(5px)',
            webkitBackdropFilter: 'blur(5px)',
            boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',
            transition: 'transform 0.3s ease',
            display: isUIVisible ? 'block' : 'none',
            fontWeight: '500'
        });

        Object.assign(uiHeader.style, {
            display: 'flex',
            justifyContent: 'space-between',
            alignItems: 'center',
            padding: '8px 12px',
            backgroundColor: 'rgba(0, 123, 255, 0.1)',
            cursor: 'move',
            userSelect: 'none',
            borderRadius: '8px 8px 0 0'
        });
        Object.assign(uiTitle.style, { fontWeight: 'bold', color: '#007bff' });
        Object.assign(uiControls.style, { display: 'flex', gap: '10px' });
        const buttonStyle = {
            cursor: 'pointer',
            fontWeight: 'bold',
            padding: '2px 8px',
            borderRadius: '4px',
            transition: 'background-color 0.2s'
        };
        Object.assign(uiToggleButton.style, buttonStyle);
        Object.assign(uiMinimizeButton.style, buttonStyle);
        Object.assign(uiHideButton.style, buttonStyle);
        Object.assign(uiBody.style, { padding: '10px 12px', maxHeight: '70vh', overflowY: 'auto' });
        const panelStyle = { marginBottom: '12px', padding: '8px', backgroundColor: 'rgba(0, 0, 0, 0.02)', borderRadius: '6px', border: '1px solid rgba(0, 0, 0, 0.05)' };
        Object.assign(uiRealTimePanel.style, panelStyle);
        Object.assign(uiLogPanel.style, panelStyle);
        Object.assign(uiStatsPanel.style, panelStyle);
        Object.assign(uiControlPanel.style, panelStyle);
        const titleStyle = { marginBottom: '6px', color: '#495057', fontSize: '12px' };
        Object.assign(uiRealTimeTitle.style, titleStyle);
        Object.assign(uiLogTitle.style, titleStyle);
        Object.assign(uiStatsTitle.style, titleStyle);
        Object.assign(uiFocusStatus.style, { margin: '4px 0', fontSize: '11px' });
        Object.assign(uiVisibilityStatus.style, { margin: '4px 0', fontSize: '11px' });
        Object.assign(uiLogContent.style, { maxHeight: '120px', overflowY: 'auto' });
        Object.assign(uiStatsContent.style, { lineHeight: '1.6' });
        Object.assign(uiStatus.style, { marginBottom: '6px', fontSize: '13px' });
        Object.assign(uiHotKey.style, { color: '#888', fontSize: '10px', textAlign: 'center' });

        // --- UI 交互 ---
        uiToggleButton.addEventListener('click', (e) => {
            e.stopPropagation();
            isEnabled = !isEnabled;
            addLog('system', isEnabled ? '✅ 防护已开启' : '❌ 防护已关闭', isEnabled ? '#28a745' : '#6c757d');
            updateUI();
        });

        uiMinimizeButton.addEventListener('click', (e) => {
            e.stopPropagation();
            isUIVisible = false;
            uiContainer.style.display = 'none';
            uiMinimizedTag.style.display = 'flex';
            addLog('system', '📌 已最小化到右下角标签', '#17a2b8');
        });

        uiHideButton.addEventListener('click', (e) => {
            e.stopPropagation();
            completelyHideUI();
        });

        let isDragging = false;
        let offset = { x: 0, y: 0 };
        uiHeader.addEventListener('mousedown', (e) => {
            isDragging = true;
            offset.x = e.clientX - uiContainer.getBoundingClientRect().left;
            offset.y = e.clientY - uiContainer.getBoundingClientRect().top;
            uiHeader.style.cursor = 'grabbing';
            document.body.style.userSelect = 'none';
        });
        window.addEventListener('mousemove', (e) => {
            if (!isDragging) return;
            let newX = e.clientX - offset.x;
            newX = Math.max(0, Math.min(newX, window.innerWidth - uiContainer.offsetWidth));
            let newRight = window.innerWidth - (newX + uiContainer.offsetWidth);
            newRight = Math.max(0, newRight);

            Object.assign(uiContainer.style, {
                left: 'auto',
                right: `${newRight}px`,
                bottom: '20px',
                top: 'auto',
            });
        });
        window.addEventListener('mouseup', () => {
            if (!isDragging) return;
            isDragging = false;
            uiHeader.style.cursor = 'move';
            document.body.style.userSelect = 'auto';
        });
    };

    originalAddEventListener.call(window, 'keydown', (e) => {
        if (e.key.toLowerCase() === 'h' && e.ctrlKey && e.altKey && !e.shiftKey) {
            e.preventDefault();
            e.stopPropagation();
            isUIVisible = !isUIVisible;
            if (uiContainer) {
                uiContainer.style.display = isUIVisible ? 'block' : 'none';
                if (uiMinimizedTag) {
                    uiMinimizedTag.style.display = isUIVisible ? 'none' : 'flex';
                }
            }
        }
    }, true);

    if (document.readyState === 'loading') {
        originalAddEventListener.call(window, 'DOMContentLoaded', createUI);
    } else {
        createUI();
    }

})();