EnterIt

Support Enter for new line and Ctrl+Enter to send in various AI assistant web input boxes

< Părere la script-ul EnterIt

Recenzie: Bun, script-ul merge

§
Postat în: 01-03-2026

豆包有bug,无论是按enter还是按Ctrl+Enter键都无法正常输入,现在我把修改后的版本发在这里

// ==UserScript==
// @name               EnterIt-FixForDoubao
// @name:zh-CN         EnterIt-修复版
// @namespace          http://tampermonkey.net/
// @version            1.2.3
// @description        支持在各种 AI 助手网页端输入框按回车换行,Ctrl+回车发送。修复豆包无法发送的问题。
// @author             Clover Yan & AI Fix
// @match              https://chatgpt.com/*
// @match              https://claude.ai/*
// @match              https://gemini.google.com/*
// @match              https://www.perplexity.ai/*
// @match              https://chat.deepseek.com/*
// @match              https://grok.com/*
// @match              https://github.com/*
// @match              https://notebooklm.google.com/*
// @match              https://www.phind.com/*
// @match              https://poe.com/*
// @match              https://chat.mistral.ai/*
// @match              https://you.com/*
// @match              https://v0.dev/*
// @match              https://copilot.microsoft.com/*
// @match              https://m365.cloud.microsoft/*
// @match              https://yuanbao.tencent.com/*
// @match              https://www.doubao.com/*
// @match              https://www.qianwen.com/*
// @match              https://chat.qwen.ai/*
// @match              https://yiyan.baidu.com/*
// @icon               https://www.khyan.top/favicon.png
// @grant              none
// @run-at             document-start
// @license            AGPL-3.0-or-later
// ==/UserScript==

