Gemini & AI Studio Enter Key Customizer

Modifies Enter key behavior in Gemini (incl. edit mode) & AI Studio (main input). Configurable send keys (Ctrl/Cmd, Shift, Alt) + Enter for send/save, Enter for newline; or native behaviors. Enhanced settings panel.

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name              Gemini & AI Studio Enter Key Customizer
// @name:en           Gemini & AI Studio Enter Key Customizer
// @name:ja           Gemini & AI Studio Enterキーカスタマイザー
// @name:zh-TW        Gemini 與 AI Studio Enter 鍵自訂器
// @namespace         https://greasyfork.org/en/users/1467948-stonedkhajiit
// @version           1.1.0
// @description       Modifies Enter key behavior in Gemini (incl. edit mode) & AI Studio (main input). Configurable send keys (Ctrl/Cmd, Shift, Alt) + Enter for send/save, Enter for newline; or native behaviors. Enhanced settings panel.
// @description:en    Modifies Enter key behavior in Gemini (incl. edit mode) & AI Studio (main input). Configurable send keys (Ctrl/Cmd, Shift, Alt) + Enter for send/save, Enter for newline; or native behaviors. Enhanced settings panel.
// @description:ja    Gemini(編集モード含む)およびAI Studio(メイン入力)のEnterキー動作を変更。送信/保存キーを選択可 (Ctrl/Cmd, Shift, Alt) + Enter、Enterで改行。または標準動作。強化された設定パネルあり。
// @description:zh-TW 調整 Gemini (包含編輯模式) 與 AI Studio (主要輸入框) 的 Enter 鍵行為。可自訂傳送/儲存鍵 (Ctrl/Cmd, Shift, Alt) + Enter,Enter 鍵換行;或原生行為。附強化設定面板。
// @author            StonedKhajiit
// @match             https://gemini.google.com/*
// @match             https://aistudio.google.com/*
// @grant             GM_setValue
// @grant             GM_getValue
// @grant             GM_registerMenuCommand
// @grant             GM_unregisterMenuCommand
// @license           MIT
// ==/UserScript==

