ChatGPT Ctrl+Enter to Send

在 ChatGPT 网䈎按下 Ctrl+Enter 或 Cmd+Enter 發送訊息,單獨按 Enter 只換行

目前为 2024-07-11 提交的版本。查看 最新版本

// ==UserScript==
// @name         ChatGPT Ctrl+Enter to Send
// @namespace    http://tampermonkey.net/
// @version      3.5
// @description  在 ChatGPT 网䈎按下 Ctrl+Enter 或 Cmd+Enter 發送訊息,單獨按 Enter 只換行
// @author       SoizoKtantas & ChatGPT
// @match        https://chatgpt.com/*
// @icon         https://www.google.com/s2/favicons?domain=openai.com
// @license      Apache License 2.0
// @grant        GM_registerMenuCommand
// @grant        GM_unregisterMenuCommand
// @grant        GM_setValue
// @grant        GM_getValue
// @require      https://greasyfork.org/scripts/411512-gm-createmenu/code/GM_createMenu.js?version=851631
// ==/UserScript==

(function() {
    'use strict';

    // 初始化開關狀態
    let isEnterEnabled = GM_getValue('isEnterEnabled', false);
    let isCtrlEnterEnabled = GM_getValue('isCtrlEnterEnabled', false);

    // 定義開關菜單
    GM_createMenu.add([
        {
            on : {
                name : "啓用 Enter 換行",
                callback : function(){
                    isEnterEnabled = true;
                    GM_setValue('isEnterEnabled', true);
                    alert("Enter 換行已啓用");
                }
            },
            off : {
                name : "停用 Enter 換行",
                callback : function(){
                    isEnterEnabled = false;
                    GM_setValue('isEnterEnabled', false);
                    alert("Enter 換行已停用");
                }
            },
            load : function(menuStatus){
                if (menuStatus === 'on') {
                    isEnterEnabled = true;
                } else {
                    isEnterEnabled = false;
                }
            },
            default : isEnterEnabled
        },
        {
            on : {
                name : "啓用 Ctrl+Enter 發送",
                callback : function(){
                    isCtrlEnterEnabled = true;
                    GM_setValue('isCtrlEnterEnabled', true);
                    alert("Ctrl+Enter 發送已啓用");
                }
            },
            off : {
                name : "停用 Ctrl+Enter 發送",
                callback : function(){
                    isCtrlEnterEnabled = false;
                    GM_setValue('isCtrlEnterEnabled', false);
                    alert("Ctrl+Enter 發送已停用");
                }
            },
            load : function(menuStatus){
                if (menuStatus === 'on') {
                    isCtrlEnterEnabled = true;
                } else {
                    isCtrlEnterEnabled = false;
                }
            },
            default : isCtrlEnterEnabled
        }
    ]);
    GM_createMenu.create({storage: true});

    // 添加事件監聽器到文檔,使用 capture 階段
    document.addEventListener('keydown', function(e) {
        // 獲取焦點元素
        const activeElement = document.activeElement;

        // 檢查焦點是否在 #prompt-textarea 上
        if (activeElement && activeElement.id === 'prompt-textarea') {
            if (e.key === 'Enter') {
                if (isCtrlEnterEnabled && (e.ctrlKey || e.metaKey)) {
                    e.preventDefault(); // 防止默認行為
                    e.stopImmediatePropagation(); // 阻止其他事件處理器

                    // 查找發送按鈕
                    const sendButton = document.querySelector('#__next > div.relative.z-0.flex.h-full.w-full.overflow-hidden > div > main > div.flex.h-full.flex-col.focus-visible\\:outline-0 > div.w-full.md\\:pt-0.dark\\:border-white\\/20.md\\:border-transparent.md\\:dark\\:border-transparent.md\\:w-\\[calc\\(100\\%-\\.5rem\\)\\].juice\\:w-full > div.px-3.text-base.md\\:px-4.m-auto.md\\:px-5.lg\\:px-1.xl\\:px-5 > div > form > div > div.flex.w-full.items-center > div > div > button');

                    if (sendButton) {
                        // 模擬點擊發送按鈕
                        sendButton.click();
                    }
                } else if (isEnterEnabled) {
                    e.preventDefault(); // 防止默認行為
                    e.stopImmediatePropagation(); // 阻止其他事件處理器
                    // 插入換行
                    const textarea = activeElement;
                    const start = textarea.selectionStart;
                    const end = textarea.selectionEnd;
                    textarea.value = textarea.value.substring(0, start) + "\n" + textarea.value.substring(end);
                    // 將光標位置調整到換行後
                    textarea.selectionStart = textarea.selectionEnd = start + 1;

                    // 手動觸發 input 事件
                    const event = new Event('input', { bubbles: true });
                    textarea.dispatchEvent(event);
                }
            }
        }
    }, true); // 使用 capture 階段
})();