Gemini Keyboard Shortcuts

This userscript enhances your Gemini experience by adding a wide range of keyboard shortcuts for streamlined navigation and interaction, as well as cleaning up Gemini's UI.

// ==UserScript==
// @name        Gemini Keyboard Shortcuts
// @namespace   http://tampermonkey.net/
// @version     1.2.5
// @description This userscript enhances your Gemini experience by adding a wide range of keyboard shortcuts for streamlined navigation and interaction, as well as cleaning up Gemini's UI.
// @license     MIT
// @author      Henry Getz
// @match       https://gemini.google.com/u/*
// @match       https://gemini.google.com/app*
// @icon        data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjgiIGhlaWdodD0iMjgiIHZpZXdCb3g9IjAgMCAyOCAyOCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTE0IDI4QzE0IDI2LjA2MzMgMTMuNjI2NyAyNC4yNDMzIDEyLjg4IDIyLjU0QzEyLjE1NjcgMjAuODM2NyAxMS4xNjUgMTkuMzU1IDkuOTA1IDE4LjA5NUM4LjY0NSAxNi44MzUgNy4xNjMzMyAxNS44NDMzIDUuNDYgMTUuMTJDMy43NTY2NyAxNC4zNzMzIDEuOTM2NjcgMTQgMCAxNEMxLjkzNjY3IDE0IDMuNzU2NjcgMTMuNjM4MyA1LjQ2IDEyLjkxNUM3LjE2MzMzIDEyLjE2ODMgOC42NDUgMTEuMTY1IDkuOTA1IDkuOTA1QzExLjE2NSA4LjY0NSAxMi4xNTY3IDcuMTYzMzMgMTIuODggNS40NkMxMy42MjY3IDMuNzU2NjcgMTQgMS45MzY2NyAxNCAwQzE0IDEuOTM2NjcgMTQuMzYxNyAzLjc1NjY3IDE1LjA4NSA1LjQ2QzE1LjgzMTcgNy4xNjMzMyAxNi44MzUgOC42NDUgMTguMDk1IDkuOTA1QzE5LjM1NSAxMS4xNjUgMjAuODM2NyAxMi4xNjgzIDIyLjU0IDEyLjkxNUMyNC4yNDMzIDEzLjYzODMgMjYuMDYzMyAxNCAyOCAxNEMyNi4wNjMzIDE0IDI0LjI0MzMgMTQuMzczMyAyMi41NCAxNS4xMkMyMC44MzY3IDE1Ljg0MzMgMTkuMzU1IDE2LjgzNSAxOC4wOTUgMTguMDk1QzE2LjgzNSAxOS4zNTUgMTUuODMxNyAyMC44MzY3IDE1LjA4NSAyMi41NEMxNC4zNjE3IDI0LjI0MzMgMTQgMjYuMDYzMyAxNCAyOFoiIGZpbGw9InVybCgjcGFpbnQwX3JhZGlhbF8xNjc3MV81MzIxMikiLz4KPGRlZnM+CjxyYWRpYWxHcmFkaWVudCBpZD0icGFpbnQwX3JhZGlhbF8xNjc3MV81MzIxMiIgY3g9IjAiIGN5PSIwIiByPSIxIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgZ3JhZGllbnRUcmFuc2Zvcm09InRyYW5zbGF0ZSgyLjc3ODc2IDExLjM3OTUpIHJvdGF0ZSgxOC42ODMyKSBzY2FsZSgyOS44MDI1IDIzOC43MzcpIj4KPHN0b3Agb2Zmc2V0PSIwLjA2NzEyNDYiIHN0b3AtY29sb3I9IiM5MTY4QzAiLz4KPHN0b3Agb2Zmc2V0PSIwLjM0MjU1MSIgc3RvcC1jb2xvcj0iIzU2ODREMSIvPgo8c3RvcCBvZmZzZXQ9IjAuNjcyMDc2IiBzdG9wLWNvbG9yPSIjMUJBMUUzIi8+CjwvcmFkaWFsR3JhZGllbnQ+CjwvZGVmcz4KPC9zdmc+Cg==
// @supportURL  https://github.com/HenryGetz/GeminiPilot/issues
// @grant       none
// @run-at      document-start
// ==/UserScript==
/*

#New Feature: URL Parameters!

Empower your automation workflows!  Directly open Gemini with pre-populated prompts by using query parameters in the URL (e.g., `https://gemini.google.com/app?q=YOURTESTPROMPT`).


# Included Keyboard Shortcuts:


## Chat Management

|   Shortcut (Mac/Windows)   |     Action     |
|:--------------------------:|:--------------:|
| ⌘/Ctrl + Shift + O         | Open new chat  |
| ⌘/Ctrl + Shift + Backspace | Delete chat    |
| ⌘/Ctrl + Shift + F         | Toggle sidebar |
| ⌥/Alt + 1-9                | Go to nth chat |
| ⌘/Ctrl + Shift + =         | Next chat      |
| ⌘/Ctrl + Shift + –         | Previous chat  |


## Text Input and Editing

| Shortcut (Mac/Windows) |             Action            |
|:----------------------:|:-----------------------------:|
|      Shift + Esc       |        Focus chat input       |
|   ⌘/Ctrl + Shift + E   |           Edit text           |
|   ⌘/Ctrl + Shift + ;   |      Copy last code block     |
|   ⌘/Ctrl + Shift + '   |Copy second-to-last code block |
|   ⌘/Ctrl + Shift + C   |         Copy response         |
|   ⌘/Ctrl + Shift + K   |     Stop/start generation     |


## Draft Navigation

| Shortcut (Mac/Windows) |        Action        |
|:----------------------:|:--------------------:|
|   ⌘/Ctrl + Shift + D   | Generate more drafts |
|   ⌘/Ctrl + Shift + ,   |      Next draft      |
|   ⌘/Ctrl + Shift + .   |    Previous draft    |


## Sharing and Linking

| Shortcut (Mac/Windows) |           Action          |
|:----------------------:|:-------------------------:|
|   ⌘/Ctrl + Shift + L   | Copy prompt/response link |
|   ⌘/Ctrl + Shift + M   |       Copy chat link      |


## Audio and File Shortcuts

| Shortcut (Mac/Windows) |         Action        |
|:----------------------:|:---------------------:|
|   ⌘/Ctrl + Shift + K   | Stop/start generation |
|   ⌘/Ctrl + Shift + Y   |    Play/pause audio   |
|   ⌘/Ctrl + Shift + S   |     Voice to text     |
|       ⌘/Ctrl + O       |       Open file       |



*/