(function() {
    'use strict';

    const SCRIPT_ID = 'GeminiEnterNewlineMultiSite_v1.1.0';
    const DEBUG_MODE = false; 

    const GEMINI_INPUT_SELECTOR_PRIMARY = 'div.ql-editor[contenteditable="true"]';
    const GEMINI_INPUT_SELECTORS_FALLBACK = [
        'textarea[enterkeyhint="send"]', 'textarea[aria-label*="Prompt"]',
        'textarea[placeholder*="Message Gemini"]', 'div[role="textbox"][contenteditable="true"]'
    ];
    const AISTUDIO_INPUT_SELECTORS = [
        'ms-autosize-textarea textarea[aria-label="Type something or tab to choose an example prompt"]',
        'ms-autosize-textarea textarea',
        'ms-autosize-textarea textarea[aria-label="Start typing a prompt"]'
    ];

    const GEMINI_EDIT_INPUT_SELECTORS = ['user-query-content.edit-mode textarea.mat-mdc-input-element'];

    const GEMINI_SEND_BUTTON_SELECTORS = [
        'button[aria-label*="Send"]', 'button[aria-label*="傳送"]',
        'button[aria-label*="送信"]', 'button[data-test-id="send-button"]',
    ];
    const GEMINI_SAVE_EDIT_BUTTON_SELECTORS = ['user-query-content.edit-mode button.update-button'];

    const AISTUDIO_SEND_BUTTON_SELECTORS = ['button[aria-label="Run"]', 'button[aria-label="Submit"]'];
    const AISTUDIO_SEND_BUTTON_MODIFIER_HINT_SELECTOR = 'span.secondary-key';

    const GM_GLOBAL_ENABLE_KEY_STORAGE = 'geminiEnterGlobalEnable_v1_5';
    const SITE_MODES = { CUSTOM: 'custom', NATIVE: 'native' };
    const INPUT_TYPES = { MAIN: 'main', EDIT: 'edit', UNKNOWN: 'unknown' };

    const GM_GEMINI_CONFIG_STORAGE = 'geminiEnterConfig_v1_5_gemini';
    const DEFAULT_GEMINI_CONFIG = {
        mode: SITE_MODES.CUSTOM,
        keys: { ctrlOrCmd: true, shift: false, alt: false }
    };

    const GM_AISTUDIO_CONFIG_STORAGE = 'aiStudioEnterConfig_v1_5_aistudio';
    const DEFAULT_AISTUDIO_CONFIG = {
        mode: SITE_MODES.NATIVE,
        keys: { ctrlOrCmd: true, shift: false, alt: false }
    };

    let activeInputInfo = { element: null, type: INPUT_TYPES.UNKNOWN };
    let isScriptGloballyEnabled = true;
    let currentGeminiConfig = JSON.parse(JSON.stringify(DEFAULT_GEMINI_CONFIG));
    let currentAIStudioConfig = JSON.parse(JSON.stringify(DEFAULT_AISTUDIO_CONFIG));
    let menuCommandIds = [];

    function logDebug(...args) {
        if (DEBUG_MODE) {
            console.log(`[${SCRIPT_ID}]`, ...args);
        }
    }

    function debounce(func, wait) {
        let timeout;
        return function executedFunction(...args) {
            const later = () => { clearTimeout(timeout); func(...args); };
            clearTimeout(timeout);
            timeout = setTimeout(later, wait);
        };
    }

    const i18n = {
        currentLang: 'en',
        strings: {
            'en': {
                notifySettingsSaved: 'Settings saved!',
                notifyScriptEnabled: 'Custom Enter key behavior enabled. Reload page if needed.',
                notifyScriptDisabled: 'Custom Enter key behavior disabled. Reload page if needed.',
                settingsTitle: 'Script Settings', closeButton: 'Close', saveButton: 'Save',
                openSettingsMenu: 'Configure Enter Key Behavior...',
                enableScriptMenu: 'Enable Custom Enter Key Behavior',
                disableScriptMenu: 'Disable Custom Enter Key Behavior',
                geminiSectionTitle: 'Gemini (gemini.google.com):',
                aiStudioSectionTitle: 'AI Studio (aistudio.google.com):',
                behaviorLabel: 'Enter Key Behavior:',
                customBehavior: 'Custom (Enter for newline, select send/save keys below)',
                nativeBehavior: 'Use Native Site Behavior (Script does nothing)',
                geminiNativeBehaviorSpecific: 'Use Gemini Native Behavior (Enter sends/saves)',
                aiStudioNativeBehaviorSpecific: 'Use AI Studio Native Behavior (Default: Ctrl/Cmd+Enter sends)',
                sendKeysLabel: 'Send/Save with (Modifier + Enter):',
                keyCtrlCmd: 'Ctrl / ⌘ Cmd',
                keyShift: 'Shift',
                keyAlt: 'Alt',
                hintCtrlCmd: 'Ctrl/Cmd', hintShift: 'Shift', hintAlt: 'Alt',
                hintOr: 'or',
                hintPreviewWillUse: 'Will use:',
                hintPreviewToSend: 'to send/save.',
                hintPreviewNoKeySelected: 'No send/save key selected. Enter for newline.',
                hintPreviewNative: 'Script will not modify Enter key behavior.',
            },
            'zh-TW': {
                notifySettingsSaved: '設定已儲存!',
                notifyScriptEnabled: '自訂 Enter 鍵行為已啟用。若未立即生效請重載頁面。',
                notifyScriptDisabled: '自訂 Enter 鍵行為已停用。若未立即生效請重載頁面。',
                settingsTitle: '腳本設定', closeButton: '關閉', saveButton: '儲存',
                openSettingsMenu: '設定 Enter 鍵行為...',
                enableScriptMenu: '啟用自訂 Enter 鍵行為',
                disableScriptMenu: '停用自訂 Enter 鍵行為',
                geminiSectionTitle: 'Gemini (gemini.google.com):',
                aiStudioSectionTitle: 'AI Studio (aistudio.google.com):',
                behaviorLabel: 'Enter 鍵行為:',
                customBehavior: '自訂 (Enter 換行,於下方選擇傳送/儲存鍵)',
                nativeBehavior: '使用網站原生行為 (腳本不介入)',
                geminiNativeBehaviorSpecific: '使用 Gemini 原生行為 (Enter 即送出/儲存)',
                aiStudioNativeBehaviorSpecific: '使用 AI Studio 原生行為 (預設 Ctrl/Cmd+Enter 送出)',
                sendKeysLabel: '使用組合鍵傳送/儲存 (組合鍵 + Enter):',
                keyCtrlCmd: 'Ctrl / ⌘ Cmd',
                keyShift: 'Shift',
                keyAlt: 'Alt',
                hintCtrlCmd: 'Ctrl/Cmd', hintShift: 'Shift', hintAlt: 'Alt',
                hintOr: '或',
                hintPreviewWillUse: '將使用:',
                hintPreviewToSend: '進行傳送/儲存。',
                hintPreviewNoKeySelected: '未選擇傳送/儲存鍵。Enter 鍵將用於換行。',
                hintPreviewNative: '腳本不會修改 Enter 鍵行為。',
            },
            'ja': {
                notifySettingsSaved: '設定を保存しました!',
                notifyScriptEnabled: 'Enterキーのカスタム動作が有効になりました。必要に応じてページを再読み込みしてください。',
                notifyScriptDisabled: 'Enterキーのカスタム動作が無効になりました。必要に応じてページを再読み込みしてください。',
                settingsTitle: 'スクリプト設定', closeButton: '閉じる', saveButton: '保存',
                openSettingsMenu: 'Enterキーの動作を設定...',
                enableScriptMenu: 'Enterキーのカスタム動作を有効化',
                disableScriptMenu: 'Enterキーのカスタム動作を無効化',
                geminiSectionTitle: 'Gemini (gemini.google.com):',
                aiStudioSectionTitle: 'AI Studio (aistudio.google.com):',
                behaviorLabel: 'Enterキーの動作:',
                customBehavior: 'カスタム (Enterで改行、送信/保存キーを以下で選択)',
                nativeBehavior: 'サイトのネイティブ動作を使用 (スクリプトは何もしません)',
                geminiNativeBehaviorSpecific: 'Geminiネイティブ動作を使用 (Enterで送信/保存)',
                aiStudioNativeBehaviorSpecific: 'AI Studioネイティブ動作を使用 (デフォルトはCtrl/Cmd+Enterで送信)',
                sendKeysLabel: '修飾キーで送信/保存 (修飾キー + Enter):',
                keyCtrlCmd: 'Ctrl / ⌘ Cmd',
                keyShift: 'Shift',
                keyAlt: 'Alt',
                hintCtrlCmd: 'Ctrl/Cmd', hintShift: 'Shift', hintAlt: 'Alt',
                hintOr: 'または',
                hintPreviewWillUse: '使用するキー:',
                hintPreviewToSend: 'で送信/保存します。',
                hintPreviewNoKeySelected: '送信/保存キーが選択されていません。Enterキーは改行に使用されます。',
                hintPreviewNative: 'スクリプトはEnterキーの動作を変更しません。',
            }
        },
        detectLanguage() {
            const lang = navigator.language || navigator.userLanguage;
            if (lang) {
                if (lang.startsWith('ja')) this.currentLang = 'ja';
                else if (lang.startsWith('zh-TW') || lang.startsWith('zh-Hant')) this.currentLang = 'zh-TW';
                else if (lang.startsWith('en')) this.currentLang = 'en';
                else this.currentLang = 'en';
            } else { this.currentLang = 'en'; }
        },
        get(key, ...args) {
            const langStrings = this.strings[this.currentLang] || this.strings.en;
            const template = langStrings[key] || (this.strings.en && this.strings.en[key]);
            if (typeof template === 'function') return template(...args);
            if (typeof template === 'string') return template;
            logDebug(`Missing i18n string for key: ${key} in lang: ${this.currentLang}`);
            return `Missing string: ${key}`;
        }
    };

    function createSettingsUI() {
        if (document.getElementById('gemini-ai-settings-overlay')) return;
        const overlay = document.createElement('div');
        overlay.id = 'gemini-ai-settings-overlay';
        overlay.classList.add('hidden');
        const style = document.createElement('style');
        style.textContent = `
            @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
            #gemini-ai-settings-overlay {
                position: fixed; inset: 0px; background-color: rgba(0, 0, 0, 0.6);
                display: flex; align-items: center; justify-content: center;
                z-index: 2147483647; font-family: 'Inter', Arial, sans-serif;
                opacity: 0; transition: opacity 0.2s ease-in-out;
            }
            #gemini-ai-settings-overlay.visible { opacity: 1; }
            #gemini-ai-settings-overlay.hidden { display: none !important; }
            #gemini-ai-settings-panel {
                background-color: #ffffff; color: #1f2937;
                padding: 18px; border-radius: 8px;
                box-shadow: 0 20px 25px -5px rgba(0,0,0,0.1), 0 10px 10px -5px rgba(0,0,0,0.04);
                width: 90%; max-width: 460px;
                position: relative; overflow-y: auto; max-height: 90vh;
            }
            body.userscript-dark-mode #gemini-ai-settings-panel { background-color: #2d3748; color: #e2e8f0; }
            body.userscript-dark-mode #gemini-ai-settings-panel h2,
            body.userscript-dark-mode #gemini-ai-settings-panel h3,
            body.userscript-dark-mode #gemini-ai-settings-panel p,
            body.userscript-dark-mode #gemini-ai-settings-panel label { color: #e2e8f0; }
            body.userscript-dark-mode #gemini-ai-settings-panel button#gemini-ai-close-btn { background-color: #4a5568; color: #e2e8f0; }
            body.userscript-dark-mode #gemini-ai-settings-panel button#gemini-ai-close-btn:hover { background-color: #718096; }
            body.userscript-dark-mode #gemini-ai-settings-panel input[type="radio"],
            body.userscript-dark-mode #gemini-ai-settings-panel input[type="checkbox"] { filter: invert(1) hue-rotate(180deg); }

            #gemini-ai-settings-panel h2 { font-size: 1.15rem; font-weight: 600; margin-bottom: 0.8rem; }
            #gemini-ai-settings-panel h3 { font-size: 1rem; font-weight: 600; margin-bottom: 0.5rem; margin-top: 1rem; }
            #gemini-ai-settings-panel .section-divider { border-top: 1px solid #e5e7eb; margin-top: 1rem; margin-bottom: 1rem; }
            body.userscript-dark-mode #gemini-ai-settings-panel .section-divider { border-top-color: #4a5568; }

            #gemini-ai-settings-panel .options-group > div { margin-bottom: 0.4rem; }
            #gemini-ai-settings-panel label { display: inline-flex; align-items: center; cursor: pointer; font-size: 0.875rem; }
            #gemini-ai-settings-panel label[title] { cursor: help; border-bottom: 1px dotted; }
            body.userscript-dark-mode #gemini-ai-settings-panel label[title] { border-bottom-color: #718096; }
            #gemini-ai-settings-panel input[type="radio"],
            #gemini-ai-settings-panel input[type="checkbox"] { margin-right: 0.5rem; cursor: pointer; transform: scale(0.95); }
            #gemini-ai-settings-panel input[type="checkbox"]:disabled + label { color: #9ca3af !important; cursor: not-allowed; }
            body.userscript-dark-mode #gemini-ai-settings-panel input[type="checkbox"]:disabled + label { color: #718096 !important; }
            
            .settings-preview-text { font-size: 0.8rem; color: #6b7280; margin-top: 0.5rem; padding-left: 0.5rem; min-height: 1em; font-style: italic; }
            body.userscript-dark-mode .settings-preview-text { color: #9ca3af; }

            .settings-buttons-container { display: flex; justify-content: flex-end; margin-top: 1.2rem; gap: 0.5rem; }
            #gemini-ai-settings-panel button {
                padding: 0.4rem 0.9rem; border-radius: 6px;
                font-weight: 500; transition: background-color 0.2s ease, box-shadow 0.2s ease;
                border: none; cursor: pointer; font-size: 0.875rem;
            }
            #gemini-ai-settings-panel button#gemini-ai-close-btn { background-color: #e5e7eb; color: #374151; }
            #gemini-ai-settings-panel button#gemini-ai-close-btn:hover { background-color: #d1d5db; }
            #gemini-ai-settings-panel button#gemini-ai-save-btn { background-color: #3b82f6; color: white; }
            #gemini-ai-settings-panel button#gemini-ai-save-btn:hover { background-color: #2563eb; }

            #gemini-ai-notification {
                position: fixed; bottom: 25px; left: 50%;
                transform: translateX(-50%);
                background-color: #10b981; color: white;
                padding: 0.8rem 1.5rem; border-radius: 6px;
                box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1), 0 2px 4px -1px rgba(0,0,0,0.06);
                z-index: 2147483647; opacity: 0;
                transition: opacity 0.3s ease-in-out, transform 0.3s ease-in-out;
                font-family: 'Inter', Arial, sans-serif; font-size: 0.9rem;
            }
            #gemini-ai-notification.visible { opacity: 1; transform: translateX(-50%) translateY(0px); }
            #gemini-ai-notification.hidden { display: none !important; }
        `;
        document.head.appendChild(style);
        const settingsPanel = document.createElement('div');
        settingsPanel.id = 'gemini-ai-settings-panel';
        const titleElement = document.createElement('h2');
        titleElement.textContent = i18n.get('settingsTitle');
        settingsPanel.appendChild(titleElement);
        const geminiTitle = document.createElement('h3');
        settingsPanel.appendChild(geminiTitle);
        const geminiOptionsDiv = document.createElement('div');
        geminiOptionsDiv.id = 'gemini-key-options';
        geminiOptionsDiv.className = 'options-group';
        settingsPanel.appendChild(geminiOptionsDiv);
        settingsPanel.appendChild(document.createElement('div')).className = 'section-divider';
        const aistudioTitle = document.createElement('h3');
        settingsPanel.appendChild(aistudioTitle);
        const aistudioOptionsDiv = document.createElement('div');
        aistudioOptionsDiv.id = 'aistudio-key-options';
        aistudioOptionsDiv.className = 'options-group';
        settingsPanel.appendChild(aistudioOptionsDiv);
        const buttonDiv = document.createElement('div');
        buttonDiv.className = 'settings-buttons-container';
        const closeButton = document.createElement('button');
        closeButton.id = 'gemini-ai-close-btn';
        closeButton.textContent = i18n.get('closeButton');
        buttonDiv.appendChild(closeButton);
        const saveButton = document.createElement('button');
        saveButton.id = 'gemini-ai-save-btn';
        saveButton.textContent = i18n.get('saveButton');
        buttonDiv.appendChild(saveButton);
        settingsPanel.appendChild(buttonDiv);
        overlay.appendChild(settingsPanel);
        document.body.appendChild(overlay);
        const notificationDiv = document.createElement('div');
        notificationDiv.id = 'gemini-ai-notification';
        notificationDiv.classList.add('hidden');
        document.body.appendChild(notificationDiv);
        closeButton.addEventListener('click', closeSettings);
        saveButton.addEventListener('click', saveSettingsFromUI);
        overlay.addEventListener('click', (e) => { if (e.target === overlay) closeSettings(); });
        if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
            document.body.classList.add('userscript-dark-mode');
        }
        window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
            document.body.classList.toggle('userscript-dark-mode', e.matches);
        });
    }

    function populateSettingsUI() {
        const geminiOptionsDiv = document.getElementById('gemini-key-options');
        const aistudioOptionsDiv = document.getElementById('aistudio-key-options');
        if (!geminiOptionsDiv || !aistudioOptionsDiv) return;

        while (geminiOptionsDiv.firstChild) geminiOptionsDiv.removeChild(geminiOptionsDiv.firstChild);
        while (aistudioOptionsDiv.firstChild) aistudioOptionsDiv.removeChild(aistudioOptionsDiv.firstChild);

        const createSiteSettingSection = (container, siteConfig, siteName) => {
            const behaviorTitle = document.createElement('p');
            behaviorTitle.textContent = i18n.get('behaviorLabel');
            behaviorTitle.style.fontWeight = '500'; behaviorTitle.style.marginBottom = '0.3rem';
            container.appendChild(behaviorTitle);

            const modes = [
                { value: SITE_MODES.CUSTOM, labelKey: 'customBehavior' },
                { value: SITE_MODES.NATIVE, labelKey: siteName === 'gemini' ? 'geminiNativeBehaviorSpecific' : (siteName === 'aistudio' ? 'aiStudioNativeBehaviorSpecific' : 'nativeBehavior') }
            ];

            if (siteName === 'aistudio' && siteConfig.mode === 'site_specific') {
                 logDebug('Mapping obsolete AI Studio SITE_SPECIFIC mode to CUSTOM for settings UI.');
                 siteConfig.mode = SITE_MODES.CUSTOM;
            }

            modes.forEach(modeInfo => {
                const div = document.createElement('div');
                const input = document.createElement('input');
                input.type = 'radio'; input.name = `${siteName}KeyModeBehavior`;
                input.id = `${siteName}-mode-${modeInfo.value}`; input.value = modeInfo.value;
                if (siteConfig.mode === modeInfo.value) input.checked = true;
                const label = document.createElement('label');
                label.htmlFor = input.id; label.textContent = i18n.get(modeInfo.labelKey);
                div.appendChild(input); div.appendChild(label);
                container.appendChild(div);
            });

            const sendKeysLabelEl = document.createElement('p');
            sendKeysLabelEl.textContent = i18n.get('sendKeysLabel');
            sendKeysLabelEl.style.fontWeight = '500'; sendKeysLabelEl.style.marginTop = '0.7rem'; sendKeysLabelEl.style.marginBottom = '0.3rem';
            container.appendChild(sendKeysLabelEl);

            const keysContainer = document.createElement('div');
            keysContainer.id = `${siteName}-custom-keys-container`;
            container.appendChild(keysContainer);

            const modifierCheckboxesSetup = [
                { keyName: 'ctrlOrCmd', labelKey: 'keyCtrlCmd' },
                { keyName: 'shift', labelKey: 'keyShift' },
                { keyName: 'alt', labelKey: 'keyAlt' },
            ];

            modifierCheckboxesSetup.forEach(opt => {
                const div = document.createElement('div');
                const input = document.createElement('input');
                input.type = 'checkbox'; input.name = `${siteName}SendKey`; input.id = `${siteName}-key-${opt.keyName}`; input.value = opt.keyName;
                if (siteConfig.keys && typeof siteConfig.keys[opt.keyName] === 'boolean') {
                    input.checked = siteConfig.keys[opt.keyName];
                }
                const label = document.createElement('label');
                label.htmlFor = input.id; label.textContent = i18n.get(opt.labelKey);
                div.appendChild(input); div.appendChild(label);
                keysContainer.appendChild(div);
            });

            const previewTextEl = document.createElement('p');
            previewTextEl.className = 'settings-preview-text';
            keysContainer.appendChild(previewTextEl);

            const updatePreviewText = () => {
                const currentMode = container.querySelector(`input[name="${siteName}KeyModeBehavior"]:checked`)?.value;
                if (currentMode === SITE_MODES.NATIVE) {
                    previewTextEl.textContent = i18n.get('hintPreviewNative'); return;
                }
                const selectedKeys = [];
                modifierCheckboxesSetup.forEach(opt => {
                    const checkbox = container.querySelector(`#${siteName}-key-${opt.keyName}`);
                    if (checkbox && checkbox.checked) selectedKeys.push(i18n.get(opt.labelKey));
                });
                if (selectedKeys.length > 0) {
                    previewTextEl.textContent = `${i18n.get('hintPreviewWillUse')} ${selectedKeys.join(` ${i18n.get('hintOr')} `)} + Enter ${i18n.get('hintPreviewToSend')}`;
                } else { previewTextEl.textContent = i18n.get('hintPreviewNoKeySelected');}
            };

            const customModeRadio = container.querySelector(`input[value="${SITE_MODES.CUSTOM}"]`);
            const toggleCheckboxesAndPreview = () => {
                const currentMode = container.querySelector(`input[name="${siteName}KeyModeBehavior"]:checked`)?.value;
                const useCustomBehavior = currentMode === SITE_MODES.CUSTOM;

                sendKeysLabelEl.style.color = useCustomBehavior ? '' : (document.body.classList.contains('userscript-dark-mode') ? '#718096':'#9ca3af');
                keysContainer.style.opacity = useCustomBehavior ? '1' : '0.5';
                previewTextEl.style.display = 'block';

                modifierCheckboxesSetup.forEach(opt => {
                    const checkbox = container.querySelector(`#${siteName}-key-${opt.keyName}`);
                    if (checkbox) {
                        checkbox.disabled = !useCustomBehavior;
                        checkbox.addEventListener('change', updatePreviewText);
                    }
                });
                updatePreviewText();
            };
            container.querySelectorAll(`input[name="${siteName}KeyModeBehavior"]`).forEach(radio => {
                radio.addEventListener('change', toggleCheckboxesAndPreview);
            });
            toggleCheckboxesAndPreview();
        };

        const geminiSectionTitleEl = geminiOptionsDiv.previousElementSibling;
        if (geminiSectionTitleEl && geminiSectionTitleEl.tagName === 'H3') geminiSectionTitleEl.textContent = i18n.get('geminiSectionTitle');
        createSiteSettingSection(geminiOptionsDiv, currentGeminiConfig, 'gemini');

        const aiStudioSectionTitleEl = aistudioOptionsDiv.previousElementSibling;
        if (aiStudioSectionTitleEl && aiStudioSectionTitleEl.tagName === 'H3') aiStudioSectionTitleEl.textContent = i18n.get('aiStudioSectionTitle');
        createSiteSettingSection(aistudioOptionsDiv, currentAIStudioConfig, 'aistudio');
    }

    function openSettings() {
        loadSettings(); populateSettingsUI();
        const overlay = document.getElementById('gemini-ai-settings-overlay');
        if (overlay) { overlay.classList.remove('hidden'); void overlay.offsetWidth; overlay.classList.add('visible'); }
    }
    function closeSettings() {
        const overlay = document.getElementById('gemini-ai-settings-overlay');
        if (overlay) {
            overlay.classList.remove('visible');
            setTimeout(() => { if (!overlay.classList.contains('visible')) overlay.classList.add('hidden'); }, 200);
        }
    }
    function showNotification(message) {
        const notificationDiv = document.getElementById('gemini-ai-notification');
        if (notificationDiv) {
            notificationDiv.textContent = message;
            notificationDiv.classList.remove('hidden'); void notificationDiv.offsetWidth; notificationDiv.classList.add('visible');
            setTimeout(() => {
                notificationDiv.classList.remove('visible');
                setTimeout(() => { if (!notificationDiv.classList.contains('visible')) notificationDiv.classList.add('hidden'); }, 300);
            }, 2500);
        }
    }

    function loadConfigForSite(storageKey, defaultConfig, siteName) {
        const savedConfigString = GM_getValue(storageKey);
        let configToReturn = JSON.parse(JSON.stringify(defaultConfig));
        if (savedConfigString) {
            try {
                const savedConfig = JSON.parse(savedConfigString);
                if (siteName === 'aistudio' && savedConfig.mode === 'site_specific') {
                    logDebug(`Migrating AI Studio mode from 'site_specific' to '${DEFAULT_AISTUDIO_CONFIG.mode}' for key ${storageKey}`);
                    configToReturn.mode = DEFAULT_AISTUDIO_CONFIG.mode;
                    configToReturn.keys = {
                        ctrlOrCmd: typeof savedConfig.keys?.ctrlOrCmd === 'boolean' ? savedConfig.keys.ctrlOrCmd : DEFAULT_AISTUDIO_CONFIG.keys.ctrlOrCmd,
                        shift: typeof savedConfig.keys?.shift === 'boolean' ? savedConfig.keys.shift : DEFAULT_AISTUDIO_CONFIG.keys.shift,
                        alt: typeof savedConfig.keys?.alt === 'boolean' ? savedConfig.keys.alt : DEFAULT_AISTUDIO_CONFIG.keys.alt,
                    };
                } else {
                    configToReturn.mode = Object.values(SITE_MODES).includes(savedConfig.mode) ? savedConfig.mode : defaultConfig.mode;
                    configToReturn.keys = {
                        ctrlOrCmd: typeof savedConfig.keys?.ctrlOrCmd === 'boolean' ? savedConfig.keys.ctrlOrCmd : defaultConfig.keys.ctrlOrCmd,
                        shift: typeof savedConfig.keys?.shift === 'boolean' ? savedConfig.keys.shift : defaultConfig.keys.shift,
                        alt: typeof savedConfig.keys?.alt === 'boolean' ? savedConfig.keys.alt : defaultConfig.keys.alt,
                    };
                }
            } catch (e) { logDebug(`Error parsing config from ${storageKey}, using defaults.`, e); }
        }
        return configToReturn;
    }
    function loadSettings() {
        isScriptGloballyEnabled = GM_getValue(GM_GLOBAL_ENABLE_KEY_STORAGE, true);
        currentGeminiConfig = loadConfigForSite(GM_GEMINI_CONFIG_STORAGE, DEFAULT_GEMINI_CONFIG, 'gemini');
        currentAIStudioConfig = loadConfigForSite(GM_AISTUDIO_CONFIG_STORAGE, DEFAULT_AISTUDIO_CONFIG, 'aistudio');
    }

    function saveConfigForSite(storageKey, newConfig, defaultConfig) {
        if (!Object.values(SITE_MODES).includes(newConfig.mode)) newConfig.mode = defaultConfig.mode;
        newConfig.keys = {
            ctrlOrCmd: typeof newConfig.keys?.ctrlOrCmd === 'boolean' ? newConfig.keys.ctrlOrCmd : false,
            shift: typeof newConfig.keys?.shift === 'boolean' ? newConfig.keys.shift : false,
            alt: typeof newConfig.keys?.alt === 'boolean' ? newConfig.keys.alt : false,
        };
        GM_setValue(storageKey, JSON.stringify(newConfig));
        return newConfig;
    }
    function saveSettingsFromUI() {
        const selectedGeminiMode = document.querySelector('input[name="geminiKeyModeBehavior"]:checked')?.value || DEFAULT_GEMINI_CONFIG.mode;
        const newGeminiKeys = {
            ctrlOrCmd: document.getElementById('gemini-key-ctrlOrCmd')?.checked || false,
            shift: document.getElementById('gemini-key-shift')?.checked || false,
            alt: document.getElementById('gemini-key-alt')?.checked || false,
        };
        currentGeminiConfig = saveConfigForSite(GM_GEMINI_CONFIG_STORAGE, { mode: selectedGeminiMode, keys: newGeminiKeys }, DEFAULT_GEMINI_CONFIG);

        const selectedAIStudioMode = document.querySelector('input[name="aistudioKeyModeBehavior"]:checked')?.value || DEFAULT_AISTUDIO_CONFIG.mode;
        const newAIStudioKeys = {
            ctrlOrCmd: document.getElementById('aistudio-key-ctrlOrCmd')?.checked || false,
            shift: document.getElementById('aistudio-key-shift')?.checked || false,
            alt: document.getElementById('aistudio-key-alt')?.checked || false,
        };
        currentAIStudioConfig = saveConfigForSite(GM_AISTUDIO_CONFIG_STORAGE, { mode: selectedAIStudioMode, keys: newAIStudioKeys }, DEFAULT_AISTUDIO_CONFIG);

        updateActiveInputListener(); updateAIStudioButtonModifierHint(); registerMenuCommand();
        showNotification(i18n.get('notifySettingsSaved')); closeSettings();
    }

    function updateAIStudioButtonModifierHint() {
        if (!window.location.hostname.includes('aistudio.google.com')) return;
        const mainSendButton = document.querySelector(AISTUDIO_SEND_BUTTON_SELECTORS.join(', '));
        if (!mainSendButton) return;
        const hintSpan = mainSendButton.querySelector(AISTUDIO_SEND_BUTTON_MODIFIER_HINT_SELECTOR);
        if (!hintSpan) return;

        if (activeInputInfo.element && activeInputInfo.type === INPUT_TYPES.EDIT) {
            hintSpan.style.display = 'none'; return;
        }
        hintSpan.style.display = 'inline'; let hintText = '';

        if (currentAIStudioConfig.mode === SITE_MODES.NATIVE) {
            hintText = i18n.get('hintCtrlCmd');
        } else if (currentAIStudioConfig.mode === SITE_MODES.CUSTOM) {
            const keyLabels = [];
            if (currentAIStudioConfig.keys.ctrlOrCmd) keyLabels.push(i18n.get('hintCtrlCmd'));
            if (currentAIStudioConfig.keys.shift) keyLabels.push(i18n.get('hintShift'));
            if (currentAIStudioConfig.keys.alt) keyLabels.push(i18n.get('hintAlt'));
            if (keyLabels.length > 0) hintText = keyLabels.join(` ${i18n.get('hintOr')} `);
            else hintSpan.style.display = 'none';
        } else {
            hintSpan.style.display = 'none';
        }
        hintSpan.textContent = hintSpan.style.display !== 'none' ? hintText + ' ' : '';
    }

    function insertNewline(element) {
        if (!element) return;
        if (element.isContentEditable) {
            element.focus(); let success = false;
            try { success = document.execCommand('insertParagraph', false, null); } catch (e) {}
            if (!success) {
                try {
                    const selection = window.getSelection();
                    if (selection && selection.rangeCount > 0) {
                        const range = selection.getRangeAt(0); const br = document.createElement('br');
                        range.deleteContents(); range.insertNode(br);
                        range.setStartAfter(br); range.collapse(true);
                        selection.removeAllRanges(); selection.addRange(range); element.focus();
                    } else { document.execCommand('insertHTML', false, '<br>');}
                } catch (e) {}
            }
        } else if (element.tagName === 'TEXTAREA') {
            const start = element.selectionStart; const end = element.selectionEnd;
            element.value = `${element.value.substring(0, start)}\n${element.value.substring(end)}`;
            element.selectionStart = element.selectionEnd = start + 1;
            element.dispatchEvent(new Event('input', { bubbles: true, cancelable: true }));
        }
    }
    function clickSubmitButtonForInput(targetElement, inputType) {
        const button = findSubmitButtonForInput({element: targetElement, type: inputType });
        logDebug('[clickSubmitButtonForInput] Target Element:', targetElement, 'Input Type:', inputType, 'Found Button:', button);
        if (button && !button.disabled) {
            button.click();
        } else {
            logDebug('[clickSubmitButtonForInput] Button not found or disabled. Fallback to form submit if applicable.');
            const form = targetElement?.closest('form');
            if (form) { if (typeof form.requestSubmit === 'function') form.requestSubmit(); else form.submit(); }
        }
    }

    function processEnterKeyForSite(event, configuredSendKeys, isCtrlOrCmdPressed, isShiftPressed, isAltPressed, isPlainEnter, isAnyModifierPressed, activeInput) {
        let shouldSend = false;
        if (configuredSendKeys.ctrlOrCmd && isCtrlOrCmdPressed) shouldSend = true;
        else if (configuredSendKeys.shift && isShiftPressed) shouldSend = true;
        else if (configuredSendKeys.alt && isAltPressed) shouldSend = true;

        logDebug('[processEnterKeyForSite] Should Send:', shouldSend, 'Plain Enter:', isPlainEnter, 'Any Modifier:', isAnyModifierPressed, 'Config:', configuredSendKeys, 'Active Input:', activeInput);

        if (shouldSend) {
            event.preventDefault(); event.stopImmediatePropagation();
            clickSubmitButtonForInput(activeInput.element, activeInput.type);
        } else if (isPlainEnter) {
            event.preventDefault(); event.stopImmediatePropagation();
            insertNewline(activeInput.element);
        } else if (isAnyModifierPressed) {
            event.preventDefault(); event.stopImmediatePropagation();
        }
    }

    function handleKeydown(event) {
        logDebug('[handleKeydown] Event on:', event.target, 'Active Input Element:', activeInputInfo.element, 'Type:', activeInputInfo.type);
        if (event.isComposing) return;
        if (!isScriptGloballyEnabled) return;
        if (!activeInputInfo.element || (event.target !== activeInputInfo.element && !activeInputInfo.element.contains(event.target))) {
             return;
        }

        const currentHost = window.location.hostname;
        const isCtrlOrCmdPressed = (event.ctrlKey || event.metaKey) && !event.shiftKey && !event.altKey;
        const isShiftPressed = event.shiftKey && !event.ctrlKey && !event.metaKey && !event.altKey;
        const isAltPressed = event.altKey && !event.ctrlKey && !event.metaKey && !event.shiftKey;
        const plainEnter = !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey;
        const anyModifierPressed = event.ctrlKey || event.shiftKey || event.altKey || event.metaKey;

        if (event.key === 'Enter') {
            logDebug('[handleKeydown] Enter pressed. Ctrl/Cmd:', isCtrlOrCmdPressed, 'Shift:', isShiftPressed, 'Alt:', isAltPressed, 'Plain:', plainEnter);
            if (currentHost.includes('gemini.google.com')) {
                if (currentGeminiConfig.mode === SITE_MODES.NATIVE) return;
                if (currentGeminiConfig.mode === SITE_MODES.CUSTOM) {
                    processEnterKeyForSite(event, currentGeminiConfig.keys, isCtrlOrCmdPressed, isShiftPressed, isAltPressed, plainEnter, anyModifierPressed, activeInputInfo);
                }
            } else if (currentHost.includes('aistudio.google.com')) {
                if (currentAIStudioConfig.mode === SITE_MODES.NATIVE) return;
                if (currentAIStudioConfig.mode === SITE_MODES.CUSTOM && activeInputInfo.type === INPUT_TYPES.MAIN) {
                    logDebug('[handleKeydown] AI Studio CUSTOM mode for MAIN input.');
                    processEnterKeyForSite(event, currentAIStudioConfig.keys, isCtrlOrCmdPressed, isShiftPressed, isAltPressed, plainEnter, anyModifierPressed, activeInputInfo);
                }
                // AI Studio edit mode is no longer specifically handled by custom logic in this simplified version
            }
        }
    }

    function updateActiveInputListener() {
        if (activeInputInfo.element) {
            const listenerAttached = activeInputInfo.element.dataset.keydownListenerAttached === 'true';
            let shouldCurrentlyBeAttached = false;

            if (isScriptGloballyEnabled) {
                const onGemini = window.location.hostname.includes('gemini.google.com');
                const onAIStudio = window.location.hostname.includes('aistudio.google.com');
                if (onGemini && currentGeminiConfig.mode === SITE_MODES.CUSTOM) {
                    shouldCurrentlyBeAttached = true;
                } else if (onAIStudio && currentAIStudioConfig.mode === SITE_MODES.CUSTOM && activeInputInfo.type === INPUT_TYPES.MAIN) {
                    shouldCurrentlyBeAttached = true;
                }
            }
            logDebug('[updateActiveInputListener] Element:', activeInputInfo.element, 'Type:', activeInputInfo.type, 'Listener Attached:', listenerAttached, 'Should be attached:', shouldCurrentlyBeAttached);
            if (listenerAttached && !shouldCurrentlyBeAttached) {
                activeInputInfo.element.removeEventListener('keydown', handleKeydown, true);
                delete activeInputInfo.element.dataset.keydownListenerAttached;
                logDebug('[updateActiveInputListener] Listener REMOVED from:', activeInputInfo.element);
            } else if (!listenerAttached && shouldCurrentlyBeAttached) {
                activeInputInfo.element.addEventListener('keydown', handleKeydown, true);
                activeInputInfo.element.dataset.keydownListenerAttached = 'true';
                logDebug('[updateActiveInputListener] Listener ADDED to:', activeInputInfo.element);
            }
        } else {
            logDebug('[updateActiveInputListener] No active input element to update listener for.');
        }
    }
    function toggleScriptGlobally() {
        isScriptGloballyEnabled = !isScriptGloballyEnabled;
        GM_setValue(GM_GLOBAL_ENABLE_KEY_STORAGE, isScriptGloballyEnabled);
        if (activeInputInfo.element) {
            updateActiveInputListener();
        }
        registerMenuCommand();
        showNotification(isScriptGloballyEnabled ? i18n.get('notifyScriptEnabled') : i18n.get('notifyScriptDisabled'));
    }
    function registerMenuCommand() {
        menuCommandIds.forEach(id => { if (typeof GM_unregisterMenuCommand === 'function') try { GM_unregisterMenuCommand(id); } catch (e) {} });
        menuCommandIds = [];
        try { const sId = GM_registerMenuCommand(i18n.get('openSettingsMenu'), openSettings, 's'); if (sId) menuCommandIds.push(sId); } catch (e) { console.error(`[${SCRIPT_ID}] Error registering 'Open Settings' menu command:`, e); }
        try { const tId = GM_registerMenuCommand(isScriptGloballyEnabled ? i18n.get('disableScriptMenu') : i18n.get('enableScriptMenu'), toggleScriptGlobally, 't'); if (tId) menuCommandIds.push(tId); } catch (e) { console.error(`[${SCRIPT_ID}] Error registering toggle script menu command:`, e); }
    }

    function findActiveInputElement() {
        const host = window.location.hostname;
        let el;
        logDebug('[findActiveInputElement] Searching on host:', host);

        const focusedElement = document.activeElement;
        if (focusedElement && (focusedElement.tagName === 'TEXTAREA' || focusedElement.isContentEditable)) {
            logDebug('[findActiveInputElement] Focused element:', focusedElement, 'Tag:', focusedElement.tagName, 'ContentEditable:', focusedElement.isContentEditable);
            if (host.includes('gemini.google.com')) {
                 const geminiEditParent = focusedElement.closest('user-query-content.edit-mode');
                 if (geminiEditParent && GEMINI_EDIT_INPUT_SELECTORS.some(s => focusedElement.matches(s))) {
                     logDebug('[findActiveInputElement] Found Gemini Edit Input via document.activeElement:', focusedElement);
                     return { element: focusedElement, type: INPUT_TYPES.EDIT };
                 }
            }
            // AI Studio edit detection via activeElement removed due to complexity and unreliability
        }

        if (host.includes('gemini.google.com')) {
            for (const selector of GEMINI_EDIT_INPUT_SELECTORS) {
                el = document.querySelector(selector);
                if (el && (el.offsetWidth > 0 || el.offsetHeight > 0 || el.getClientRects().length > 0)) {
                    logDebug('[findActiveInputElement] Found Gemini Edit Input (Selector):', el, 'Selector:', selector);
                    return { element: el, type: INPUT_TYPES.EDIT };
                }
            }
        }
        // AI Studio edit input search via general selectors removed

        if (host.includes('gemini.google.com')) {
            el = document.querySelector(GEMINI_INPUT_SELECTOR_PRIMARY);
            if (el && (el.offsetWidth > 0 || el.offsetHeight > 0 || el.getClientRects().length > 0)) {
                 logDebug('[findActiveInputElement] Found Gemini Main Input (Primary):', el);
                 return { element: el, type: INPUT_TYPES.MAIN };
            }
            for (const selector of GEMINI_INPUT_SELECTORS_FALLBACK) {
                el = document.querySelector(selector);
                 if (el && (el.offsetWidth > 0 || el.offsetHeight > 0 || el.getClientRects().length > 0)) {
                    logDebug('[findActiveInputElement] Found Gemini Main Input (Fallback):', el, 'Selector:', selector);
                    return { element: el, type: INPUT_TYPES.MAIN };
                }
            }
        } else if (host.includes('aistudio.google.com')) {
            for (const selector of AISTUDIO_INPUT_SELECTORS) {
                el = document.querySelector(selector);
                if (el && (el.offsetWidth > 0 || el.offsetHeight > 0 || el.getClientRects().length > 0)) {
                    logDebug('[findActiveInputElement] Found AI Studio Main Input:', el, 'Selector:', selector);
                     return { element: el, type: INPUT_TYPES.MAIN };
                }
            }
        }
        logDebug('[findActiveInputElement] No specific active input found by selectors.');
        return { element: null, type: INPUT_TYPES.UNKNOWN };
    }

    function findSubmitButtonForInput(inputInfo) {
        if (!inputInfo || !inputInfo.element) {
            logDebug('[findSubmitButtonForInput] No inputInfo or element provided.');
            return null;
        }
        const host = window.location.hostname;
        let selectors = [];
        let searchContext = document;

        if (host.includes('gemini.google.com')) {
            selectors = inputInfo.type === INPUT_TYPES.EDIT ? GEMINI_SAVE_EDIT_BUTTON_SELECTORS : GEMINI_SEND_BUTTON_SELECTORS;
            if (inputInfo.type === INPUT_TYPES.EDIT) {
                const userQueryContent = inputInfo.element.closest('user-query-content.edit-mode');
                if (userQueryContent) searchContext = userQueryContent;
            }
        } else if (host.includes('aistudio.google.com')) {
             // Only main send buttons for AI Studio in this simplified version
            if (inputInfo.type === INPUT_TYPES.MAIN) {
                selectors = AISTUDIO_SEND_BUTTON_SELECTORS;
            } else {
                logDebug('[findSubmitButtonForInput] AI Studio: Edit mode buttons no longer specifically targeted by script.');
                return null; // No button to find for AI Studio edit mode via script
            }
        }
        logDebug('[findSubmitButtonForInput] Input Type:', inputInfo.type, 'Host:', host, 'Attempting selectors:', selectors, 'Search Context:', searchContext.tagName || 'document');

        for (const selector of selectors) {
            let button = null;
            try {
                button = searchContext.querySelector(selector);
            } catch (e) {
                logDebug('[findSubmitButtonForInput] Error using selector:', selector, e);
                continue;
            }

            if (button && (button.offsetWidth > 0 || button.offsetHeight > 0 || button.getClientRects().length > 0)) {
                logDebug('[findSubmitButtonForInput] Found visible button with selector:', selector, button);
                return button;
            } else if (button) {
                logDebug('[findSubmitButtonForInput] Found button with selector but it is NOT VISIBLE:', selector, button);
            } else {
                 logDebug('[findSubmitButtonForInput] No button found for selector:', selector, 'in context:', searchContext.tagName || 'document');
            }
        }
        logDebug('[findSubmitButtonForInput] No submit button found for input type:', inputInfo.type, 'on host:', host);
        return null;
    }

    const mutationObserverCallback = (mutationsList, observer) => {
        logDebug('[MutationObserver] Generic DOM change detected, triggering debounced handler.');
        debouncedDOMChangeHandler();
    };

    const debouncedDOMChangeHandler = debounce(() => {
        logDebug('[debouncedDOMChangeHandler] Running...');
        const oldActiveElement = activeInputInfo.element;
        const oldActiveType = activeInputInfo.type;
        const newActiveInfo = findActiveInputElement();

        if (oldActiveElement !== newActiveInfo.element || oldActiveType !== newActiveInfo.type) {
            logDebug('[debouncedDOMChangeHandler] Active input changed. Old:', {el: oldActiveElement?.tagName, type: oldActiveType}, 'New:', {el: newActiveInfo.element?.tagName, type: newActiveInfo.type});
            if (oldActiveElement && oldActiveElement.dataset.keydownListenerAttached === 'true') {
                oldActiveElement.removeEventListener('keydown', handleKeydown, true);
                delete oldActiveElement.dataset.keydownListenerAttached;
                logDebug('[debouncedDOMChangeHandler] Removed listener from old active input:', oldActiveElement);
            }
            activeInputInfo = newActiveInfo;
            updateActiveInputListener();
        } else if (newActiveInfo.element && newActiveInfo.element.dataset.keydownListenerAttached !== 'true' && isScriptGloballyEnabled) {
             logDebug('[debouncedDOMChangeHandler] Same element, but listener needs re-evaluation for:', newActiveInfo.element);
            updateActiveInputListener();
        } else if (!newActiveInfo.element && oldActiveElement) { 
            logDebug('[debouncedDOMChangeHandler] Active element disappeared. Clearing activeInputInfo.');
             if (oldActiveElement && oldActiveElement.dataset.keydownListenerAttached === 'true') {
                oldActiveElement.removeEventListener('keydown', handleKeydown, true);
                delete oldActiveElement.dataset.keydownListenerAttached;
            }
            activeInputInfo = {element: null, type: INPUT_TYPES.UNKNOWN};
        } else {
            logDebug('[debouncedDOMChangeHandler] No change in active input or listener status seems fine.');
        }
        if (window.location.hostname.includes('aistudio.google.com')) {
            updateAIStudioButtonModifierHint();
        }
    }, 250);

    const observeDOM = function() {
        const observer = new MutationObserver(mutationObserverCallback);
        observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['class', 'style', 'disabled', 'aria-hidden', 'contenteditable'] });
        logDebug('[observeDOM] MutationObserver started.');
    };

    function init() {
        i18n.detectLanguage(); loadSettings(); createSettingsUI(); registerMenuCommand(); observeDOM();
        activeInputInfo = findActiveInputElement();
        updateActiveInputListener();
        if (window.location.hostname.includes('aistudio.google.com')) setTimeout(updateAIStudioButtonModifierHint, 500);
        logDebug(`Initialized. Global Enable: ${isScriptGloballyEnabled}. Gemini: ${JSON.stringify(currentGeminiConfig)}. AI Studio: ${JSON.stringify(currentAIStudioConfig)}.`);
        logDebug('Initial active input element:', activeInputInfo.element, 'Type:', activeInputInfo.type);
    }

    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
    else init();
})();