☰

Gemini ðŸ›Ąïļ Enter Fix Pro

āļ›āđ‰āļ­āļ‡āļāļąāļ™ Enter āļŠāđˆāļ‡āļ‚āđ‰āļ­āļ„āļ§āļēāļĄ, āļĢāļ­āļ‡āļĢāļąāļš Enter āļ„āđ‰āļēāļ‡, āđāļĨāļ°āđ€āļ›āļĨāļĩāđˆāļĒāļ™āļŦāđ‰āļ­āļ‡/āđāļ—āđ‡āļšāđƒāļ™ Gemini āļ­āļąāļ•āđ‚āļ™āļĄāļąāļ•āļī (Android āļĄāļ·āļ­āļ–āļ·āļ­)

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai dÃĐjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai dÃĐjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

// ==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 āļžāļĢāđ‰āļ­āļĄāđƒāļŠāđ‰āļ‡āļēāļ™āđāļĨāđ‰āļ§');
})();