EnterIt

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

2026-02-05 기준 버전입니다. 최신 버전을 확인하세요.

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name               EnterIt
// @name:zh-CN         EnterIt
// @name:zh-TW         EnterIt
// @namespace          http://tampermonkey.net/
// @version            1.2.0
// @description        Support Enter for new line and Ctrl+Enter to send in various AI assistant web input boxes
// @description:zh-CN  支持在各种 AI 助手网页端输入框按回车换行,Ctrl+回车发送
// @description:zh-TW  支援在各種 AI 助手網頁端輸入框,以 Enter 譜寫換行的詩篇,以 Ctrl+Enter 傳送命運的覺悟。
// @author             Clover Yan
// @homepage           https://www.khyan.top/
// @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            AGPLv3
// ==/UserScript==

(function () {
	"use strict";

	function handleChatGPT(event) {
		const isOnlyEnter =
			event.code === "Enter" && !(event.ctrlKey || event.metaKey);
		const isCtrlEnter = event.code === "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: true,
				shiftKey: false,
			});
			event.target.dispatchEvent(newEvent);
			return true;
		} else if (event.target.tagName === "TEXTAREA" && isCtrlEnter) {
			event.preventDefault();
			const newEvent = new KeyboardEvent("keydown", {
				key: "Enter",
				code: "Enter",
				bubbles: true,
				cancelable: true,
				ctrlKey: false,
				metaKey: true,
				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"
			);
		} else if (url.startsWith("https://notebooklm.google.com")) {
			return (
				event.target.tagName === "TEXTAREA" &&
				event.target.classList.contains("query-box-input")
			);
		} else 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.code === "Enter")
			);
		} else if (url.startsWith("https://www.phind.com")) {
			return (
				event.target.tagName === "DIV" &&
				event.target.classList.contains("public-DraftEditor-content") &&
				event.target.contentEditable === "true"
			);
		} else if (url.startsWith("https://chat.deepseek.com")) {
			return event.target.tagName === "TEXTAREA";
		} else if (url.startsWith("https://grok.com")) {
			return (
				event.target.tagName === "TEXTAREA" ||
				(event.target.tagName === "DIV" &&
					event.target.contentEditable === "true")
			);
		} else 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"
			);
		} else if (url.startsWith("https://m365.cloud.microsoft/chat")) {
			return event.target.id === "m365-chat-editor-target-element";
		} else if (url.startsWith("https://www.perplexity.ai")) {
			return (
				event.target.tagName === "DIV" &&
				event.target.contentEditable === "true" &&
				event.target.id === "ask-input"
			);
		} else if (url.startsWith("https://yuanbao.tencent.com")) {
			return (
				event.target.tagName === "DIV" &&
				event.target.classList.contains("ql-editor") &&
				event.target.contentEditable === "true"
			);
		} else if (url.startsWith("https://yiyan.baidu.com")) {
			return (
				event.target.tagName === "DIV" &&
				event.target.getAttribute("role") === "textbox" &&
				event.target.contentEditable === "true"
			);
		}

		return false;
	}

	function findNBLMSendButton() {
		const submitButton = document.querySelector(
			'query-box form button[type="submit"]',
		);
		if (submitButton) return submitButton;
		return null;
	}

	function handleCustomInputs(event) {
		const url = window.location.href;

		if (event.isComposing) {
			return false;
		}

		if (!shouldHandleCtrlEnter(url, event) || !event.isTrusted) {
			return false;
		}

		const isOnlyEnter =
			event.code === "Enter" && !(event.ctrlKey || event.metaKey);
		const isCtrlEnter =
			event.code === "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")) {
				eventConfig.keyCode = 13;
			}

			if (url.startsWith("https://m365.cloud.microsoft/chat") && isCtrlEnter) {
				eventConfig.keyCode = 13;
			}

			if (url.startsWith("https://chat.deepseek.com")) {
				eventConfig.keyCode = 13;
				eventConfig.composed = true;
			}

			if (url.startsWith("https://yiyan.baidu.com")) {
				eventConfig.keyCode = 13;
			}

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

			if (isCtrlEnter && url.startsWith("https://notebooklm.google.com")) {
				const sendButton = findNBLMSendButton();
				if (sendButton) {
					sendButton.click();
				}
			}

			if (
				url.startsWith("https://claude.ai") &&
				event.target.tagName === "TEXTAREA"
			) {
				if (isOnlyEnter) {
					const textarea = event.target;
					const start = textarea.selectionStart;
					const end = textarea.selectionEnd;
					const value = textarea.value;
					textarea.value =
						value.substring(0, start) + "\n" + value.substring(end);
					textarea.selectionStart = textarea.selectionEnd = start + 1;
					textarea.dispatchEvent(new Event("input", { bubbles: true }));
				} else if (isCtrlEnter) {
					const saveButton = document.querySelector('button[type="submit"]');
					if (saveButton) {
						saveButton.click();
					}
				}
			}

			return true;
		}

		return false;
	}

	function handleTextarea(event) {
		if (event.target.tagName !== "TEXTAREA" || !event.isTrusted) {
			return false;
		}

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

		if (isOnlyEnter) {
			event.stopPropagation();
			return true;
		} else {
			const isCtrlEnter =
				event.code === "Enter" && (event.ctrlKey || event.metaKey);
			if (isCtrlEnter) {
				const preventCtrlEnterSites = ["https://www.qianwen.com"];
				if (
					preventCtrlEnterSites.some((site) =>
						window.location.href.startsWith(site),
					)
				) {
					event.preventDefault();
					event.stopImmediatePropagation();
					const newEvent = new KeyboardEvent("keydown", {
						key: "Enter",
						code: "Enter",
						bubbles: true,
						cancelable: true,
						shiftKey: false,
					});
					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://claude.ai") ||
			url.startsWith("https://notebooklm.google.com") ||
			url.startsWith("https://gemini.google.com") ||
			url.startsWith("https://www.phind.com") ||
			url.startsWith("https://chat.deepseek.com") ||
			url.startsWith("https://github.com") ||
			url.startsWith("https://grok.com") ||
			url.startsWith("https://m365.cloud.microsoft") ||
			url.startsWith("https://www.perplexity.ai") ||
			url.startsWith("https://yuanbao.tencent.com") ||
			url.startsWith("https://yiyan.baidu.com")
		) {
			if (handleCustomInputs(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;
		}
	}

	function fixYuanbaoPlaceholder() {
		const editor = document.querySelector('.ql-editor[contenteditable="true"]');
		if (editor) {
			const placeholder = editor.getAttribute("data-placeholder");
			if (placeholder && placeholder.includes("shift+enter")) {
				editor.setAttribute(
					"data-placeholder",
					placeholder.replace(/shift\+enter/gi, "Ctrl+Enter"),
				);
			}
		}
	}

	function observeYuanbaoPlaceholder() {
		if (!window.location.href.startsWith("https://yuanbao.tencent.com")) {
			return;
		}

		fixYuanbaoPlaceholder();

		const observer = new MutationObserver(() => {
			fixYuanbaoPlaceholder();
		});

		observer.observe(document.body, {
			childList: true,
			subtree: true,
			attributes: true,
			attributeFilter: ["data-placeholder"],
		});
	}

	document.addEventListener("keydown", handleKeyDown, { capture: true });

	if (document.readyState === "loading") {
		document.addEventListener("DOMContentLoaded", observeYuanbaoPlaceholder);
	} else {
		observeYuanbaoPlaceholder();
	}

	console.log("✅ EnterIt 已加载");
})();