您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
解决在输入法状态下按Enter键导致消息直接发送的问题;Solve the problem that pressing the Enter key in the input method state causes the message to be sent directly.
// ==UserScript== // @name 阻止claude输入发送 // @description 解决在输入法状态下按Enter键导致消息直接发送的问题;Solve the problem that pressing the Enter key in the input method state causes the message to be sent directly. // @match https://claude.ai/* // @author sinoftj // @version 2.0 // @namespace https://greasyfork.org/users/1457414 // ==/UserScript== (function() { 'use strict'; // 输入法状态追踪 let imeActive = false; let lastImeEndTime = 0; const IME_BUFFER_TIME = 5; // 输入法结束后的缓冲时间(毫秒) // 检查是否处于输入法状态 function isInImeContext(e) { return imeActive || e.isComposing || e.keyCode === 229 || (Date.now() - lastImeEndTime < IME_BUFFER_TIME); } // 处理输入法事件 document.addEventListener('compositionstart', function() { imeActive = true; }, true); document.addEventListener('compositionend', function() { lastImeEndTime = Date.now(); setTimeout(() => { imeActive = false; }, IME_BUFFER_TIME); }, true); // 拦截Enter键事件 - 捕获阶段 document.addEventListener('keydown', function(e) { if ((e.key === 'Enter' || e.keyCode === 13) && isInImeContext(e)) { e.stopImmediatePropagation(); e.preventDefault(); return false; } }, true); // 备份保护:keypress事件拦截 document.addEventListener('keypress', function(e) { if ((e.key === 'Enter' || e.keyCode === 13) && isInImeContext(e)) { e.stopImmediatePropagation(); e.preventDefault(); return false; } }, true); // 处理标准输入框元素 function protectInputElement(input) { const originalKeyDown = input.onkeydown; input.onkeydown = function(e) { if ((e.key === 'Enter' || e.keyCode === 13) && isInImeContext(e)) { e.stopPropagation(); e.preventDefault(); return false; } if (originalKeyDown) return originalKeyDown.call(this, e); }; } // 处理contenteditable元素(特别是富文本编辑器) function protectContentEditableElement(element) { // 为contenteditable元素添加直接事件监听 element.addEventListener('keydown', function(e) { if ((e.key === 'Enter' || e.keyCode === 13) && isInImeContext(e)) { e.stopPropagation(); e.preventDefault(); return false; } }, true); // 使用捕获模式,确保在事件被其他处理器捕获前拦截 // 查找并处理可能嵌套的ProseMirror编辑器 const proseMirrors = element.querySelectorAll('.ProseMirror'); if (proseMirrors.length > 0) { proseMirrors.forEach(editor => { editor.addEventListener('keydown', function(e) { if ((e.key === 'Enter' || e.keyCode === 13) && isInImeContext(e)) { e.stopPropagation(); e.preventDefault(); return false; } }, true); }); } } // 处理所有可能的编辑元素 function protectElement(element) { if (!element) return; if (element.tagName === 'TEXTAREA' || (element.tagName === 'INPUT' && element.type === 'text')) { protectInputElement(element); } else if (element.getAttribute('contenteditable') === 'true') { protectContentEditableElement(element); } // 特殊处理ProseMirror编辑器 else if (element.classList && element.classList.contains('ProseMirror')) { protectContentEditableElement(element); } } // 直接监听iframe中的事件(如果有) function setupIframeProtection() { try { const iframes = document.querySelectorAll('iframe'); iframes.forEach(iframe => { try { if (iframe.contentDocument) { iframe.contentDocument.addEventListener('keydown', function(e) { if ((e.key === 'Enter' || e.keyCode === 13) && isInImeContext(e)) { e.stopPropagation(); e.preventDefault(); return false; } }, true); iframe.contentDocument.addEventListener('compositionstart', function() { imeActive = true; }, true); iframe.contentDocument.addEventListener('compositionend', function() { lastImeEndTime = Date.now(); setTimeout(() => { imeActive = false; }, IME_BUFFER_TIME); }, true); } } catch (err) { // 跨域iframe访问可能会失败,忽略错误 } }); } catch (err) { console.error('处理iframe时出错:', err); } } // 页面加载后处理现有输入元素 function initializeProtection() { // 保护标准输入元素 document.querySelectorAll('textarea, input[type="text"]').forEach(protectInputElement); // 保护contenteditable元素 document.querySelectorAll('[contenteditable="true"]').forEach(protectContentEditableElement); // 特别处理ProseMirror编辑器 document.querySelectorAll('.ProseMirror').forEach(protectContentEditableElement); // 设置iframe保护 setupIframeProtection(); // 监控DOM变化,处理新添加的输入元素 if (window.MutationObserver) { const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if (mutation.addedNodes && mutation.addedNodes.length > 0) { mutation.addedNodes.forEach((node) => { if (node.nodeType === 1) { // 元素节点 protectElement(node); // 处理节点内的所有可能输入元素 if (node.querySelectorAll) { const inputs = node.querySelectorAll('textarea, input[type="text"], [contenteditable="true"], .ProseMirror'); if (inputs.length > 0) { inputs.forEach(input => protectElement(input)); } } } }); } // 特别检查属性变化,以防contenteditable状态变化 if (mutation.type === 'attributes' && mutation.attributeName === 'contenteditable' && mutation.target.getAttribute('contenteditable') === 'true') { protectContentEditableElement(mutation.target); } }); // 检查是否有新的iframe添加 setupIframeProtection(); }); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['contenteditable'] }); } } // 确保在DOM完全加载后执行,并给予足够时间加载任何动态内容 if (document.readyState === 'loading') { window.addEventListener('DOMContentLoaded', () => setTimeout(initializeProtection, 1000)); } else { setTimeout(initializeProtection, 1000); } // 监听动态加载的页面部分,比如单页应用的视图变化 window.addEventListener('load', () => setTimeout(initializeProtection, 1500)); // 监听可能的路由变化(用于SPA应用) window.addEventListener('popstate', () => setTimeout(initializeProtection, 500)); document.addEventListener('visibilitychange', () => { if (!document.hidden) setTimeout(initializeProtection, 500); }); // 初次执行,尽快保护可能存在的元素 setTimeout(initializeProtection, 300); })();