//With this false, it will copy from the response in the viewport.

const assumeLastResponse = false;

//This setting allows you to delete chats in succession, like browser tabs, instead of beign forced to go to a new one. Perfect if doing Gemini housekeeping

const goToNextChatOnDelete = true;



const hasQuery = window.location.href.includes("?q=");
let url = new URL(window.location.href);
let params = new URLSearchParams(url.search);
let query = unescape(params.get('q'));

window.onload = onLoad;

function onLoad(){
    //This code makes the prompt take up the full width of the screen, and moves the heading
    let s = document.createElement("style");
    document.head.append(s);
    s.textContent = `

.conversation-container, .input-area-container, .bottom-container {
    max-width: -webkit-fill-available !important;
}

.capabilities-disclaimer, #gbwa, .cdk-overlay-backdrop {
    display: none !important;
}

.code-block-decoration.footer, .code-block-decoration.header {
    user-select: none; /* Standard syntax */
    -webkit-user-select: none; /* WebKit (Safari, Chrome) browsers */
    -moz-user-select: none; /* Firefox */
    -ms-user-select: none; /* Internet Explorer/Edge */

}

.bottom-container {
    padding-bottom: 20px;
}

bard-mode-switcher {
    position: fixed;
    top: 0px;
    right: 64px;
    z-index: 1000;
    background: var(--bard-color-surface-container);
    border: solid var(--bard-color-surface-container) 4px;
    border-right: solid var(--bard-color-surface-container) 100px;
    transform: translate(100px, -4px);
    border-radius: 100px;
    box-shadow: 0 0 20px 12px rgba(var(--bard-color-main-container-background-rgb), 77%)
}

.mat-mdc-focus-indicator::before {
    border: none !important;
}

* > .conversation-container:first-child {
    border-top: solid transparent 60px !important;
}

`;

    const nums = ["first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth", "tenth"];
    const rapidClickDelayMS = 100;
    const capitalize = word => word.charAt(0).toUpperCase() + word.slice(1);


    //This code makes sure that the 'more chats' feature is selected without user interaction (so that you can select chats 6-9 with alt as well.)

    //This code also allows for query parameters in the URL.

    let showMoreClicked = false;
    let inputBarClicked = false;
    const observer = new MutationObserver((_, observer) => {
        const showMore = document.querySelector('[data-test-id="show-more-button"]');
        const inputBar = document.querySelector('.text-input-field');
        const textInput = document.querySelector('[aria-label="Enter a prompt here"]');

        if (showMore && !showMoreClicked) {
            showMoreClicked = true;
            simulateClick(showMore);
        }
        if (hasQuery && inputBar && !inputBarClicked) {
            if (textInput && !inputBarClicked) {


                inputBarClicked = true;
                console.log(query);
                params.delete('q');
                window.history.pushState(null,"",url.origin + url.pathname);

                setTimeout(function(){
                    inputBar.click();

                    setTimeout(function(){
                        textInput.firstChild.remove();
                        query = query.split("\n");
                        for (let line of query) {
                            let p = document.createElement("p");
                            p.innerText = line;
                            textInput.append(p);
                        }

                        //This waits to also change the url when the drafts generate. Google is weird and changes it back
                        const observer = new MutationObserver((_, observer) => {
                            let showDrafts = document.querySelector('[data-test-id="generate-more-drafts-button"]');
                            if (showDrafts) {
                                observer.disconnect();

                                setTimeout(function(){
                                    url = new URL(window.location.href);
                                    params = new URLSearchParams(url.search);
                                    window.history.pushState(null,"",url.origin + url.pathname);
                                }, 2000)
                            }
                        });
                        observer.observe(document.body, {childList: true, subtree: true});

                        setTimeout(function(){
                            document.querySelector('[aria-label="Send message"]').click();
                        }, rapidClickDelayMS)
                    } ,rapidClickDelayMS)
                }, rapidClickDelayMS)

            }
        } else if (inputBar && !inputBarClicked) {
            console.log(hasQuery)
            inputBarClicked = true;
            setTimeout(() => inputBar.click(), rapidClickDelayMS)
        }

        if (showMoreClicked && inputBarClicked) {
            observer.disconnect();
        }
    });
    observer.observe(document.body, {childList: true, subtree: true});

    let c = null;
    function getLastElement(querySelector) {
        const containers = document.querySelectorAll('.conversation-container');
        c = containers[containers.length - 1];
        if (!assumeLastResponse) {
            let mostVisibleElement = null;
            let maxVisibleArea = 0;

            containers.forEach(container => {
                const rect = container.getBoundingClientRect();
                const viewportHeight = window.innerHeight;

                // Calculate visible area (only consider area within the viewport)
                const visibleArea = Math.max(0, Math.min(rect.bottom, viewportHeight) - Math.max(rect.top, 0));

                if (visibleArea > maxVisibleArea && visibleArea !== 0) {
                    maxVisibleArea = visibleArea;
                    mostVisibleElement = container;
                }
            });
            c = mostVisibleElement;
        }
        return c.querySelectorAll(querySelector)[c.querySelectorAll(querySelector).length - 1];
    }

    function copy(text) {
        const textarea = document.createElement('textarea');
        textarea.value = text;
        document.body.appendChild(textarea);
        textarea.select();
        document.execCommand('copy');
        document.body.removeChild(textarea);
    }

    function copyRichTextFromDiv(element) {
        const div = element;

        if (!div) {
            console.error("Div not found.");
            return;
        }

        document.querySelectorAll('.code-block-decoration.footer, .code-block-decoration.header, .table-footer').forEach(el => el.style.display = 'none');

        const selection = window.getSelection();
        const range = document.createRange();
        range.selectNodeContents(div);
        selection.removeAllRanges();
        selection.addRange(range);

        try {
            const successful = document.execCommand('copy');
        } catch (err) {
            console.error('Failed to copy rich text: ', err);
        }

        selection.removeAllRanges();
        setTimeout(function(){
            document.querySelectorAll('.code-block-decoration.footer, .code-block-decoration.header').forEach(el => el.style.display = '');
        }, rapidClickDelayMS)

    }



    function clearNotifications() {
        for (let ele of document.querySelectorAll(".gemini-key-notification")) {
            ele.remove();
        }
    }

    function notify(text) {
        clearNotifications();
        for (let ele of document.querySelectorAll(".gmat-mdc-dialog")) {
            ele.remove();
        }

        var div = document.createElement('div');
        div.classList.add("gemini-key-notification");
        div.innerText = text;
        let tDuration = 125;
        let nDuration = 3000;
        let tLeft = nDuration - tDuration;
        div.style.cssText = `position: absolute;bottom: 26px;left: 26px;font-family: var(--mdc-snackbar-supporting-text-font);font-size: var(--mdc-snackbar-supporting-text-size);font-weight: var(--mdc-snackbar-supporting-text-weight);line-height: var(--mdc-snackbar-supporting-text-line-height);color: var(--mdc-snackbar-supporting-text-color);border-radius: var(--mdc-snackbar-container-shape);background-color: var(--mdc-snackbar-container-color);z-index: 2147483647;padding: 16px;line-height: 20px;transition-property: opacity, scale;transition-duration: ${tDuration}ms;transform-origin: center;scale: 0.6;opacity: 0;`;
        document.body.append(div);
        setTimeout(function(){div.style.opacity = 1; div.style.scale = 1;}, rapidClickDelayMS)
        setTimeout(function(){
            div.style.opacity = 0;
            setTimeout(function(){div.remove()}, tDuration)
        }, tLeft);
    }


    function simulateClick(element) {
        element.click();
    }

    let draftIndex = 0;
    let googleDraftCount = 3;
    let waitOnGeneration = false;

    function changeDraft(direction) {
        let draftButtons = document.querySelectorAll(".draft-preview-button");
        if (!waitOnGeneration) {
            draftIndex = (draftIndex + direction + googleDraftCount) % googleDraftCount; // Ensure index stays within 0-2
        }

        if (!waitOnGeneration && draftButtons[draftIndex]) {
            simulateClick(draftButtons[draftIndex]);
            //notify(`${capitalize(nums[draftIndex])} draft`)
        } else if (!waitOnGeneration) {
            draftIndex = 0;
            draftIndex = (draftIndex + direction + googleDraftCount) % googleDraftCount;
            simulateClick(getLastElement('[data-test-id="generate-more-drafts-button"]'));
            notify(`Generating ${nums[draftIndex]} draft`)
            waitOnGeneration = true;

            const observer = new MutationObserver((_, observer) => {
                draftButtons = document.querySelectorAll(".draft-preview-button");
                if (draftButtons[draftIndex]) {
                    observer.disconnect();
                    setTimeout(function(){
                        waitOnGeneration = false;
                        simulateClick(draftButtons[draftIndex]);
                        //notify(`${capitalize(nums[draftIndex])} draft`)
                    },rapidClickDelayMS * 2)
                }
            });
            observer.observe(document.body, {childList: true, subtree: true});
        } else {
            notify("Waiting on generation");
        }
    }

    const nextDraft = () => changeDraft(1);
    const previousDraft = () => changeDraft(-1);

    let chatIndex = 0;
    let waitOnLoadingMore = false;

    function changeChat(direction) {
        chatIndex = Array.from(document.querySelectorAll('[data-test-id="conversation"]')).indexOf(document.querySelector('.selected[data-test-id="conversation"]'));
        let chatButtons = document.querySelectorAll('[data-test-id="conversation"]');

        if (!waitOnLoadingMore) {
            chatIndex = Math.max(0, chatIndex + direction);
        }

        if (!waitOnLoadingMore && chatButtons[chatIndex]) {
            simulateClick(chatButtons[chatIndex]);
            notify(`"${chatButtons[chatIndex].querySelector(".conversation-title").innerHTML.trim()}"`)
        } else if (!waitOnLoadingMore) {
            simulateClick(document.querySelector('[data-test-id="load-more-button"]'));
            notify(`Loading chats`)
            waitOnLoadingMore = true;

            const observer = new MutationObserver((_, observer) => {
                chatButtons = document.querySelectorAll('[data-test-id="conversation"]');
                if (chatButtons[chatIndex]) {
                    observer.disconnect();
                    setTimeout(function(){
                        waitOnLoadingMore = false;
                        simulateClick(chatButtons[chatIndex]);
                        //notify(`${capitalize(nums[draftIndex])} draft`)
                        notify(`"${chatButtons[chatIndex].querySelector(".conversation-title").innerHTML.trim()}"`)
                    },rapidClickDelayMS * 2)
                }
            });
            observer.observe(document.body, {childList: true, subtree: true});
        } else {
            notify("Chats loading");
        }
    }

    const nextChat = () => changeChat(1);
    const previousChat = () => changeChat(-1);



    var isMac = /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform);

    document.addEventListener('keydown', function(event) {
        // Check for Command or Control key

        if (event.shiftKey && event.key === "Escape") {
            simulateClick(document.querySelector('.text-input-field'));
            event.preventDefault();
        }

        let keyNumber = parseInt(event.code.replace("Digit",""));
        keyNumber = keyNumber === 0 ? 10 : keyNumber;

        if (event.altKey && keyNumber) {
            document.querySelectorAll('[data-test-id="conversation"]')[keyNumber - 1].click();
            chatIndex = Array.from(document.querySelectorAll('[data-test-id="conversation"]')).indexOf(document.querySelector('.selected[data-test-id="conversation"]'));
            notify(`"${document.querySelectorAll('[data-test-id="conversation"]')[chatIndex].querySelector(".conversation-title").innerHTML.trim()}"`)
            //notify(`${capitalize(nums[keyNumber-1])} conversation`)
            event.preventDefault();
        }


        if (event.key === "Escape" && document.activeElement.getAttribute("aria-label").includes("Edit prompt")) {
            simulateClick(getLastElement('[aria-label*="Cancel"]'));
            event.preventDefault();
        }

        const isCmdOrCtrl = (isMac && event.metaKey) || (!isMac && event.ctrlKey);

        if (!isCmdOrCtrl) return;

        if (isCmdOrCtrl && event.key === 'o' && !event.shiftKey) {
            event.preventDefault();
            simulateClick(document.querySelector('.upload-button button'));
            simulateClick(document.querySelector('[aria-label*="Upload files"]'))
        }

        switch (event.key) {
            case 'o':
                if (event.shiftKey) {
                    simulateClick(document.querySelector('[aria-label*="New chat"] button'));
                    simulateClick(document.querySelector('.text-input-field'));
                    //notify("New chat created");
                    event.preventDefault();
                } else {
                    document.querySelector('[aria-label*="upload file"]').click(); setTimeout(function(){document.body.querySelector('[aria-label*="Upload files"]').click()}, rapidClickDelayMS);
                }
                break;
                //BELOW NEEDS MORE TIME
            case 'c':
                if (event.shiftKey) {
                    event.preventDefault();
                    getLastElement();
                    copyRichTextFromDiv(c.querySelector(".model-response-text"));
                    notify("Copied response")


                    /* All of the below code was me desperately trying to do it through Google's menus, and failing for 2+ hours. Good riddance

                    simulateClick(getLastElement('[aria-label*="options"]'));
                    setTimeout(function(){simulateClick(document.querySelector('[aria-label*="Copy"]'))},rapidClickDelayMS*2)
                    simulateClick(getLastElement('[aria-label*="options"]'));
                    simulateClick(document.querySelector('#overflow-container'))
                    setTimeout(function(){document.querySelector('.cdk-overlay-pane').style.top = "99999999px"; c.focus()},rapidClickDelayMS)
                    clearNotifications();
*/
                }
                break;
            case 'i':
                if (event.shiftKey) {
                    // Implement custom instructions if Gemini supports them
                    event.preventDefault();
                }
                break;
            case 'f':
                if (event.shiftKey) {
                    simulateClick(document.querySelector('[aria-label*="Main menu"]'));
                    event.preventDefault();
                }
                break;
            case 'Backspace':
                if (event.shiftKey) {
                    event.preventDefault();
                    chatIndex = Array.from(document.querySelectorAll('[data-test-id="conversation"]')).indexOf(document.querySelector('.selected[data-test-id="conversation"]'));
                    document.querySelector('.conversation.selected').parentElement.querySelector('[data-test-id="actions-menu-button"]').click(); setTimeout(function(){document.body.querySelector('[data-test-id="delete-button"]').click()}, rapidClickDelayMS); setTimeout(function(){document.body.querySelector('[data-test-id="confirm-button"]').click(); setTimeout(function(){if(goToNextChatOnDelete){simulateClick(document.querySelectorAll('[data-test-id="conversation"]')[chatIndex])}}, rapidClickDelayMS)}, rapidClickDelayMS)
                }
                break;
            case 'd':
                if (event.shiftKey) {
                    let element = getLastElement('[data-test-id="generate-more-drafts-button"]');
                    if (!element) {
                        element = getLastElement('[mattooltip="Regenerate drafts"]');
                    }
                    simulateClick(element);
                    event.preventDefault();
                }
                break;
            case 'e':
                if (event.shiftKey) {
                    simulateClick(getLastElement('[mattooltip="Edit text"]'));
                    event.preventDefault();
                }
                break;
            case ';':
                if (event.shiftKey) {
                    event.preventDefault();
                    //                    simulateClick(getLastElement('[mattooltip="Copy code"]'));
                    getLastElement();
                    copyRichTextFromDiv(c.querySelectorAll("code-block")[c.querySelectorAll("code-block").length - 1]);
                    notify("Copied last code block to clipboard");
                }
                break;
            case '\'':
                if (event.shiftKey) {
                    event.preventDefault();
                    //                    simulateClick(getLastElement('[mattooltip="Copy code"]'));
                    getLastElement();
                    copyRichTextFromDiv(c.querySelectorAll("code-block")[c.querySelectorAll("code-block").length - 2]);
                    notify("Copied second-last code block to clipboard");
                }
                break;
            case 'm':
                if (event.shiftKey) {
                    simulateClick(getLastElement('[aria-label*="Share"]'));
                    setTimeout(function(){simulateClick(document.querySelector('[aria-label*="Share response"]'))},rapidClickDelayMS)
                    setTimeout(function(){simulateClick(document.querySelector('[data-test-id="share-mode-radio-button-full"] label'))},rapidClickDelayMS*2)
                    setTimeout(function(){simulateClick(document.querySelector('[data-test-id="create-button"]'))},rapidClickDelayMS*3)

                    //below waits until the link menu loads, then copies it and closes the menu
                    const observer = new MutationObserver((_, observer) => {
                        const element = document.querySelector('[aria-label="Copy public link"]');
                        if (element) {
                            observer.disconnect();
                            simulateClick(element);
                            setTimeout(function(){
                                simulateClick(document.querySelector('[aria-label="Close"]'))
                                notify("Chat link copied");
                            },rapidClickDelayMS)
                        }
                    });
                    observer.observe(document.body, {childList: true, subtree: true});


                    clearNotifications();
                    //notify("Last response copied to clipboard");
                    event.preventDefault();
                }
                break;
            case 'l':
                if (event.shiftKey) {
                    simulateClick(getLastElement('[aria-label*="Share"]'));
                    setTimeout(function(){simulateClick(document.querySelector('[aria-label*="Share response"]'))},rapidClickDelayMS)
                    setTimeout(function(){simulateClick(document.querySelector('[data-test-id="create-button"]'))},rapidClickDelayMS*2)

                    //below waits until the link menu loads, then copies it and closes the menu
                    const observer = new MutationObserver((_, observer) => {
                        const element = document.querySelector('[aria-label="Copy public link"]');
                        if (element) {
                            observer.disconnect();
                            simulateClick(element);
                            setTimeout(function(){
                                simulateClick(document.querySelector('[aria-label="Close"]'));
                                notify("Prompt/response link copied");
                            },rapidClickDelayMS)
                        }
                    });
                    observer.observe(document.body, {childList: true, subtree: true});
                    //notify("Last response copied to clipboard");
                    event.preventDefault();
                }
                break;
            case ',':
                if (event.shiftKey) {
                    previousDraft();
                }
                break;
            case '.':
                if (event.shiftKey) {
                    nextDraft();
                }
                break;
            case '-':
                if (event.shiftKey) {
                    event.preventDefault();
                    previousChat();
                }
                break;
            case '=':
                if (event.shiftKey) {
                    event.preventDefault();
                    nextChat();
                }
                break;
            case 'k':
                event.preventDefault();
                if (event.shiftKey) {
                    simulateClick(document.querySelector('[aria-label="Send message"]'));
                    //notify("Last response copied to clipboard");
                }
                break;
            case 'y':
                if (event.shiftKey) {
                    simulateClick(getLastElement('.response-tts-container button'));
                    event.preventDefault();
                }
                break;
            case 's':
                if (event.shiftKey) {
                    simulateClick(document.querySelector('[mattooltip="Use microphone"]'));
                    event.preventDefault();
                }
                break;
        }
    });
}

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址