瀏覽代碼

fix(app): terminal copy/paste

Adam 2 月之前
父節點
當前提交
ef5ec5dc28
共有 1 個文件被更改,包括 25 次插入30 次删除
  1. 25 30
      packages/app/src/components/terminal.tsx

+ 25 - 30
packages/app/src/components/terminal.tsx

@@ -130,11 +130,12 @@ export const Terminal = (props: TerminalProps) => {
     const t = term
     if (!t) return
     t.focus()
+    t.textarea?.focus()
     setTimeout(() => t.textarea?.focus(), 0)
   }
   const handlePointerDown = () => {
     const activeElement = document.activeElement
-    if (activeElement instanceof HTMLElement && activeElement !== container) {
+    if (activeElement instanceof HTMLElement && activeElement !== container && !container.contains(activeElement)) {
       activeElement.blur()
     }
     focusTerminal()
@@ -204,44 +205,32 @@ export const Terminal = (props: TerminalProps) => {
       ghostty = g
       term = t
 
-      const copy = () => {
+      const handleCopy = (event: ClipboardEvent) => {
         const selection = t.getSelection()
-        if (!selection) return false
-
-        const body = document.body
-        if (body) {
-          const textarea = document.createElement("textarea")
-          textarea.value = selection
-          textarea.setAttribute("readonly", "")
-          textarea.style.position = "fixed"
-          textarea.style.opacity = "0"
-          body.appendChild(textarea)
-          textarea.select()
-          const copied = document.execCommand("copy")
-          body.removeChild(textarea)
-          if (copied) return true
-        }
+        if (!selection) return
 
-        const clipboard = navigator.clipboard
-        if (clipboard?.writeText) {
-          clipboard.writeText(selection).catch(() => {})
-          return true
-        }
+        const clipboard = event.clipboardData
+        if (!clipboard) return
+
+        event.preventDefault()
+        clipboard.setData("text/plain", selection)
+      }
+
+      const handlePaste = (event: ClipboardEvent) => {
+        const clipboard = event.clipboardData
+        const text = clipboard?.getData("text/plain") ?? clipboard?.getData("text") ?? ""
+        if (!text) return
 
-        return false
+        event.preventDefault()
+        event.stopPropagation()
+        t.paste(text)
       }
 
       t.attachCustomKeyEventHandler((event) => {
         const key = event.key.toLowerCase()
 
         if (event.ctrlKey && event.shiftKey && !event.metaKey && key === "c") {
-          copy()
-          return true
-        }
-
-        if (event.metaKey && !event.ctrlKey && !event.altKey && key === "c") {
-          if (!t.hasSelection()) return true
-          copy()
+          document.execCommand("copy")
           return true
         }
 
@@ -252,6 +241,12 @@ export const Terminal = (props: TerminalProps) => {
         return matchKeybind(keybinds, event)
       })
 
+      container.addEventListener("copy", handleCopy, true)
+      cleanups.push(() => container.removeEventListener("copy", handleCopy, true))
+
+      container.addEventListener("paste", handlePaste, true)
+      cleanups.push(() => container.removeEventListener("paste", handlePaste, true))
+
       const fit = new mod.FitAddon()
       const serializer = new SerializeAddon()
       cleanups.push(() => disposeIfDisposable(fit))