Gemini 🛡️ Enter Fix Pro

ป้องกัน Enter ส่งข้อความ, รองรับ Enter ค้าง, และเปลี่ยนห้อง/แท็บใน Gemini อัตโนมัติ (Android มือถือ)

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey, Greasemonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Userscripts.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een gebruikersscriptbeheerder nodig.

(Ik heb al een user script manager, laat me het downloaden!)

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

(Ik heb al een beheerder - laat me doorgaan met de installatie!)

// ==UserScript==
// @name         Gemini 🛡️ Enter Fix Pro
// @namespace    https://tampermonkey.local/gemini-enter-fix
// @version      1.4.0
// @description  ป้องกัน Enter ส่งข้อความ, รองรับ Enter ค้าง, และเปลี่ยนห้อง/แท็บใน Gemini อัตโนมัติ (Android มือถือ)
// @match        https://gemini.google.com/*
// @grant        none
// @license      MIT
// ==/UserScript==
(function () {
    'use strict';
    /** ================= CONFIG ================= **/
    const CONFIG = {
        DEBUG: true,
        NS: 'gemini-enterfix',
        RECHECK_INTERVAL: 2000, // ms, ตรวจสอบช่องข้อความใหม่ทุก 2 วินาที
    };
    /* ================== LOGGER ================== */
    function log(msg, type = "info") {
        try {
            if (!CONFIG.DEBUG) return;

            // ตรวจสอบข้อความให้แน่ใจว่าเป็น string เสมอ
            const safeMsg = typeof msg === "string" ? msg : JSON.stringify(msg, null, 2);

            // เตรียม payload ที่ปลอดภัย
            const payload = {
                namespace: "LogCenter", // ✅ ต้องตรงกับ CONFIG.NAMESPACE ใน Logs Center
                from: (typeof GM_info !== "undefined" && GM_info.script && GM_info.script.name) 
                ? GM_info.script.name 
                : "UnknownScript",
                type,
                time: new Date().toLocaleTimeString("th-TH", { hour12: false }),
                stack: new Error().stack,
                message: safeMsg
            };

            // ✅ ส่ง log ไปยัง Logs Center
            window.postMessage(payload, "*");
        } catch (err) {
            console.error("Logger error:", err);
        }
    }
    /** ================= UTILITIES ================= **/
    function insertNewLine(el) {
        try {
            // ใช้ execCommand เพื่อให้ Quill รองรับ
            el.focus();
            const ok = document.execCommand('insertLineBreak', false);
            if (!ok) {
                const sel = el.ownerDocument.getSelection();
                if (!sel || !sel.rangeCount) return;
                const range = sel.getRangeAt(0);
                const br = el.ownerDocument.createElement('br');
                range.deleteContents();
                range.insertNode(br);
                range.setStartAfter(br);
                range.setEndAfter(br);
                sel.removeAllRanges();
                sel.addRange(range);
            }
            el.dispatchEvent(new InputEvent('input', { bubbles: true }));
        } catch (err) {
            log(`insertNewLine error: ${err.message}`, 'error');
        }
    }
    /** ================= KEY HANDLER ================= **/
    function handleKey(e) {
        try {
            const el = document.activeElement;
            if (!el || !el.isContentEditable) return;
            // Enter ธรรมดา = ขึ้นบรรทัดใหม่
            if (e.key === 'Enter' && !e.ctrlKey && !e.shiftKey) {
                e.preventDefault();
                e.stopImmediatePropagation();
                insertNewLine(el);
            }
            // Ctrl/Shift + Enter = ส่งข้อความ
            else if (e.key === 'Enter' && (e.ctrlKey || e.shiftKey)) {
                log('📨 ส่งข้อความ (Ctrl/Shift+Enter)');
            }
        } catch (err) {
            log(`handleKey error: ${err.message}`, 'error');
        }
    }
    /** ================= EVENT ATTACH ================= **/
    function attachEditor(el) {
        if (!el || el.dataset[`${CONFIG.NS}-active`] === '1') return;
        el.dataset[`${CONFIG.NS}-active`] = '1';
        // ใช้ keydown (ไม่ใช้ keypress เพราะ Quill intercept)
        el.addEventListener('keydown', handleKey, { capture: true, passive: false });
        log('✅ ผูก Event Keydown สำเร็จ');
    }
    function scanEditors(root = document) {
        const boxes = root.querySelectorAll('.ql-editor,[contenteditable="true"],div[role="textbox"]');
        boxes.forEach(attachEditor);
    }
    /** ================= AUTO RE-ATTACH ================= **/
    // debounce เพื่อให้เปลี่ยนห้องแล้ว reattach ได้เร็วแต่ไม่ถี่เกิน
    let reattachTimer = null;
    function scheduleReattach() {
        if (reattachTimer) return;
        reattachTimer = setTimeout(() => {
            reattachTimer = null;
            scanEditors(document);
        }, 300);
    }
    // สังเกต DOM เปลี่ยน (เปลี่ยนแท็บ/ห้อง)
    const observer = new MutationObserver(scheduleReattach);
    observer.observe(document, { childList: true, subtree: true });
    // ตรวจซ้ำทุกๆ N วินาที (ป้องกันกรณี Shadow DOM โหลดช้า)
    setInterval(() => {
        scanEditors(document);
    }, CONFIG.RECHECK_INTERVAL);
    /** ================= INIT ================= **/
    window.addEventListener('keydown', handleKey, { capture: true, passive: false });
    scanEditors(document);
    log('🧩 Gemini Enter Fix Pro พร้อมใช้งานแล้ว');
})();