Greasy Fork

Greasy Fork is available in English.

左键限制解除

左键选中

当前为 2025-02-13 提交的版本,查看 最新版本

// ==UserScript==
// @name              左键限制解除
// @description       左键选中
// @version           1.1
// @match             *://*/*
// @run-at            document-start
// @grant             none
// @namespace http://greasyfork.icu/users/12375
// ==/UserScript==

(function() {
  'use strict';

  // 默认规则配置
  var rule = {
    name: "default",
    hook_eventNames: "contextmenu|select|selectstart|copy|cut|dragstart",
    unhook_eventNames: "keydown|keyup",
    dom0: true,
    hook_addEventListener: true,
    hook_preventDefault: true,
    hook_set_returnValue: true
  };

  // 要处理的 event 列表
  var hook_eventNames, unhook_eventNames, eventNames;
  // 储存名称
  var storageName = getRandStr('qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM', parseInt(Math.random() * 12 + 8));
  // 储存被 Hook 的函数
  var EventTarget_addEventListener = EventTarget.prototype.addEventListener;
  var document_addEventListener = document.addEventListener;
  var Event_preventDefault = Event.prototype.preventDefault;

  // 清理循环
  function clearLoop() {
    var elements = getElements();

    for(var i in elements) {
      for(var j in eventNames) {
        var name = 'on' + eventNames[j];
        if(elements[i][name] !== null && elements[i][name] !== onxxx) {
          if(unhook_eventNames.indexOf(eventNames[j]) >= 0) {
            elements[i][storageName + name] = elements[i][name];
            elements[i][name] = onxxx;
          } else {
            elements[i][name] = null;
          }
        }
      }
    }
  }

  // 返回true的函数
  function returnTrue(e) {
    return true;
  }
  function unhook_t(e) {
    return unhook(e, this, storageName + e.type + 't');
  }
  function unhook_f(e) {
    return unhook(e, this, storageName + e.type + 'f');
  }
  function unhook(e, self, funcsName) {
    var list = self[funcsName];
    for(var i in list) {
      list[i](e);
    }
    e.returnValue = true;
    return true;
  }
  function onxxx(e) {
    var name = storageName + 'on' + e.type;
    this[name](e);
    e.returnValue = true;
    return true;
  }

  // 获取随机字符串
  function getRandStr(chs, len) {
    var str = '';

    while(len--) {
      str += chs[parseInt(Math.random() * chs.length)];
    }
    return str;
  }

  // 获取所有元素 包括document
  function getElements() {
    var elements = Array.prototype.slice.call(document.getElementsByTagName('*'));
    elements.push(document);
    return elements;
  }

  // 初始化
  function init() {

    // hook addEventListener
    if(rule.hook_addEventListener) {
      EventTarget.prototype.addEventListener = addEventListener;
      document.addEventListener = addEventListener;
    }

  }
  init();

  // 视频控制保护逻辑
  const EV = {
    select: 1, selectstart: 2, copy: 4, cut: 8, contextmenu: 16,
    mousedown: 32, mouseup: 64, mousemove: 128, click: 256
  };

  const videoElements = new WeakMap();
  const isVideoControl = (target) => {
    while(target) {
      if(videoElements.has(target)) return videoElements.get(target);
      if(target.tagName === 'VIDEO' ||
         target.classList.contains('progress-bar') ||
         target.closest('video, [role="video-controls"]')) {
        videoElements.set(target, true);
        return true;
      }
      target = target.parentElement;
    }
    return false;
  };

  const { addEventListener: protoAdd } = EventTarget.prototype;
  const { preventDefault: protoPrevent } = Event.prototype;

  EventTarget.prototype.addEventListener = function(type, listener, options) {
    const eventFlag = EV[type] || 0;
    if(eventFlag & 0b00011111 && !isVideoControl(this)) {
      protoAdd.call(this, type, e => e.stopImmediatePropagation(), { capture: true, ...options });
    } else {
      protoAdd.call(this, type, listener, options);
    }
  };

})();