Gemini - Last Prompt Replacer

Streamlines replacing the last prompt in a Gemini conversation with robust short and long press support.

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         Gemini - Last Prompt Replacer
// @namespace    http://tampermonkey.net/
// @version      0.8
// @description  Streamlines replacing the last prompt in a Gemini conversation with robust short and long press support.
// @author       vfxturjo
// @license      MIT
// @match        https://gemini.google.com/app/*
// @grant        GM_registerMenuCommand
// @grant        GM_setClipboard
// ==/UserScript==

(function() {
    'use strict';

    let keydownTimer = null;
    let isActionInProgress = false; // State flag to prevent key-repeat issues
    const longPressDuration = 400; // Time in ms to distinguish a long press

    /**
     * The core function to replace the last prompt.
     * @param {boolean} submit - If true, the script will simulate an "Enter" key press.
     */
    async function replacePrompt(submit = true) {
        console.log(`Gemini Replacer: Action triggered (Submit: ${submit}).`);

        try {
            const allEditButtons = document.querySelectorAll('[data-test-id="prompt-edit-button"]');
            if (allEditButtons.length === 0) {
                // Check if we are already in edit mode
                if (!document.querySelector('textarea[aria-label="Edit prompt"]')) {
                    alert("Gemini Replacer Error: Could not find any prompt edit buttons.");
                }
                // If we are already in edit mode, we can still proceed to paste.
            } else {
                const lastEditButton = allEditButtons[allEditButtons.length - 1];
                lastEditButton.click();
                console.log("Gemini Replacer: Edit button clicked.");
            }

            const clipboardText = await navigator.clipboard.readText();
            if (typeof clipboardText !== 'string' || clipboardText.length === 0) {
                alert("Gemini Replacer: Clipboard is empty or contains no text.");
                return;
            }
            console.log("Gemini Replacer: Successfully read from clipboard.");

            // A brief moment for the text area to become visible.
            setTimeout(() => {
                const promptTextArea = document.querySelector('textarea[aria-label="Edit prompt"]');

                if (promptTextArea) {
                    console.log("Gemini Replacer: Found the prompt text area.");
                    promptTextArea.value = clipboardText;
                    promptTextArea.dispatchEvent(new Event('input', { bubbles: true }));

                    if (submit) {
                        const enterEvent = new KeyboardEvent('keydown', {
                            bubbles: true, cancelable: true, key: 'Enter', code: 'Enter', keyCode: 13, which: 13
                        });
                        promptTextArea.dispatchEvent(enterEvent);
                        console.log("Gemini Replacer: Pasted content and simulated Enter press.");
                    } else {
                        console.log("Gemini Replacer: Pasted content without submitting. Ready for editing.");
                    }
                } else {
                    alert("Gemini Replacer Error: Could not find the prompt text area after clicking edit.");
                }
            }, 100);

        } catch (error) {
            if (error.name === 'NotAllowedError') {
                alert('Gemini Replacer: Please grant clipboard access permission to the site.');
            } else {
                console.error("Gemini Replacer: An unexpected error occurred:", error);
                alert("Gemini Replacer: An unexpected error occurred. See the console for details.");
            }
        }
    }

    // --- Triggers ---

    GM_registerMenuCommand('Replace Last Prompt', () => replacePrompt(true));

    document.addEventListener('keydown', function(event) {
        // Only run if CTRL+Q is pressed AND we are not already processing an action
        if (event.ctrlKey && event.key.toLowerCase() === 'q' && !isActionInProgress) {
            event.preventDefault();
            isActionInProgress = true; // Set the flag to block repeated events

            // Start a timer for the long press action.
            keydownTimer = setTimeout(() => {
                replacePrompt(false); // Execute the action without submitting.
                keydownTimer = null; // Clear the timer ID after it has run.
            }, longPressDuration);
        }
    });

    document.addEventListener('keyup', function(event) {
        // We only care about the keyup event if we started an action
        if (event.key.toLowerCase() === 'q' && isActionInProgress) {
            // If the timer is still running, it's a short press.
            if (keydownTimer) {
                clearTimeout(keydownTimer);
                replacePrompt(true); // Execute the action with submission.
            }
            // If keydownTimer is null, the long press already fired. Do nothing.

            // Reset state for the next key press
            keydownTimer = null;
            isActionInProgress = false;
        }
    });

})();