(function () {
    "use strict";

    function replaceAll(str, search, replace) {
        return str.split(search).join(replace);
    }

    // 核心修改:处理普通的 TEXTAREA 输入框(如豆包、通义千问等)
    function handleTextarea(event) {
        if (event.target.tagName !== "TEXTAREA" || !event.isTrusted) {
            return false;
        }

        const isOnlyEnter = event.key === "Enter" && !(event.ctrlKey || event.metaKey || event.shiftKey);
        const isCtrlEnter = event.key === "Enter" && (event.ctrlKey || event.metaKey);

        if (isOnlyEnter) {
            // 拦截 Enter,阻止发送,让系统默认换行
            event.stopPropagation();
            return true;
        } else if (isCtrlEnter) {
            // 拦截 Ctrl+Enter,模拟发送一个纯 Enter 事件来触发网页的发送动作
            event.preventDefault();
            event.stopImmediatePropagation();

            const newEvent = new KeyboardEvent("keydown", {
                key: "Enter",
                code: "Enter",
                keyCode: 13,
                which: 13,
                bubbles: true,
                cancelable: true,
                ctrlKey: false,
                metaKey: false,
                shiftKey: false,
            });
            event.target.dispatchEvent(newEvent);
            return true;
        }

        return false;
    }

    // 处理 ChatGPT 特殊逻辑
    function handleChatGPT(event) {
        const isOnlyEnter = event.key === "Enter" && !(event.ctrlKey || event.metaKey);
        const isCtrlEnter = event.key === "Enter" && event.ctrlKey;
        const isPromptTextarea = event.target.id === "prompt-textarea";

        if (!event.isTrusted) return false;

        if (isPromptTextarea && isOnlyEnter) {
            event.preventDefault();
            const newEvent = new KeyboardEvent("keydown", {
                key: "Enter", code: "Enter", bubbles: true, cancelable: true, ctrlKey: false, metaKey: false, shiftKey: true,
            });
            event.target.dispatchEvent(newEvent);
            return true;
        } else if (isPromptTextarea && isCtrlEnter) {
            event.preventDefault();
            const newEvent = new KeyboardEvent("keydown", {
                key: "Enter", code: "Enter", bubbles: true, cancelable: true, ctrlKey: false, metaKey: false, shiftKey: false,
            });
            event.target.dispatchEvent(newEvent);
            return true;
        }
        return false;
    }

    // 其余各类自定义输入框处理函数 (保持原样)
    function shouldHandleCtrlEnter(url, event) {
        if (url.startsWith("https://claude.ai")) return (event.target.tagName === "DIV" && event.target.contentEditable === "true") || event.target.tagName === "TEXTAREA";
        if (url.startsWith("https://notebooklm.google.com")) return event.target.tagName === "TEXTAREA" && event.target.classList.contains("query-box-input");
        if (url.startsWith("https://gemini.google.com")) return ((event.target.tagName === "DIV" && event.target.classList.contains("ql-editor") && event.target.contentEditable === "true") || event.target.tagName === "TEXTAREA") && !(event.shiftKey && event.key === "Enter");
        if (url.startsWith("https://www.phind.com")) return event.target.tagName === "DIV" && event.target.classList.contains("public-DraftEditor-content") && event.target.contentEditable === "true";
        if (url.startsWith("https://chat.deepseek.com")) return event.target.tagName === "TEXTAREA";
        if (url.startsWith("https://grok.com")) return event.target.tagName === "TEXTAREA" || (event.target.tagName === "DIV" && event.target.contentEditable === "true");
        if (url.startsWith("https://github.com")) return event.target.getAttribute("placeholder") === "Ask Copilot" || event.target.getAttribute("placeholder") === "Ask anything" || event.target.getAttribute("id") === "copilot-chat-textarea";
        if (url.startsWith("https://m365.cloud.microsoft/chat")) return event.target.id === "m365-chat-editor-target-element";
        if (url.startsWith("https://www.perplexity.ai")) return event.target.tagName === "DIV" && event.target.contentEditable === "true" && event.target.id === "ask-input";
        if (url.startsWith("https://yuanbao.tencent.com")) return event.target.tagName === "DIV" && event.target.classList.contains("ql-editor") && event.target.contentEditable === "true";
        if (url.startsWith("https://yiyan.baidu.com")) return event.target.tagName === "DIV" && event.target.getAttribute("role") === "textbox" && event.target.contentEditable === "true";
        return false;
    }

    function handleCustomInputs(event) {
        const url = window.location.href;
        if (event.isComposing || !shouldHandleCtrlEnter(url, event) || !event.isTrusted) return false;

        const isOnlyEnter = event.key === "Enter" && !(event.ctrlKey || event.metaKey);
        const isCtrlEnter = event.key === "Enter" && (event.ctrlKey || event.metaKey);

        if (isOnlyEnter || isCtrlEnter) {
            const preventDefaultSites = ["https://claude.ai", "https://www.phind.com", "https://www.perplexity.ai", "https://yuanbao.tencent.com"];
            if (preventDefaultSites.some((site) => url.startsWith(site))) event.preventDefault();

            event.stopImmediatePropagation();

            let eventConfig = { key: "Enter", code: "Enter", bubbles: true, cancelable: true, shiftKey: isOnlyEnter };
            if (url.startsWith("https://www.phind.com") || url.startsWith("https://chat.deepseek.com") || url.startsWith("https://yiyan.baidu.com")) eventConfig.keyCode = 13;

            const newEvent = new KeyboardEvent("keydown", eventConfig);
            event.target.dispatchEvent(newEvent);
            return true;
        }
        return false;
    }

    function handleKeyDown(event) {
        const url = window.location.href;
        if (url.startsWith("https://chatgpt.com")) {
            if (handleChatGPT(event)) return;
        } else if (
            url.startsWith("https://poe.com") ||
            url.startsWith("https://chat.mistral.ai") ||
            url.startsWith("https://you.com") ||
            url.startsWith("https://v0.dev") ||
            url.startsWith("https://copilot.microsoft.com") ||
            url.startsWith("https://www.doubao.com") ||
            url.startsWith("https://www.qianwen.com") ||
            url.startsWith("https://chat.qwen.ai")
        ) {
            if (handleTextarea(event)) return;
        } else {
            if (handleCustomInputs(event)) return;
        }
    }

    // 辅助功能:修改输入框的提示文字(让效果更直观)
    function fixPlaceholder(config) {
        const editor = document.querySelector(config.selector);
        if (!editor) return;
        const attr = config.attribute;
        const placeholder = attr ? editor.getAttribute(attr) : editor.placeholder;
        if (placeholder && placeholder.includes(config.searchString)) {
            const newText = replaceAll(placeholder, config.searchString, config.replaceString);
            if (attr) editor.setAttribute(attr, newText); else editor.placeholder = newText;
        }
    }

    function observePlaceholder() {
        const url = window.location.href;
        const configs = [
            ["https://www.doubao.com", { selector: 'textarea', attribute: null, searchString: "Enter 发送", replaceString: "Enter 换行,Ctrl+Enter 发送" }],
            ["https://yuanbao.tencent.com", { selector: '.ql-editor', attribute: "data-placeholder", searchString: "shift+enter换行", replaceString: "Enter 换行,Ctrl+Enter 发送" }],
            ["https://yiyan.baidu.com", { selector: 'span[data-slate-placeholder="true"]', attribute: null, searchString: "通过shift+回车换行", replaceString: "Enter换行,Ctrl+Enter发送" }]
        ];
        const config = configs.find(([site]) => url.startsWith(site))?.[1];
        if (!config) return;

        const observer = new MutationObserver(() => fixPlaceholder(config));
        observer.observe(document.body, { childList: true, subtree: true, attributes: true });
        fixPlaceholder(config);
    }

    document.addEventListener("keydown", handleKeyDown, { capture: true });
    if (document.readyState === "loading") {
        document.addEventListener("DOMContentLoaded", observePlaceholder);
    } else {
        observePlaceholder();
    }
    console.log("✅ EnterIt 已加载并修复豆包适配");
})();

Postează un raspuns

Autentifică-te pentru a posta un răspuns.