ffactory / Block Google Docs keyboard shortcuts (ALT / OPTION)

// ==UserScript==
// @name         Block Google Docs keyboard shortcuts (ALT / OPTION)
// @namespace    http://tampermonkey.net/
// @version      2024-11-07
// @description  Prevents Google Docs from receiving shortcuts like ALT+1 or Option+/
// @author       ffactory
// @match        https://docs.google.com/*edit*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=google.com
// @run-at       dpcument-start
// @grant        none
// @updateURL    https://openuserjs.org/meta/ffactory/Block_Google_Docs_keyboard_shortcuts_(ALT_OPTION).meta.js
// @downloadURL  https://openuserjs.org/install/ffactory/Block_Google_Docs_keyboard_shortcuts_(ALT_OPTION).user.js
// @copyright    2024, ffactory (https://openuserjs.org/users/ffactory)
// @license      MIT
// ==/UserScript==

(function () {
  'use strict';

  function addEventListener(doc) {
    console.log("Suppressing keyboard shortcuts on element");

    // Add the keydown listener to the document
    doc.addEventListener(
      'keydown',
      function (event) {
        if (event.altKey) {
          console.log("Suppressed keyboard shortcut:", event.key);
          event.stopImmediatePropagation();
        }
      },
      true // Run during capturing phase to intercept the event before bubbling phase
    );
  }

  // Option 1: Google sheets listens for keyboard events on the `window`
  addEventListener(window);

  // Option 2: Google docs and slides listen for keyboard events using an iframe

  // Check if the iframe already exists
  const targetIframe = document.querySelector('iframe.docs-texteventtarget-iframe');
  if (targetIframe) {
    const iframeDoc = targetIframe.contentDocument || targetIframe.contentWindow.document;
    addEventListener(iframeDoc);

  }
  else {
    console.log("Keypress target iframe NOT YET detected. Will wait until it's added");

    const timeoutId = window.setTimeout(function () {
      console.error("Keypress target iframe not found! Maybe Google's initialization has changed, check the script.");
    }, 2000);

    // Set up a MutationObserver to monitor future changes
    const observer = new MutationObserver(function (mutationsList) {
      for (const mutation of mutationsList) {
        for (const addedNode of mutation.addedNodes) {
          // Check if the added node is the target iframe
          if (addedNode.tagName && addedNode.tagName.toLowerCase() === 'iframe' && addedNode.classList.contains('docs-texteventtarget-iframe')) {
            const iframeDoc = addedNode.contentDocument || addedNode.contentWindow.document;
            addEventListener(iframeDoc);
            window.clearTimeout(timeoutId);
            observer.disconnect(); // Stop observing once the target iframe is found
            return;
          }
        }
      }
    });

    // Observe the document for added iframes
    observer.observe(document.body, {
      childList: true,
      subtree: true
    });
  }
})();