- // ==UserScript==
- // @name Pause Mouse Movement for Website
- // @namespace http://tampermonkey.net/
- // @version 1.0
- // @description Allows toggling pause on website's mousemove listeners, while local cursor still moves.
- // @author Your Name Here
- // @match *://*/*
- // @grant none
- // @run-at document-start
- // @license MIT
- // ==/UserScript==
-
- (function() {
- 'use strict';
-
- // --- Configuration ---
- const TOGGLE_KEY = 'm'; // Key to press for toggling
- const REQUIRE_CTRL = true; // Require Ctrl key?
- const REQUIRE_ALT = true; // Require Alt key?
- const REQUIRE_SHIFT = false; // Require Shift key?
- // --- End Configuration ---
-
- let isPaused = false; // Initial state: website mouse movement is NOT paused
- const listenerMap = new Map(); // Stores mapping: originalListener -> wrappedListener
- let statusIndicator = null; // Reference to the status indicator element
-
- console.log("Pause Mouse Movement Script: Initializing.");
-
- // --- Status Indicator ---
- function createStatusIndicator() {
- const indicator = document.createElement('div');
- indicator.style.position = 'fixed';
- indicator.style.bottom = '10px';
- indicator.style.right = '10px';
- indicator.style.padding = '5px 10px';
- indicator.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
- indicator.style.color = 'white';
- indicator.style.fontSize = '12px';
- indicator.style.borderRadius = '3px';
- indicator.style.zIndex = '99999'; // Ensure it's on top
- indicator.style.fontFamily = 'sans-serif';
- indicator.style.pointerEvents = 'none'; // Don't let it interfere with mouse events
- document.body.appendChild(indicator);
- return indicator;
- }
-
- function updateStatusIndicator() {
- if (!statusIndicator && document.body) {
- statusIndicator = createStatusIndicator();
- }
- if (statusIndicator) {
- statusIndicator.textContent = `Website Mouse: ${isPaused ? 'Paused' : 'Active'} (Toggle: ${REQUIRE_CTRL ? 'Ctrl+' : ''}${REQUIRE_ALT ? 'Alt+' : ''}${REQUIRE_SHIFT ? 'Shift+' : ''}${TOGGLE_KEY.toUpperCase()})`;
- statusIndicator.style.backgroundColor = isPaused ? 'rgba(255, 0, 0, 0.7)' : 'rgba(0, 128, 0, 0.7)'; // Red when paused, Green when active
- }
- }
-
- // --- Toggle Function ---
- function togglePause() {
- isPaused = !isPaused;
- console.log(`Pause Mouse Movement Script: Website mousemove listeners ${isPaused ? 'paused' : 'activated'}.`);
- updateStatusIndicator();
- }
-
- // --- Keyboard Shortcut Listener ---
- document.addEventListener('keydown', (event) => {
- // Check if the pressed key and modifiers match the configuration
- if (event.key.toLowerCase() === TOGGLE_KEY.toLowerCase() &&
- event.ctrlKey === REQUIRE_CTRL &&
- event.altKey === REQUIRE_ALT &&
- event.shiftKey === REQUIRE_SHIFT)
- {
- // Prevent default action if the key combination might have one
- event.preventDefault();
- event.stopPropagation();
- togglePause();
- }
- }, true); // Use capture phase to catch before page scripts
-
- // --- Intercept addEventListener ---
- const originalAddEventListener = EventTarget.prototype.addEventListener;
- EventTarget.prototype.addEventListener = function(type, listener, options) {
- if (type === 'mousemove' && typeof listener === 'function') {
- // Only wrap mousemove listeners
- if (!listenerMap.has(listener)) {
- const wrappedListener = function(...args) {
- if (!isPaused) {
- // If not paused, call the original listener
- // Use Reflect.apply to correctly handle 'this' context and arguments
- try {
- Reflect.apply(listener, this, args);
- } catch (e) {
- console.error("Error executing original mousemove listener:", e);
- }
- }
- // If paused, do nothing, effectively blocking the listener
- };
- listenerMap.set(listener, wrappedListener);
- // Add the wrapped listener instead of the original
- originalAddEventListener.call(this, type, wrappedListener, options);
- // console.log("Wrapped mousemove listener added for:", this);
- } else {
- // Listener already wrapped, potentially re-adding? Call original to ensure browser handles it correctly.
- originalAddEventListener.call(this, type, listenerMap.get(listener), options);
- }
- } else {
- // For all other event types, call the original function directly
- originalAddEventListener.call(this, type, listener, options);
- }
- };
-
- // --- Intercept removeEventListener ---
- const originalRemoveEventListener = EventTarget.prototype.removeEventListener;
- EventTarget.prototype.removeEventListener = function(type, listener, options) {
- if (type === 'mousemove' && typeof listener === 'function') {
- // If it's a mousemove listener, try to remove the wrapped version
- const wrappedListener = listenerMap.get(listener);
- if (wrappedListener) {
- // Remove the wrapped listener
- originalRemoveEventListener.call(this, type, wrappedListener, options);
- listenerMap.delete(listener); // Clean up the map
- // console.log("Wrapped mousemove listener removed for:", this);
- } else {
- // If no wrapper found (maybe added before script ran?), try removing original anyway
- originalRemoveEventListener.call(this, type, listener, options);
- }
- } else {
- // For all other event types, call the original function directly
- originalRemoveEventListener.call(this, type, listener, options);
- }
- };
-
- console.log("Pause Mouse Movement Script: Event listener interception active.");
-
- // Update status indicator once the body is available
- if (document.readyState === 'loading') {
- document.addEventListener('DOMContentLoaded', updateStatusIndicator);
- } else {
- // DOMContentLoaded has already fired
- updateStatusIndicator();
- }
-
- })();