Greasy Fork is available in English.
移除网页对复制、粘贴、右键、选中、切屏检测(onblur / visibilitychange)的限制,支持 iframe 与 Shadow DOM 深层拦截。
// ==UserScript==
// @name 解锁网页复制/粘贴/右键/切屏限制💉
// @namespace http://greasyfork.icu/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
// ==/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();
}
})();