// ==UserScript== // @name DeepSeek ShortCuts // @name:zh-CN DeepSeek快捷键 // @name:zh-TW DeepSeek快捷鍵 // @description Keyboard Shortcuts For DeepSeek (Mac & Windows & Linux) // @description:zh-CN 为DeepSeek提供快捷键支持(Mac & Windows & Linux) // @description:zh-TW 為DeepSeek提供快捷鍵支持(Mac & Windows & Linux) // @version 1.4.0 // @icon https://raw.githubusercontent.com/MiPoNianYou/UserScripts/refs/heads/main/Icons/DeepSeekShortcutsIcon.svg // @author 念柚 // @namespace https://github.com/MiPoNianYou/UserScripts // @supportURL https://github.com/MiPoNianYou/UserScripts/issues // @license GPL-3.0 // @match https://chat.deepseek.com/* // @grant GM_addStyle // @downloadURL none // ==/UserScript== (function () { "use strict"; const helpPanelStyles = ` .ShortcutsHelpPanel { --panel-bg-color: rgba(44, 44, 46, 0.85); --panel-text-color: rgba(255, 255, 255, 0.9); --panel-secondary-text-color: rgba(235, 235, 245, 0.6); --panel-border-color: rgba(84, 84, 88, 0.65); --panel-padding: 24px; --panel-radius: 12px; --key-bg-color: rgba(118, 118, 128, 0.24); --warning-bg-color: rgba(118, 118, 128, 0.24); --warning-border-color: rgba(84, 84, 88, 0.65); --warning-text-color: rgb(255, 159, 10); --font-stack: system-ui, sans-serif; --closebtn-color: #FF5F57; --closebtn-hover-color: #E0443E; --closebtn-symbol-color: #4D0000; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -48%) scale(0.95); z-index: 9999; pointer-events: none; visibility: hidden; min-width: 280px; max-width: 450px; padding: var(--panel-padding); border: 0.5px solid var(--panel-border-color); border-radius: var(--panel-radius); background: var(--panel-bg-color); box-shadow: 0 12px 28px rgba(0, 0, 0, 0.2), 0 2px 4px rgba(0, 0, 0, 0.1); backdrop-filter: blur(20px) saturate(180%); color: var(--panel-text-color); font-family: var(--font-stack); font-size: 14px; font-weight: 500; line-height: 1.5; opacity: 0; transition: opacity 0.3s ease-in-out, transform 0.3s ease-in-out, visibility 0s linear 0.3s; display: flex; flex-direction: column; } .ShortcutsHelpPanel.visible { opacity: 1; transform: translate(-50%, -50%) scale(1); pointer-events: auto; visibility: visible; transition-delay: 0s; } .ShortcutsHelpCloseButton { position: absolute; top: 14px; left: 14px; width: 12px; height: 12px; padding: 0; border: 0.5px solid rgba(0, 0, 0, 0.2); border-radius: 50%; background-color: var(--closebtn-color); cursor: pointer; display: flex; align-items: center; justify-content: center; transition: background-color 0.15s ease; appearance: none; -webkit-appearance: none; } .ShortcutsHelpCloseButton::before { content: '×'; display: block; color: transparent; font-size: 11px; font-weight: bold; line-height: 12px; text-align: center; transition: color 0.15s ease; } .ShortcutsHelpCloseButton:hover { background-color: var(--closebtn-hover-color); } .ShortcutsHelpCloseButton:hover::before { color: var(--closebtn-symbol-color); } .ShortcutsHelpCloseButton:active { background-color: var(--closebtn-hover-color); filter: brightness(0.9); } .ShortcutsHelpTitle { margin: 0 0 15px 0; width: 100%; color: var(--panel-text-color); font-size: 16px; font-weight: 600; text-align: center; padding-top: 5px; flex-shrink: 0; } .ShortcutsHelpContent { flex-grow: 1; overflow-y: auto; max-height: 65vh; margin-right: -10px; padding-right: 10px; scrollbar-width: thin; scrollbar-color: rgba(235, 235, 245, 0.3) transparent; } .ShortcutsHelpContent::-webkit-scrollbar { width: 6px; } .ShortcutsHelpContent::-webkit-scrollbar-track { background: transparent; margin: 5px 0; } .ShortcutsHelpContent::-webkit-scrollbar-thumb { background-color: rgba(235, 235, 245, 0.4); border-radius: 3px; } .ShortcutsHelpContent::-webkit-scrollbar-thumb:hover { background-color: rgba(235, 235, 245, 0.6); } .ShortcutsHelpRow { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; padding: 5px 0; } .ShortcutsHelpContent > .ShortcutsHelpRow:last-child { margin-bottom: 0; } .ShortcutsHelpKey { min-width: 90px; padding: 4px 8px; margin-left: 16px; background: var(--key-bg-color); border: 0.5px solid var(--panel-border-color); border-radius: 5px; box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1); color: var(--panel-text-color); font-family: inherit; font-size: 13px; text-align: center; flex-shrink: 0; } .ShortcutsHelpDesc { flex-grow: 1; padding-right: 10px; color: var(--panel-secondary-text-color); } .ShortcutsHelpWarning { margin-top: 18px; padding: 12px; background: var(--warning-bg-color); border: 0.5px solid var(--warning-border-color); border-radius: 8px; color: var(--warning-text-color); font-size: 12px; line-height: 1.5; text-align: center; flex-shrink: 0; } `; if (typeof GM_addStyle === "function") { GM_addStyle(helpPanelStyles); } else { const styleElement = document.createElement("style"); styleElement.textContent = helpPanelStyles; document.head.appendChild(styleElement); } const createFinder = (config) => () => { const { selector, filterCriteria, position = "first", parentSelector, parentPosition = "last", childPosition = "first", } = config; if (parentSelector) { const parents = Array.from(document.querySelectorAll(parentSelector)); if (parents.length === 0) return null; const parentIndex = parentPosition === "last" ? parents.length - 1 : 0; const targetParent = parents[parentIndex]; if (!targetParent) return null; const children = Array.from(targetParent.querySelectorAll(selector)); if (children.length === 0) return null; const childIndex = childPosition === "last" ? children.length - 1 : 0; return children[childIndex] || null; } else { const elements = Array.from(document.querySelectorAll(selector)); if (elements.length === 0) return null; if (filterCriteria) { return ( elements.find( (element) => element.textContent?.includes(filterCriteria) || element.querySelector(filterCriteria) ) || null ); } else { const index = position === "last" ? elements.length - 1 : 0; return elements[index] || null; } } }; const findRegenerate = createFinder({ selector: ".ds-icon-button", filterCriteria: "#重新生成", }); const findContinue = createFinder({ selector: ".ds-button", filterCriteria: "继续生成", }); const findStop = createFinder({ selector: "._7436101", position: "first", }); const findLastCopy = createFinder({ parentSelector: "div._4f9bf79.d7dc56a8", parentPosition: "last", selector: "._965abe9 .ds-icon-button", childPosition: "first", }); const findLastEdit = createFinder({ parentSelector: "._9663006", parentPosition: "last", selector: "._78e0558 .ds-icon-button", childPosition: "last", }); const findDeepThink = createFinder({ selector: ".ds-button span", filterCriteria: "深度思考", }); const findSearch = createFinder({ selector: ".ds-button span", filterCriteria: "联网搜索", }); const findUpload = createFinder({ selector: ".f02f0e25", position: "first", }); const findNewChat = createFinder({ selector: "._217e214", position: "first", }); const findToggleSidebar = createFinder({ selector: ".ds-icon-button", filterCriteria: "svg #打开边栏0730, svg #折叠边栏0730", }); const findChatMenu = createFinder({ parentSelector: "._83421f9.b64fb9ae", parentPosition: "last", selector: "._2090548", childPosition: "first", }); const getModifiers = () => { const isMac = /Macintosh|Mac OS X/i.test(navigator.userAgent); return { Character: isMac ? "Control" : "Alt", Property: isMac ? "ctrlKey" : "altKey", }; }; const modifierKeys = getModifiers(); const shortcutDefs = [ [`${modifierKeys.Character} + R`, "重新生成回答"], [`${modifierKeys.Character} + C`, "继续生成回答"], [`${modifierKeys.Character} + Q`, "中断当前生成"], [`${modifierKeys.Character} + K`, "复制末条回答"], [`${modifierKeys.Character} + E`, "编辑末次提问"], [`${modifierKeys.Character} + D`, "深度思考模式"], [`${modifierKeys.Character} + S`, "联网搜索模式"], [`${modifierKeys.Character} + U`, "上传本地文件"], [`${modifierKeys.Character} + N`, "新建对话窗口"], [`${modifierKeys.Character} + T`, "切换开关边栏"], [`${modifierKeys.Character} + I`, "当前对话菜单"], [`${modifierKeys.Character} + H`, "快捷按键帮助"], ]; let helpPanelElement = null; const createHelpPanel = () => { const panelElement = document.createElement("div"); panelElement.classList.add("ShortcutsHelpPanel"); const closeButton = document.createElement("button"); closeButton.classList.add("ShortcutsHelpCloseButton"); closeButton.addEventListener("click", (e) => { e.stopPropagation(); closeHelpPanel(); }); const titleElement = document.createElement("h3"); titleElement.textContent = "快捷按键指北"; titleElement.classList.add("ShortcutsHelpTitle"); const contentDiv = document.createElement("div"); contentDiv.classList.add("ShortcutsHelpContent"); panelElement.append(closeButton, titleElement); shortcutDefs.forEach(([keyShortcut, description]) => { const rowElement = document.createElement("div"); rowElement.classList.add("ShortcutsHelpRow"); const keyElement = document.createElement("span"); keyElement.textContent = keyShortcut; keyElement.classList.add("ShortcutsHelpKey"); const descriptionElement = document.createElement("span"); descriptionElement.textContent = description; descriptionElement.classList.add("ShortcutsHelpDesc"); rowElement.append(descriptionElement, keyElement); contentDiv.append(rowElement); }); panelElement.append(contentDiv); const warningElement = document.createElement("div"); warningElement.textContent = "⚠️ 脚本依UA自动适配快捷键 篡改UA或致功能异常"; warningElement.classList.add("ShortcutsHelpWarning"); panelElement.append(warningElement); document.body.append(panelElement); return panelElement; }; const handleOutsideClick = (mouseEvent) => { if ( helpPanelElement && helpPanelElement.classList.contains("visible") && !helpPanelElement.contains(mouseEvent.target) && !mouseEvent.target.classList.contains("ShortcutsHelpCloseButton") ) { closeHelpPanel(); } }; const toggleHelpPanel = (panelElement) => { if (!panelElement) { return; } const isVisible = panelElement.classList.contains("visible"); if (isVisible) { panelElement.classList.remove("visible"); window.removeEventListener("click", handleOutsideClick, true); } else { panelElement.classList.add("visible"); setTimeout(() => { window.addEventListener("click", handleOutsideClick, true); }, 0); } }; const initHelpPanel = () => { if (!helpPanelElement) { helpPanelElement = createHelpPanel(); } }; const closeHelpPanel = () => { if (helpPanelElement && helpPanelElement.classList.contains("visible")) { helpPanelElement.classList.remove("visible"); window.removeEventListener("click", handleOutsideClick, true); } }; const safeClick = (finderFunction) => { const element = finderFunction(); if (element) { element.click(); } }; const debounce = (func, wait) => { let timeout; return function executeDebounced(...args) { const later = () => { clearTimeout(timeout); func.apply(this, args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; }; const toggleHelpPanelAction = () => { initHelpPanel(); if (helpPanelElement) { toggleHelpPanel(helpPanelElement); } }; const debouncedToggleHelpPanel = debounce(toggleHelpPanelAction, 150); const keyActionMap = { r: () => safeClick(findRegenerate), c: () => safeClick(findContinue), q: () => safeClick(findStop), k: () => safeClick(findLastCopy), e: () => safeClick(findLastEdit), d: () => safeClick(findDeepThink), s: () => safeClick(findSearch), u: () => safeClick(findUpload), n: () => safeClick(findNewChat), t: () => safeClick(findToggleSidebar), i: () => safeClick(findChatMenu), h: () => { debouncedToggleHelpPanel(); return true; }, }; const createKeyHandler = () => { const isModifierKeyPressed = (keyboardEvent) => keyboardEvent[modifierKeys.Property]; return (keyboardEvent) => { if (keyboardEvent.key === "Escape") { if ( helpPanelElement && helpPanelElement.classList.contains("visible") ) { closeHelpPanel(); keyboardEvent.preventDefault(); keyboardEvent.stopPropagation(); } return; } if (!isModifierKeyPressed(keyboardEvent)) { return; } const pressedKey = keyboardEvent.key.toLowerCase(); const actionFunction = keyActionMap[pressedKey]; if (actionFunction) { const actionResult = actionFunction(keyboardEvent); if (actionResult !== false) { keyboardEvent.preventDefault(); keyboardEvent.stopPropagation(); } } }; }; const mainKeyHandler = createKeyHandler(); window.addEventListener("keydown", mainKeyHandler, true); })();