From 0668428a5ebc221d39b907f251dc0dc43e30a2df Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Mon, 21 Jul 2025 12:28:36 -0400 Subject: testing alt keyboard copy methods --- src/components/ClipboardExperiments.tsx | 509 ++++++++++++++++++++++++++++++++ 1 file changed, 509 insertions(+) create mode 100644 src/components/ClipboardExperiments.tsx (limited to 'src/components/ClipboardExperiments.tsx') diff --git a/src/components/ClipboardExperiments.tsx b/src/components/ClipboardExperiments.tsx new file mode 100644 index 0000000..ec7d9ab --- /dev/null +++ b/src/components/ClipboardExperiments.tsx @@ -0,0 +1,509 @@ +import { useState } from "react"; +import { PanelSectionRow, ButtonItem, Field, Focusable } from "@decky/ui"; +import { FaClipboard, FaFlask, FaRocket, FaCog, FaTerminal } from "react-icons/fa"; +import { toaster } from "@decky/api"; +import { getLaunchOption, copyToSystemClipboard } from "../api/lsfgApi"; + +interface ExperimentResult { + success: boolean; + method: string; + error?: string; + details?: string; +} + +export function ClipboardExperiments() { + const [results, setResults] = useState([]); + const [isLoading, setIsLoading] = useState(null); + + const addResult = (result: ExperimentResult) => { + setResults(prev => [...prev, { ...result, timestamp: Date.now() }]); + }; + + const getLaunchOptionText = async (): Promise => { + try { + const result = await getLaunchOption(); + return result.launch_option || "~/lsfg %command%"; + } catch (error) { + return "~/lsfg %command%"; + } + }; + + // Approach 1: Direct Navigator Clipboard API + const testDirectClipboard = async () => { + setIsLoading("direct"); + try { + const text = await getLaunchOptionText(); + await navigator.clipboard.writeText(text); + + // Test if it actually worked by reading back + const readBack = await navigator.clipboard.readText(); + const success = readBack === text; + + addResult({ + success, + method: "Direct Navigator Clipboard", + details: success ? `Successfully copied: "${text}"` : `Mismatch: wrote "${text}", read "${readBack}"` + }); + + if (success) { + toaster.toast({ + title: "Clipboard Success!", + body: "Direct navigator.clipboard API worked" + }); + } + } catch (error) { + addResult({ + success: false, + method: "Direct Navigator Clipboard", + error: String(error) + }); + } finally { + setIsLoading(null); + } + }; + + // Approach 2: CEF Browser with Data URL + const testDataUrlApproach = async () => { + setIsLoading("dataurl"); + try { + const text = await getLaunchOptionText(); + const htmlContent = ` + + + + + Clipboard Helper + + + +
+

๐Ÿš€ Clipboard Automation Test

+

Attempting to copy launch option: ${text}

+
Working...
+
+ +
+ + + + `; + + const dataUrl = 'data:text/html;charset=utf-8,' + encodeURIComponent(htmlContent); + window.open(dataUrl, '_blank'); + + addResult({ + success: true, + method: "Data URL Browser Window", + details: "Opened data URL with auto-copy script" + }); + } catch (error) { + addResult({ + success: false, + method: "Data URL Browser Window", + error: String(error) + }); + } finally { + setIsLoading(null); + } + }; + + // Approach 3: Focused Element + Selection + Input API + const testInputSimulation = async () => { + setIsLoading("input"); + try { + const text = await getLaunchOptionText(); + + // Create a temporary input element + const tempInput = document.createElement('input'); + tempInput.value = text; + tempInput.style.position = 'absolute'; + tempInput.style.left = '-9999px'; + document.body.appendChild(tempInput); + + // Focus and select the text + tempInput.focus(); + tempInput.select(); + + // Try different copy methods + let copySuccess = false; + let method = ''; + + // Method 1: execCommand (deprecated but might work) + try { + if (document.execCommand('copy')) { + copySuccess = true; + method = 'execCommand'; + } + } catch (e) {} + + // Method 2: Navigator clipboard on selected text + if (!copySuccess) { + try { + await navigator.clipboard.writeText(text); + copySuccess = true; + method = 'navigator.clipboard'; + } catch (e) {} + } + + // Clean up + document.body.removeChild(tempInput); + + if (copySuccess) { + // Verify + try { + const readBack = await navigator.clipboard.readText(); + const verified = readBack === text; + addResult({ + success: verified, + method: `Input Simulation (${method})`, + details: verified ? "Successfully copied and verified" : "Copy worked but verification failed" + }); + } catch (e) { + addResult({ + success: true, + method: `Input Simulation (${method})`, + details: "Copy appeared to work but couldn't verify" + }); + } + } else { + addResult({ + success: false, + method: "Input Simulation", + error: "All copy methods failed" + }); + } + } catch (error) { + addResult({ + success: false, + method: "Input Simulation", + error: String(error) + }); + } finally { + setIsLoading(null); + } + }; + + // Approach 4: Backend Clipboard + const testBackendClipboard = async () => { + setIsLoading("backend"); + try { + const text = await getLaunchOptionText(); + + const result = await copyToSystemClipboard(text); + + if (result.success) { + addResult({ + success: true, + method: `Backend System Clipboard (${result.method})`, + details: result.message || "Successfully copied to system clipboard" + }); + + toaster.toast({ + title: "Clipboard Success!", + body: `Copied using ${result.method}` + }); + } else { + addResult({ + success: false, + method: "Backend System Clipboard", + error: result.error || "Unknown error" + }); + } + } catch (error) { + addResult({ + success: false, + method: "Backend System Clipboard", + error: String(error) + }); + } finally { + setIsLoading(null); + } + }; + + // Approach 5: Hybrid approach with immediate feedback + const testHybridApproach = async () => { + setIsLoading("hybrid"); + try { + const text = await getLaunchOptionText(); + + // Try direct first + let directWorked = false; + try { + await navigator.clipboard.writeText(text); + const readBack = await navigator.clipboard.readText(); + directWorked = readBack === text; + } catch (e) {} + + if (directWorked) { + addResult({ + success: true, + method: "Hybrid (Direct Success)", + details: "Direct clipboard API worked, no browser needed" + }); + + toaster.toast({ + title: "Clipboard Success!", + body: "Launch option copied to clipboard" + }); + } else { + // Fall back to optimized browser approach + const htmlContent = ` + + + + + Quick Copy + + + +
+

๐Ÿš€ Clipboard Helper

+

Copying: ${text}

+
โณ Working...
+ + +
+ + + + `; + + const dataUrl = 'data:text/html;charset=utf-8,' + encodeURIComponent(htmlContent); + window.open(dataUrl, '_blank', 'width=500,height=300'); + + addResult({ + success: true, + method: "Hybrid (Browser Fallback)", + details: "Direct failed, opened optimized browser window" + }); + } + } catch (error) { + addResult({ + success: false, + method: "Hybrid Approach", + error: String(error) + }); + } finally { + setIsLoading(null); + } + }; + + const clearResults = () => { + setResults([]); + }; + + return ( + <> + +
+ ๐Ÿงช Clipboard Automation Experiments +
+
+ + +
+ Testing different approaches to automate clipboard access in Steam Deck gaming mode: +
+
+ + {/* Test Buttons */} + + +
+ +
Test Direct Clipboard API
+ {isLoading === "direct" &&
โณ
} +
+
+
+ + + +
+ +
Test Data URL Browser
+ {isLoading === "dataurl" &&
โณ
} +
+
+
+ + + +
+ +
Test Input Simulation
+ {isLoading === "input" &&
โณ
} +
+
+
+ + + +
+ +
Test Backend Clipboard
+ {isLoading === "backend" &&
โณ
} +
+
+
+ + + +
+ +
Test Hybrid Approach (Recommended)
+ {isLoading === "hybrid" &&
โณ
} +
+
+
+ + {/* Results Section */} + {results.length > 0 && ( + <> + + +
+
+ {results.filter(r => r.success).length} successful, {results.filter(r => !r.success).length} failed +
+ + Clear + +
+
+
+ + {results.slice(-5).map((result, index) => ( + + +
+
+ {result.success ? "โœ…" : "โŒ"} {result.method} +
+ {result.details && ( +
+ {result.details} +
+ )} + {result.error && ( +
+ Error: {result.error} +
+ )} +
+
+
+ ))} + + )} + + ); +} -- cgit v1.2.3