Prevent Tab Focus Detection

Prevent websites from detecting tab focus without breaking functionality

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name        Prevent Tab Focus Detection
// @description Prevent websites from detecting tab focus without breaking functionality
// @version     2026.02.12
// @author      Claude Sonnet 4.5
// @grant       none
// @inject-into auto
// @run-at      document-start
// @match       *://*/*
// @namespace https://greasyfork.org/users/1519047
// ==/UserScript==

(function() {
    'use strict';

    // Store original functions
    const originalGetters = {};
    const originalMethods = {};

    // Override document visibility properties
    const overrideProperty = (obj, prop, fakeValue) => {
        const descriptor = Object.getOwnPropertyDescriptor(obj, prop);
        if (descriptor && descriptor.get) {
            originalGetters[prop] = descriptor.get;
        }

        try {
            Object.defineProperty(obj, prop, {
                configurable: true,
                enumerable: true,
                get: function() {
                    return fakeValue;
                }
            });
        } catch(e) {
            console.debug('Tab focus prevention: Failed to override', prop, e);
        }
    };

    // Override all Page Visibility API properties (including vendor prefixes)
    overrideProperty(document, 'hidden', false);
    overrideProperty(document, 'visibilityState', 'visible');
    overrideProperty(document, 'webkitHidden', false);
    overrideProperty(document, 'webkitVisibilityState', 'visible');
    overrideProperty(document, 'mozHidden', false);
    overrideProperty(document, 'mozVisibilityState', 'visible');
    overrideProperty(document, 'msHidden', false);
    overrideProperty(document, 'msVisibilityState', 'visible');

    // Override hasFocus methods to always return true
    if (document.hasFocus) {
        originalMethods.documentHasFocus = document.hasFocus;
        document.hasFocus = function() {
            return true;
        };
    }

    if (window.hasFocus) {
        originalMethods.windowHasFocus = window.hasFocus;
        window.hasFocus = function() {
            return true;
        };
    }

    // Intercept visibility change events
    const interceptEvent = (e) => {
        e.stopImmediatePropagation();
    };

    // Only intercept Page Visibility API events (safest approach)
    const eventsToIntercept = [
        'visibilitychange',
        'webkitvisibilitychange',
        'mozvisibilitychange',
        'msvisibilitychange'
    ];

    eventsToIntercept.forEach(eventType => {
        window.addEventListener(eventType, interceptEvent, true);
        document.addEventListener(eventType, interceptEvent, true);
    });

    console.debug('Tab focus detection prevention active');
})();