Gemini 🛡️ Enter Fix Pro

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

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Greasemonkey lub Violentmonkey.

You will need to install an extension such as Tampermonkey to install this script.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana będzie instalacja rozszerzenia Tampermonkey lub Userscripts.

You will need to install an extension such as Tampermonkey to install this script.

Aby zainstalować ten skrypt, musisz zainstalować rozszerzenie menedżera skryptów użytkownika.

(Mam już menedżera skryptów użytkownika, pozwól mi to zainstalować!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Musisz zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

(Mam już menedżera stylów użytkownika, pozwól mi to zainstalować!)

// ==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 พร้อมใช้งานแล้ว');
})();