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}
)}
))} )} ); }